4

in my mainActivity, which is the sole activity of my application, I am creating the below handler and running a runnable inside it.

I have some misunderstandings about handlers and where they run.

See the code

Handler handler;

    @Override
    protected void onCreate(Bundle bundle)
    {
      handler = new Handler();
      handler.postDelayed(r , 5000);
    }

    Runnable r = new Runnable()
    {
         @Override 
         public void run() {
              FetchServerAndUpdateStatus(); //network stuff in here
              handler.postDelayed(r , 5000);
         }
    }
  • I assume this code will still run in UI thread and I won't be able to make any network calls in there no ?
  • If yes, what shall I do ? Create and use a seperate thread ?
  • If I created a new thread, How can I run the postdelayed method ? The thread does not have post delayed ?
  • Does not using handler/runnable and using TimerTask and Runnable instead a better approach ? Or, just like the above handler/runnable, that will also run on the UI thread, unless created inside a seperate one.
tony9099
  • 4,567
  • 9
  • 44
  • 73

2 Answers2

3

When you construct a Handler it is bound to the thread it is constructed on.

onCreate() is run on the UI thread so this handler will be bound to the Looper on the main thread, and thus will run on that thread.

If you want a handler you can use on another thread you can construct one. See the looper docs: https://developer.android.com/reference/android/os/Looper.html

Which has this block:

class LooperThread extends Thread {
  public Handler mHandler;

  public void run() {
      Looper.prepare();

      mHandler = new Handler() {
          public void handleMessage(Message msg) {
              // process incoming messages here
          }
      };

      synchronized (this) {
          this.notifyAll();
      }

      Looper.loop();
  }
}

Add this class and then in your onCreate do the following:

mLooperThread = new LooperThread();
mLooperThread.start();
synchronized (mLooperThread) {
  while (null == mLooperThread.mHandler) {
    mLooperThread.wait();
  }
}
mLooperThread.mHandler.postDelayed(r , 5000);

This will cause the runnable to be run NOT on the UI thread, which is probably what you wanted.

For tasks that need to interact with the UI an AsyncTask may be better since it includes a mechanism to run things that touch Views when the task is done on the UI thread, since anything that touches a View must be done on the UI thread.

The other mechanisms for executing on the UI thread are to post to the view itself:

https://developer.android.com/reference/android/view/View.html#post(java.lang.Runnable) or [https://developer.android.com/reference/android/view/View.html#postDelayed(java.lang.Runnable, long)](https://developer.android.com/reference/android/view/View.html#postDelayed(java.lang.Runnable, long))

Or to ask the Activity to run it on the UI for you:

https://developer.android.com/reference/android/app/Activity.html#runOnUiThread(java.lang.Runnable)

Nick Palmer
  • 2,589
  • 1
  • 25
  • 34
  • thanks a lot. I guess by far the explanation you gave was the most precise and novice friendly. I think way many people think that when creating a handler inside onCreate() or onResume() they are starting it on a seperate thread, which actually they are not. There is a big confusion between handlers and threads out there, which kind of got me lost. Thanks for fill in the blanks there. – tony9099 Sep 26 '13 at 07:29
  • This will cause: Attempt to invoke virtual method 'boolean android.os.Handler.post(java.lang.Runnable)' on a null object reference – user2905416 Oct 31 '19 at 01:41
  • Yes, there is a race on the construction of the mHandler which can be avoided using a monitor on the LooperThread. I updated the code to address this issue. – Nick Palmer Nov 06 '19 at 19:13
0
  1. It depends on what you do with your handler, you didn't show, how you want to obtain m_handler. If you create it with new Handler(Looper.getMainLooper()), it will run on UI thread.
  2. If you want to run code in background (network operations) you should use AsyncTask
joozek
  • 2,143
  • 2
  • 21
  • 32
  • can you elaborate more on Activty.getHandler() thing, where can I obtain it other than the activity ? Yes definitely I will be using network stuff so I need it to run on background. The above code as is, does it run on the UI thread or another thread ? – tony9099 Sep 25 '13 at 15:30
  • Sorry, I messed things up a bit. You can get main _looper_ by calling `Looper.getMainLooper()`. Looper is something that runs code in loops, you can than attach a handler to it with `new Handler(looper)`. I'll edit my answer anyway – joozek Sep 25 '13 at 15:36
  • If i create it without anything, like the above, where does it run ? – tony9099 Sep 25 '13 at 16:00
  • [Docs](http://developer.android.com/reference/android/os/Handler.html#Handler()) says that it will be run with looper bound to current thread. If you (or anyone) didn't create a looper for current thread, then an exception is thrown – joozek Sep 25 '13 at 16:48