2

I have a thread with a priority set to Thread.MIN_PRIORITY + 1 that does some image processing for me (resizing, reading and writing).

I've noticed that whenever that thread is working on an image, animations in my UI thread start to stutter and freeze up.

The priority is low enough such that animations should take a higher priority over that thread, and my CPU certainly isn't starved for resources.

Is there any particular reason this might be happening?


Edit - my thread:

public class WorkerQueue extends Thread {
  public Handler handler;
  int priority = Thread.MIN_PRIORITY + 1;
  private static WorkerQueue self = null;

  public static WorkerQueue getInstance() {
    if (self == null) {
      self = new WorkerQueue();
      self.start();
      self.setPriority(priority);
    }

    return self;
  }

  @Override
  public void run() {
      Looper.prepare();
      handler = new Handler();
      handler.getLooper().getThread().setPriority(priority);
      Looper.loop();    
  }

  public synchronized void enqueueTask(final Worker task) {
    handler.post(new Runnable() {
      @Override
      public void run() {
          task.run();
      }
    });
  }
}
Nyx
  • 2,233
  • 1
  • 12
  • 25
  • 1
    Instead of answering your question i would suggest you to read this - https://developer.android.com/training/displaying-bitmaps/index.html – Prachur Mar 11 '14 at 06:17
  • I have read through it, and since my task is quite long running I decided to use my own looper thread instead of an asyncTask. Other than that, my code is quite similar to the examples given there. – Nyx Mar 11 '14 at 06:56

3 Answers3

2

It may be GC.

Image processing can require a lot of memory allocations and consequent garbage collection. GCs in Android use the mark-and-sweep algorithm which requires the VM to stop execution of your program - you can see how this can cause UI stuttering. See for example this answer and this on-the-money quote:

The main disadvantage of the mark-and-sweep approach is the fact that that normal program execution is suspended while the garbage collection algorithm runs. In particular, this can be a problem in a program that interacts with a human user or that must satisfy real time execution constraints. For example, an interactive application that uses mark-and sweep garbage collection becomes unresponsive periodically.

You can confirm whether this is correct by looking at logcat - this prints out a message for every GC, and for that time, the UI thread will be blocked.

If it is GC, then one approach to resolve it would be to look at your memory allocation patterns and see if you can reduce memory churn, maybe by reusing buffers and working memory.

Andrew Alcock
  • 19,401
  • 4
  • 42
  • 60
  • Definitely will look into this and see if the logs match up with what I'm seeing! Will report back with my results – Nyx Mar 24 '14 at 03:17
  • It seems it was the GC. GC_FOR_ALLOC was being called frequently and taking up to 100ms which blocks all threads including the UI thread! – Nyx Mar 25 '14 at 17:09
0

LazyList can help you.
This is open source that loading image in other thread and display on UI when it finish

henry4343
  • 3,871
  • 5
  • 22
  • 30
  • LazyList doesn't quite suit my needs. I've already got an implementation for loading and displaying images that works fine. My issue is more to do with resizing – Nyx Mar 11 '14 at 06:54
-1

You should be using AsyncTask to process and display bitmaps:

https://developer.android.com/training/displaying-bitmaps/process-bitmap.html#async-task

This class specifically designed for this usage, as to why this is happening on your Thread it is probably related to how Android handles GC differently to regular Java applications. This is especially true when dealing with Bitmap objects displayed in a ListView or GridView.

tpbapp
  • 2,506
  • 2
  • 19
  • 21
  • Workers (Runnables) that get enqueued to the thread that I posted above don't actually touch the UI thread, which is why I didn't see the need to use an AsyncTask. All they do is load an image from disk, resize it, and save the resized image to disk. – Nyx Mar 24 '14 at 03:16
  • I'm aware of that, but you still need to use AsyncTask especially when loading from the disk or network location. If loading from memory it's not as important. You need to read the document I linked to, specifically the parts about AsyncDrawable and WeakReference. – tpbapp Mar 24 '14 at 03:22