Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 61 additions & 13 deletions docs/developer-guide/graphics.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,37 @@ hi.show();
.Hi world demo code, notice that the blue bar on top is the iOS7+ status bar
image::img/developer-guide/graphics-hiworld.png[Hi world demo code, notice that the blue bar on top is the iOS7+ status bar,scaledwidth=20%]

==== Painting with Gradients

Solid colors are only the starting point. `Graphics` also understands "paint" objects
that describe gradients and other patterns. You can pass an instance of
https://www.codenameone.com/javadoc/com/codename1/ui/Paint.html[`Paint`]
to `setColor(Paint)` in place of an integer color value to activate a gradient for
subsequent fill and draw operations. The
https://www.codenameone.com/javadoc/com/codename1/ui/LinearGradientPaint.html[`LinearGradientPaint`]
class is the most common option and accepts a list of color stops along a line:

[source,java]
----
LinearGradientPaint gradient = new LinearGradientPaint(
0, 0, getWidth(), 0, // horizontal gradient
new int[] {0xff4285f4, 0xff34a853, 0xfffbbc05},
new float[] {0f, 0.5f, 1f}
);
g.setColor(gradient);
g.fillRect(getX(), getY(), getWidth(), getHeight());
----

The `fillLinearGradient()` convenience methods (with optional `repeat` flag)
provide a shorthand when you just need a two-color gradient without constructing
your own `Paint` object.

Radial gradients are equally straightforward using
`fillRadialGradient()` or `fillRectRadialGradient()`, which can render circular
and rectangular radial transitions respectively. These APIs accept the
inner/outer colors, focal point, and spread so you can combine them with linear
gradients to build sophisticated backgrounds and lighting effects.

=== Glass Pane

The `GlassPane `in Codename One is inspired by the Swing `GlassPane` & `LayeredPane` with quite a few twists.
Expand Down Expand Up @@ -139,9 +170,13 @@ paths and curves and caching the shape drawn in the GPU.

=== Device Support

Shapes and transforms are available on most smartphone platforms with some caveats for the current Windows Phone port.
Shapes and transforms ship with all of Codename One's actively maintained ports
(Android, iOS, JavaScript, desktop/Simulator, and UWP). Older platforms that
have reached end of life may lack these APIs, so keep the guard code shown below
if you still target them with legacy builds.

Notice that perspective transform is missing from the desktop/simulator port. Unfortunately there is no real equivalent to perspective transform in JavaSE that we could use.
Notice that perspective transform is missing from the desktop/simulator port.
Unfortunately there is no real equivalent to perspective transform in JavaSE that we could use.

=== A 2D Drawing App

Expand Down Expand Up @@ -316,16 +351,17 @@ NOTE: `scale()` and `rotate()` methods are only available on platforms that supp

==== Device Support

As of this writing, not all devices support transforms (i.e. `scale()` and `rotate()`). The following is a list of platforms
and their respective levels of support.
All current Codename One ports expose affine transforms (i.e. `scale()` and
`rotate()`). Use the following table as a quick reference when deciding whether
you need a fallback path.

.Transforms Device Support
[cols="2*"]
|===
|Platform
|Affine Supported

| Simulator
| Simulator/Desktop
| Yes

| iOS
Expand All @@ -337,14 +373,8 @@ and their respective levels of support.
| JavaScript
| Yes

| J2ME
| No

| BlackBerry (4.2 & 5)
| No

| Windows Phone
| No (pending)
| UWP
| Yes
|===


Expand Down Expand Up @@ -1002,6 +1032,24 @@ You could also use the `Graphics.setTransform()` class to apply rotations and ot
(including 3D perspective transforms), but I'll leave that for its own topic as it is a little bit more complex.


==== Global Alpha & Anti-Aliasing

So far we have relied on the per-pixel alpha stored in images and gradients. `Graphics`
also lets you apply a global alpha multiplier to every draw call by using
`setAlpha(int)` or `concatenateAlpha(int)` after checking `isAlphaSupported()`.
Both methods accept values from `0` (fully transparent) to `255` (fully opaque)
and remain active until you change them again. `concatenateAlpha()` is
especially handy when you need to temporarily fade a component because it
returns the previous alpha so you can restore it later.

Anti-aliasing can likewise be toggled at runtime. Call `isAntiAliasingSupported()`
and `isAntiAliasedTextSupported()` to discover which hints the current port
exposes, then use `setAntiAliased(boolean)` and `setAntiAliasedText(boolean)` to
opt into smoother edges for shapes and glyphs respectively. These switches make
it easy to balance rendering quality versus speed depending on the type of
content you draw.


==== Event Coordinates

The coordinate system and event handling are closely tied. You can listen for touch events on a component by
Expand Down
42 changes: 39 additions & 3 deletions docs/developer-guide/io.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,19 @@ You can then read the token like this:
String token = Preferences.get("token", null);
----

The backing store filename defaults to `"codenameone.properties"`, but you can
override it by calling `Preferences.setPreferencesLocation(String)` before your
app touches the API. This is useful when you need to segregate preference
namespaces per user or plug in an encrypted storage layer.

When you have a batch of updates, prefer the `Preferences.set(Map<String,Object>)`
overload so that all values are persisted with a single disk write.

Preferences can also notify interested parties when a key changes. Register a
`PreferenceListener` via `addPreferenceListener()` to react to updates made in
other parts of your code (or even triggered remotely via `Codename One Push`).
Remember to remove listeners you no longer need to avoid leaks.

WARNING: This gets somewhat confusing with primitive numbers e.g. if you use `Preferences.set("primitiveLongValue", myLongNumber)` then invoke `Preferences.get("primitiveLongValue", 0)` you might get an exception! +
This would happen because the value is physically a `Long` object but you are trying to get an `Integer`. The workaround is to remain consistent and use code like this `Preferences.get("primitiveLongValue", (long)0)`.

Expand Down Expand Up @@ -250,9 +263,9 @@ In general SQL seems overly complex for most embedded device programming tasks.

.Portability Of SQLite
****
SQLite is supported on iOS, Android, RIM, Desktop & JavaScript builds. However, the JavaScript version of SQL has been deprecated and isn't supported on all platforms.

You will notice that at this time support is still missing from the Windows builds.
SQLite is supported on iOS, Android, JavaScript, Desktop/Simulator, and UWP
builds. The JavaScript port relies on the browser's WebSQL implementation, so
it may be unavailable in environments that have already removed that feature.

The biggest issue with SQLite portability is in iOS. The SQLite version for most platforms is threadsafe and as a result very stable. However, the iOS version is not!

Expand Down Expand Up @@ -416,6 +429,17 @@ byte[] resultOfRequest = request.getData();
Notice that in this case the `addToQueueAndWait` method returned after the connection completed. Also notice that this was totally legal to do on the EDT!


==== Timeouts & Retries

Each request can override the global timeout using `setTimeout(int)`, which
expects a duration in milliseconds. This is especially useful when you are
talking to endpoints that occasionally need a longer window than the default
NetworkManager setting. You can also configure how many times Codename One
should retry a failing call silently by using `setSilentRetryCount(int)`. When
the silent retry limit is reached the standard error handling kicks in (e.g.
listeners fire, fail dialogs show, etc.).


==== Threading

By default the `NetworkManager` launches with a single network thread. This is sufficient for very simple applications that don't do too much networking but if you need to fetch many images concurrently and perform web services in parallel this might be an issue.
Expand Down Expand Up @@ -1296,6 +1320,18 @@ Map<String, Object> jsonData = Rest.post(myUrl).body(bodyValueAsString).getAsJso

Notice the usage of post and the body builder method. There are MANY methods in the builder class that cover pretty much everything you would expect and then some when it comes to the needs of rest services.

Some highlights that are easy to miss:

* `.priority(byte)` lets you change the underlying `ConnectionRequest` priority
when you need certain calls to jump the queue.
* `.cookiesEnabled(boolean)` controls whether cookies are persisted for the
request when you need stateless behavior.
* `.useBoolean(boolean)` and `.useLongs(boolean)` toggle how the JSON parser
materializes number and boolean types inside the resulting `Map`, which is
handy when your backend is strict about data types.
* `.cacheMode(...)` and `.postParameters(...)` expose the same knobs as
`ConnectionRequest`, keeping you in the fluent API even for advanced tweaks.

I changed the code in the kitchen sink webservice sample to use this API. I was able to make it shorter and more readable without sacrificing anything.

==== Rest in Practice - Twilio
Expand Down
21 changes: 19 additions & 2 deletions docs/developer-guide/performance.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,17 @@ The Performance Monitor tool can be accessible via the #Simulator# -> #Performan
.Main tab of the performance monitor: Logs and timings
image::img/developer-guide/performance-monitor-tab-1.png[Main tab of the performance monitor: Logs and timings]

The first tab of the performance monitor includes a table of the drawn components. Each entry includes the number of times it was drawn and the slowest/fastest and average drawing time.
The first tab of the performance monitor includes a table of the drawn components. Each entry includes the number of times it was drawn and the slowest/fastest and average drawing time. The toolbar across the top
includes Pause/Continue buttons so you can freeze the counters while you inspect
the current snapshot, a "Clear Data" action to reset the tables, and a "GC"
button that invokes the simulator's garbage collector so you can see how memory
usage changes.

This is useful if a `Form` is slow. You might be able to pinpoint it to a specific component using this tool.

The Log on the bottom includes debug related information. E.g. it warns about the usage of mutable images which might be slow on some platforms. This also displays warnings when an unlocked image is drawn etc.
The Log on the bottom includes debug related information. E.g. it warns about the usage of mutable images which might be slow on some platforms. This also displays warnings when an unlocked image is drawn etc. A live
"Image Memory Overhead" meter summarizes how much native image memory the
current form consumes so you can correlate spikes with your drawing code.

.Rendering tree
image::img/developer-guide/performance-monitor-tab-2.png[Rendering tree]
Expand Down Expand Up @@ -138,6 +144,17 @@ Log.bindCrashProtection(true);

We normally place this in the `init(Object)` method so all future on-device errors are emailed to you. Internally this method uses the `Display.getInstance().addEdtErrorHandler()` API to bind error listeners to the EDT. When an exception is thrown there it is swallowed (using `ActionEvent.consume()`). The `Log` data is then sent using `Log.sendLog()`.

If your crash handler runs while networking is unavailable or you want to avoid
blocking the EDT, use `Log.sendLogAsync()` instead. It performs the upload in a
background thread and is what Codename One's lifecycle helper falls back to when
regular error reporting fails.

You can also plug in your own crash reporting pipeline by calling
`Display.getInstance().setCrashReporter(CrashReport)`. The
https://www.codenameone.com/javadoc/com/codename1/system/CrashReport.html[`CrashReport`]
callback will receive the exception, device information, and log payload so you
can forward it to services like Firebase Crashlytics or your in-house tools.

To truly benefit from this feature we need to use the `Log` class for all logging and exception handling instead of API's such as `System.out`.

To log standard printouts you can use the `Log.p(String)` method and to log exceptions with their stack trace you can use `Log.e(Throwable)`.
Expand Down