screen.setCurrent() from a 2nd thread

13 messages - 5146 views

here's my case:

1) take an onAction click

2) launch a webservice object that asynchronously does someting on the network (on a new thread)

3) get the callback from the webservice object (called from 2nd thread)

4) handle the callback by displaying a new screen with setCurrent()

 

on some phones this works great (sony ericsson), though on N95, N82 and some other nokias, the new screen doesnt slide on until i press a key.

strange eh?

I've tried to do Kuix.getCanvas().repaint() but it didn't help.

my only solution is to push a task into the main worker that kickstarts the event processing:

        WorkerTask repaintTask = new WorkerTask() {
            public boolean run() {
                Kuix.getCanvas().repaint();
                return false;
            }
        };
        Worker.instance.pushTask(repaintTask);

 

is there a better way?

oops, that should return 'true' to be removed from the worker list

Excellent question, I was just contemplating a similar issue.  I have a listener we created that gets me to the callback.

Some of our callbacks should open new pages, which will hopefully work as expected, for example:

            Kuix.getFrameHandler().pushFrame(new HomeScreenFrame());
            Kuix.getFrameHandler().removeFrame(this);

but some will need to refresh the canvas.  We will even need to have listeners sitting on unanticipated messages from the server (like an IM from another user) so I will be running into the same issue very soon.

It would be great to get some feedback on this.

is there any official answer to this yet?  This is the source of many headaches for me in my product.  We're just weeks away from buying the commercial license for this, and stuff like this is a real problem.

Sorry, this isn't a solution. I'm also facing the same issue - my code it littered with Worker.pushTask(...) requests for interacting with Kuix from non-UI threads. This works, and I'll use this method if necessary, but it doesn't seem ideal.

This could be consider as the "Official" solution. But if someone have a better idea we're open ;)

Else you can take a look at the Kuix.getCanvas().repaintAsSoonAsPossible(). If the current thread is the worker one, the repaint is done immediately, else it would be repaint in the next worker loop.

Hi Pandora, Tofu and all future readers of this thread.

Kuix Version: 1.1.0

Just to confirm, the Worker Solution posted above resolved the "White Screen" and "Static Screen" issues we experienced.

 WorkerTask repaintTask = new WorkerTask() {
            public boolean run() {
                Kuix.getCanvas().repaint();
                return false;
            }
        };
        Worker.instance.pushTask(repaintTask);

For newbies here's how I did it (Moderators please correct where required):

OPEN: org.kalmeo.kuix.widget.Screen

ADD:
import org.kalmeo.util.worker.Worker;
import org.kalmeo.util.worker.WorkerTask;

FIND METHOD:
setCurrent()  in the Screen class

ADD CODE BELOW LINE "Kuix.getCanvas().getDesktop().setCurrentScreen(this);":

      //an effort to avoid white screens and hanging canvas
            WorkerTask repaintTask = new WorkerTask() {

                public boolean run() {
                    Kuix.getCanvas().repaint();
                    return false;
                }
            };
            Worker.instance.pushTask(repaintTask);

REBUILD you project. Thanks Pandora808 for this and many other solutions and tips. Much appreciated!

PS. If you haven't already bought the Kuix License, please consider doing it ASAP. We need to fund this project so that it doesn't stop developing.

Greetings from Sunny South Africa!

klickr will work,for the setCurrentScreen method will not effect immediatly,it also push a worktask to repait the new window,so if u use a thread to get data,sometimes the new window will not be shown untill u press any key,but it seldom happens in emulator.

Hi Shappy,

Yup, I experienced the exact same issue - but it was sort of resolved by pandora808's solution up-top. Having implemented that solution I never experienced the static-screen issue again. However, what I did discover was that once you push a new Task into the worker instance a "memory leak" occurs. The worker just keeps on creating objects even when there is no acitivity. This can be seen on a memory monitor. Just launch the app, push a new Task and then sit back and watch the memory fill up. Calling System.gc() clears out all the "spawned" objects - but new objects start forming at the very next worker cycle. An out of memory error results.

L.

Hi klickr,

I'm not very sure your problem(my English is poor),u mean that pushTask will make memory leak?And even cause out of memory error?I never have that problem,perhaps u must check your other code.My Midlet work well and can work for a long time,never cause out of menory error.

btw. what "pandora808's solution up-top" means? 808?

However, what I did discover was that once you push a new Task into the worker instance a "memory leak" occurs. The worker just keeps on creating objects even when there is no acitivity. This can be seen on a memory monitor.

 

I think you need to return true instead of false (@return <code>true</code> if the task need to be removed after execute).

Yes,memory leaks realy exist!,please read this code snipped in Worker.java:


                        for (runningTaskIndex = 0; runningTaskIndex < tasks.size(); ++runningTaskIndex)
                        {
                            task = (WorkerTask) tasks.elementAt(runningTaskIndex);
                            if (task.run())
                            {
                                tasks.removeElementAt(runningTaskIndex);
                                runningTaskIndex--;
                            }
                        }

We can see,if task.run() returns false,then the task will NEVER remove from the tasks list!!
but the setCurrent() method just modified can NOT direct return true,it will result some incomplete redrawing concern!
            WorkerTask repaintTask = new WorkerTask() {

                public boolean run() {
                    Kuix.getCanvas().repaint();
                    return false;
                }
            };
            Worker.instance.pushTask(repaintTask);

so, I give the following solution:

            Worker.instance.pushTask(new WorkerTask()
            {
                public boolean run()
                {
                    Kuix.getCanvas().repaint();
                    if (!isInWidgetTree())
                    {
                        return true;
                    }
                    return false;
                }
            });

if the screen widget not in widget tree(maybe removed from its parent),then the task can safely remove from tasks list.

BTW:pls forgive my poor English ;-)