Skip to content

Commit 3837fd1

Browse files
authored
Refresh developer guide docs for current platform features (#4050)
1 parent 1ee78d0 commit 3837fd1

File tree

3 files changed

+119
-18
lines changed

3 files changed

+119
-18
lines changed

docs/developer-guide/graphics.asciidoc

Lines changed: 61 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,37 @@ hi.show();
6060
.Hi world demo code, notice that the blue bar on top is the iOS7+ status bar
6161
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%]
6262

63+
==== Painting with Gradients
64+
65+
Solid colors are only the starting point. `Graphics` also understands "paint" objects
66+
that describe gradients and other patterns. You can pass an instance of
67+
https://www.codenameone.com/javadoc/com/codename1/ui/Paint.html[`Paint`]
68+
to `setColor(Paint)` in place of an integer color value to activate a gradient for
69+
subsequent fill and draw operations. The
70+
https://www.codenameone.com/javadoc/com/codename1/ui/LinearGradientPaint.html[`LinearGradientPaint`]
71+
class is the most common option and accepts a list of color stops along a line:
72+
73+
[source,java]
74+
----
75+
LinearGradientPaint gradient = new LinearGradientPaint(
76+
0, 0, getWidth(), 0, // horizontal gradient
77+
new int[] {0xff4285f4, 0xff34a853, 0xfffbbc05},
78+
new float[] {0f, 0.5f, 1f}
79+
);
80+
g.setColor(gradient);
81+
g.fillRect(getX(), getY(), getWidth(), getHeight());
82+
----
83+
84+
The `fillLinearGradient()` convenience methods (with optional `repeat` flag)
85+
provide a shorthand when you just need a two-color gradient without constructing
86+
your own `Paint` object.
87+
88+
Radial gradients are equally straightforward using
89+
`fillRadialGradient()` or `fillRectRadialGradient()`, which can render circular
90+
and rectangular radial transitions respectively. These APIs accept the
91+
inner/outer colors, focal point, and spread so you can combine them with linear
92+
gradients to build sophisticated backgrounds and lighting effects.
93+
6394
=== Glass Pane
6495

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

140171
=== Device Support
141172

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

144-
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.
178+
Notice that perspective transform is missing from the desktop/simulator port.
179+
Unfortunately there is no real equivalent to perspective transform in JavaSE that we could use.
145180

146181
=== A 2D Drawing App
147182

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

317352
==== Device Support
318353

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

322358
.Transforms Device Support
323359
[cols="2*"]
324360
|===
325361
|Platform
326362
|Affine Supported
327363

328-
| Simulator
364+
| Simulator/Desktop
329365
| Yes
330366

331367
| iOS
@@ -337,14 +373,8 @@ and their respective levels of support.
337373
| JavaScript
338374
| Yes
339375

340-
| J2ME
341-
| No
342-
343-
| BlackBerry (4.2 & 5)
344-
| No
345-
346-
| Windows Phone
347-
| No (pending)
376+
| UWP
377+
| Yes
348378
|===
349379

350380

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

10041034

1035+
==== Global Alpha & Anti-Aliasing
1036+
1037+
So far we have relied on the per-pixel alpha stored in images and gradients. `Graphics`
1038+
also lets you apply a global alpha multiplier to every draw call by using
1039+
`setAlpha(int)` or `concatenateAlpha(int)` after checking `isAlphaSupported()`.
1040+
Both methods accept values from `0` (fully transparent) to `255` (fully opaque)
1041+
and remain active until you change them again. `concatenateAlpha()` is
1042+
especially handy when you need to temporarily fade a component because it
1043+
returns the previous alpha so you can restore it later.
1044+
1045+
Anti-aliasing can likewise be toggled at runtime. Call `isAntiAliasingSupported()`
1046+
and `isAntiAliasedTextSupported()` to discover which hints the current port
1047+
exposes, then use `setAntiAliased(boolean)` and `setAntiAliasedText(boolean)` to
1048+
opt into smoother edges for shapes and glyphs respectively. These switches make
1049+
it easy to balance rendering quality versus speed depending on the type of
1050+
content you draw.
1051+
1052+
10051053
==== Event Coordinates
10061054

10071055
The coordinate system and event handling are closely tied. You can listen for touch events on a component by

docs/developer-guide/io.asciidoc

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,19 @@ You can then read the token like this:
127127
String token = Preferences.get("token", null);
128128
----
129129

130+
The backing store filename defaults to `"codenameone.properties"`, but you can
131+
override it by calling `Preferences.setPreferencesLocation(String)` before your
132+
app touches the API. This is useful when you need to segregate preference
133+
namespaces per user or plug in an encrypted storage layer.
134+
135+
When you have a batch of updates, prefer the `Preferences.set(Map<String,Object>)`
136+
overload so that all values are persisted with a single disk write.
137+
138+
Preferences can also notify interested parties when a key changes. Register a
139+
`PreferenceListener` via `addPreferenceListener()` to react to updates made in
140+
other parts of your code (or even triggered remotely via `Codename One Push`).
141+
Remember to remove listeners you no longer need to avoid leaks.
142+
130143
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! +
131144
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)`.
132145

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

251264
.Portability Of SQLite
252265
****
253-
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.
254-
255-
You will notice that at this time support is still missing from the Windows builds.
266+
SQLite is supported on iOS, Android, JavaScript, Desktop/Simulator, and UWP
267+
builds. The JavaScript port relies on the browser's WebSQL implementation, so
268+
it may be unavailable in environments that have already removed that feature.
256269
257270
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!
258271
@@ -416,6 +429,17 @@ byte[] resultOfRequest = request.getData();
416429
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!
417430

418431

432+
==== Timeouts & Retries
433+
434+
Each request can override the global timeout using `setTimeout(int)`, which
435+
expects a duration in milliseconds. This is especially useful when you are
436+
talking to endpoints that occasionally need a longer window than the default
437+
NetworkManager setting. You can also configure how many times Codename One
438+
should retry a failing call silently by using `setSilentRetryCount(int)`. When
439+
the silent retry limit is reached the standard error handling kicks in (e.g.
440+
listeners fire, fail dialogs show, etc.).
441+
442+
419443
==== Threading
420444

421445
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.
@@ -1296,6 +1320,18 @@ Map<String, Object> jsonData = Rest.post(myUrl).body(bodyValueAsString).getAsJso
12961320

12971321
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.
12981322

1323+
Some highlights that are easy to miss:
1324+
1325+
* `.priority(byte)` lets you change the underlying `ConnectionRequest` priority
1326+
when you need certain calls to jump the queue.
1327+
* `.cookiesEnabled(boolean)` controls whether cookies are persisted for the
1328+
request when you need stateless behavior.
1329+
* `.useBoolean(boolean)` and `.useLongs(boolean)` toggle how the JSON parser
1330+
materializes number and boolean types inside the resulting `Map`, which is
1331+
handy when your backend is strict about data types.
1332+
* `.cacheMode(...)` and `.postParameters(...)` expose the same knobs as
1333+
`ConnectionRequest`, keeping you in the fluent API even for advanced tweaks.
1334+
12991335
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.
13001336

13011337
==== Rest in Practice - Twilio

docs/developer-guide/performance.asciidoc

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,17 @@ The Performance Monitor tool can be accessible via the #Simulator# -> #Performan
5252
.Main tab of the performance monitor: Logs and timings
5353
image::img/developer-guide/performance-monitor-tab-1.png[Main tab of the performance monitor: Logs and timings]
5454

55-
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.
55+
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
56+
includes Pause/Continue buttons so you can freeze the counters while you inspect
57+
the current snapshot, a "Clear Data" action to reset the tables, and a "GC"
58+
button that invokes the simulator's garbage collector so you can see how memory
59+
usage changes.
5660

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

59-
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.
63+
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
64+
"Image Memory Overhead" meter summarizes how much native image memory the
65+
current form consumes so you can correlate spikes with your drawing code.
6066

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

139145
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()`.
140146

147+
If your crash handler runs while networking is unavailable or you want to avoid
148+
blocking the EDT, use `Log.sendLogAsync()` instead. It performs the upload in a
149+
background thread and is what Codename One's lifecycle helper falls back to when
150+
regular error reporting fails.
151+
152+
You can also plug in your own crash reporting pipeline by calling
153+
`Display.getInstance().setCrashReporter(CrashReport)`. The
154+
https://www.codenameone.com/javadoc/com/codename1/system/CrashReport.html[`CrashReport`]
155+
callback will receive the exception, device information, and log payload so you
156+
can forward it to services like Firebase Crashlytics or your in-house tools.
157+
141158
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`.
142159

143160
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)`.

0 commit comments

Comments
 (0)