Image drawing on iOS is erratic

42 views
Skip to first unread message

nickk...@gmail.com

unread,
Jul 18, 2016, 12:32:32 AM7/18/16
to CodenameOne Discussions
I'm drawing clocks in my app. They are just a circle with two lines, and many of these are drawn as images and added to the hashmap of a list model (as 'icon' ) and applied to a MultiList. There are about 20 items on the list, with icon (a clock) text and emblem.

The clock is made by a class that has a static method that returns a method showing the time passed to it. The image is created by Image.create(width, height). Graphics object is obtained by calling getGraphics on this image, and then used to draw a circle and two lines.
        Image clock = Image.createImage(size, size, 0x00000000);     
        Graphics g = clock.getGraphics();
        g.setAntiAliased(true);
        g.setAlpha(255);

//draw circle and hands with g.drawShape(GeneralPath,Stroke);

Shape drawn is obtained from GeneralPath.createFromPool() and reset and then recycled between each call. Stroke is set once and used for all subsequent calls.


All of this is done on the EDT I believe, its called from onPostShow but it is wrapped in a Display.getInstance().invokeAndBlock() so I can show and then hide a InfiniteProgress dialog.
                Dialog d = new InfiniteProgress().showInifiniteBlocking();
        Display.getInstance().invokeAndBlock(() -> {
 //Draw clock in here - along with a couple of other method calls, all layout related.
        });
        d.dispose();




Works great on Android and the simulator. On iOS it works for about half the items on the list, the other half the time there are random errors - sometimes images are missing entirely (remaining content in the list item is shifted left), sometimes the image is totally black, and sometimes the circle is missing but the hands are draw.

Any things I should be aware of about this approach? 

Shai Almog

unread,
Jul 18, 2016, 12:58:11 AM7/18/16
to CodenameOne Discussions, nickk...@gmail.com
invokeAndBlock is by definition off the EDT.
iOS is really sensitive to off EDT drawing due to the way offline images are drawn there (they use a global context object).

nickk...@gmail.com

unread,
Jul 18, 2016, 1:01:59 AM7/18/16
to CodenameOne Discussions, nickk...@gmail.com

Then this Javadoc is confusing or incorrect:

Invokes runnable and blocks the current thread, if the current thread is the
edt it will still be blocked however a separate thread would be launched
to perform the duties of the EDT while it is blocked. Once blocking is finished
the EDT would be restored to its original position.

My reading of that is that calling invoke and block on the EDT invokes the runnable on the EDT and moves drawing / events to another thread while its blocked.

If this is no good, what is an approach for drawing on a number of images on iOS while showing an infinite progress dialog so that the UI doesn't hang?

Shai Almog

unread,
Jul 19, 2016, 12:14:21 AM7/19/16
to CodenameOne Discussions, nickk...@gmail.com
Yes, I refined the JavaDoc there. We didn't touch it since 2007.
The EDT section in the developer guide explains this better.

nickk...@gmail.com

unread,
Aug 9, 2016, 8:08:07 PM8/9/16
to CodenameOne Discussions, nickk...@gmail.com
Ok, so what's the workflow for drawing images on iOS without blocking the EDT (i.e., showing a progress indicator or inifiniteprogress?)

Shai Almog

unread,
Aug 10, 2016, 1:51:42 AM8/10/16
to CodenameOne Discussions, nickk...@gmail.com
What do you need to draw that will take so long it will require progress indication?
Drawing to any surface needs the EDT, the rendering pipeline is pretty deep in some OS's and very complex. Making it threadsafe would make it unusable...

nickk...@gmail.com

unread,
Aug 10, 2016, 7:02:31 PM8/10/16
to CodenameOne Discussions, nickk...@gmail.com
I'm drawing clocks for a list of events that have different times that need to be displayed.

I am caching them so they aren't generated every time but they do need to be generated at some point. Currently there are about 20 and it takes under a second so it just 'sticks' the UI briefly. 

I was concerned about scalability if there were 100+ but if there is nothing that can be done to manage this I'll just put a static loading message and block the UI while images are created on the EDT.

There is thread safe drawing on iOS since iOS 4.0 but I don't know enough about the details under the hood of the VM to know if its possible with how Codename One is handling the drawing.

What are circumstances where invokeAndBlock called from the EDT would be useful? I've always used it to show a loading indicator while setting up a form in postShow or beforeShow and it seems to work but if its not running on the EDT it probably is causing issues.

           Dialog d = new InfiniteProgress().showInifiniteBlocking();
        Display.getInstance().invokeAndBlock(() -> {
 //layout the form here, set models for list from local data sources (e.g., SQLite), add components to the heirarchy or whatever else can be done (without network).
        });
        d.dispose();

Shai Almog

unread,
Aug 11, 2016, 1:10:13 AM8/11/16
to CodenameOne Discussions, nickk...@gmail.com
Drawing to images on iOS relies on a buffer which is global so it can't be threadsafe.
You can use a UITimer to create the clocks one by one on the EDT and cancel the timer when you are done.
Reply all
Reply to author
Forward
0 new messages