Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When the worker thread works, UI becomes choppy

I have a handwriting recognition app - the user draws with their finger, the app recognizes characters. The recognition engine runs in a worker thread that has the the minimal possible priority - Thread.MIN_PRIORITY. It's a purely CPU/memory algorithm, no I/O whatsoever. Still, when the thread is actively working, the UI becomes rather choppy. The finger strokes take a noticeable delay to appear. I also notice touch events getting lost.

Isn't that exactly what threading was supposed to help avoid? Why is the UI thread starved for CPU? How do convince the system to treat the worker thread as, well, a low-priority background thread?

It looks like the system is introducing (willingly or because of CPU starvation) a delay between invalidate() and onDraw(). Can I somehow lower that delay?

Testing on relatively old hardware - HTC Magic with Android 2.1.

like image 559
Seva Alekseyev Avatar asked Nov 06 '12 16:11

Seva Alekseyev


3 Answers

Try to add Thread.sleep(1) in main cycle in character recognition method

@Override
public void run() {
  while (!recognited) {

    //do some script

    try {
      Thread.sleep(1);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }
}

this sleep lets virtual machine to resume other thread a bit early and often

like image 33
neworld Avatar answered Sep 25 '22 08:09

neworld


Had same problem, so I made my thread:

  1. Thread.yield() after processing a chunk of work.

  2. Limited updates posted to UI thread with a min 500 ms interval (causing much less re-draw).

  3. Made the worker work on prioritized buckets of data, this focuses on updating the views, user is currently interacting with.

Now the whole UI is really lazy, but free of lag.

Here's what my worker's scheduling method looks like (actual work is done by Process method):

//--low priority
Thread.currentThread().setPriority(Thread.MIN_PRIORITY);

//--as long as there's more work to do, and not cancelled--
while (mPriorityBuffer.hasNext() && !isCancelled()) {

    //--get the work with highest priority--
    Work next = mPriorityBuffer.getNext();

    //--do work--
    Update u = mProcessor.process(next);

    // collect updates for main thread
    mUpdates.push(u);

    long timeNow = Calendar.getInstance().getTimeInMillis();
    if(timeNow - timeLast > 500){
        //--its been quite a while now, update ui--
        postUpdatesToMainThread();
        timeLast = timeNow;
    }

    //--let UI thread work on updates--
    Thread.yield();
}
like image 110
S.D. Avatar answered Sep 23 '22 08:09

S.D.


It is possible that your GUI thread is floaded with touch events, if so then solution is to introduce few ms wait on UI thread and boosting your worker thread. More on this here:

https://groups.google.com/forum/?fromgroups=#!topic/android-developers/Oe6k1_bm38o

also, maybe you are processing too much data, like if no movement actually happend, or movement is not significant enough.

like image 26
marcinj Avatar answered Sep 23 '22 08:09

marcinj