391

In an android service I have created thread(s) for doing some background task.

I have a situation where a thread needs to post certain task on main thread's message queue, for example a Runnable.

Is there a way to get Handler of the main thread and post Message/Runnable to it from my other thread?

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
Ahmed
  • 14,503
  • 22
  • 92
  • 150
  • 2
    You can also use Custom broadcast receiver....try my answer here, [Inner Broadcast Receiver][1] [1]: http://stackoverflow.com/a/22541324/1881527 – Melbourne Lopes Mar 21 '14 at 09:29
  • There are many ways. Apart from David's answer & dzeikei's comment in his answer, (3) you can use a Broadcast Receiver, or (4) pass the handler in extras of Intent used to start the service, and then retrieve the main thread's handler inside service using getIntent().getExtras() . – Ashok Bijoy Debnath Dec 04 '14 at 08:37
  • 2
    @sazzad-hissain-khan, Why tag this question from 2012 with mostly answers in Java with the kotlin tag? – Tenfour04 Aug 07 '19 at 18:45

16 Answers16

696

NOTE: This answer has gotten so much attention, that I need to update it. Since the original answer was posted, the comment from @dzeikei has gotten almost as much attention as the original answer. So here are 2 possible solutions:

1. If your background thread has a reference to a Context object:

Make sure that your background worker threads have access to a Context object (can be the Application context or the Service context). Then just do this in the background worker thread:

// Get a handler that can be used to post to the main thread
Handler mainHandler = new Handler(context.getMainLooper());

Runnable myRunnable = new Runnable() {
    @Override 
    public void run() {....} // This is your code
};
mainHandler.post(myRunnable);

2. If your background thread does not have (or need) a Context object

(suggested by @dzeikei):

// Get a handler that can be used to post to the main thread
Handler mainHandler = new Handler(Looper.getMainLooper());

Runnable myRunnable = new Runnable() {
    @Override 
    public void run() {....} // This is your code
};
mainHandler.post(myRunnable);
David Wasser
  • 93,459
  • 16
  • 209
  • 274
  • 1
    Thanks David it worked out for me, one more thing if you could help me with, if I extend Handler and impl handleMessage() would it prevent main thread from handling its messages ? that's only a question out of curosity.. – Ahmed Jun 20 '12 at 19:03
  • 2
    No. If you subclass `Handler` (or use `Handler.Callback` interface) your `handleMessage()` method will ONLY be called for messages that have been posted using your handler. The main thread is using a different handler to post/process messages so there is no conflict. – David Wasser Jun 20 '12 at 19:22
  • 215
    I believe you won't even need context if you use `Handler mainHandler = new Handler(Looper.getMainLooper());` – dzeikei Nov 05 '13 at 03:57
  • 6
    Minor point; your code doesn't go where the ... currently is. It should be `new Runnable(){@Override public void run() {....}};` – Richard Tingle Jul 31 '14 at 10:19
  • @DavidWasser thank you very much your code does exactly what i want but just a query. I am using this code to get the location of the user in the splashScreen. How can i set a boolean variable to check if i have got a response depending on which i decide the next activity to be started. – Sagar Devanga Jan 21 '15 at 07:53
  • 2
    @SagarDevanga This is not the right place to ask a different question. Please post a new question , not a comment to an unrelated answer. You will get better and faster response that way. – David Wasser Jan 21 '15 at 09:10
  • If you don't want to use a Runnable just do it this way: Message msg = mainHandler.obtainMessage(); msg.sendToTarget(); //Don't use dispatchMessage – Shailendra Yadav Sep 09 '19 at 05:24
  • If you have access to the activity then you can call the runOnUiThread() method to post runnable to be executed on the UI thread from another thread. – Ahad Dec 01 '19 at 07:29
161

As a commenter below pointed correctly, this is not a general solution for services, only for threads launched from your activity (a service can be such a thread, but not all of those are). On the complicated topic of service-activity communication please read the whole Services section of the official doc - it is complex, so it would pay to understand the basics: http://developer.android.com/guide/components/services.html#Notifications

The method below may work in the simplest cases:

If I understand you correctly you need some code to be executed in the GUI thread of the application (cannot think about anything else called "main" thread). For this there is a method on Activity:

someActivity.runOnUiThread(new Runnable() {
        @Override
        public void run() {
           //Your code to run in GUI thread here
        }//public void run() {
});

Doc: http://developer.android.com/reference/android/app/Activity.html#runOnUiThread%28java.lang.Runnable%29

Hope this is what you are looking for.

Gurunath Sripad
  • 1,308
  • 2
  • 14
  • 24
Alexey Vassiliev
  • 2,349
  • 2
  • 17
  • 8
  • 24
    OP says he is running threads in a `Service`. You cannot use `runOnUiThread()` in a `Service`. This answer is misleading and doesn't address the asked question. – David Wasser Nov 27 '13 at 09:25
93

Kotlin versions

When you are on an activity, then use

runOnUiThread {
    //code that runs in main
}

When you have activity context, mContext then use

mContext.runOnUiThread {
    //code that runs in main
}

When you are in somewhere outside activity where no context available, then use

Handler(Looper.getMainLooper()).post {  
    //code that runs in main
}
Sazzad Hissain Khan
  • 37,929
  • 33
  • 189
  • 256
32

There is another simple way, if you don't have an access to the Context.

1). Create a handler from the main looper:

Handler uiHandler = new Handler(Looper.getMainLooper());

2). Implement a Runnable interface:

Runnable runnable = new Runnable() { // your code here }

3). Post your Runnable to the uiHandler:

uiHandler.post(runnable);

That's all ;-) Have fun with threads, but don't forget to synchronize them.

tema_man
  • 443
  • 4
  • 7
31

A condensed code block is as follows:

   new Handler(Looper.getMainLooper()).post(new Runnable() {
       @Override
       public void run() {
           // things to do on the main thread
       }
   });

This does not involve passing down the Activity reference or the Application reference.

Kotlin Equivalent:

    Handler(Looper.getMainLooper()).post(Runnable {
        // things to do on the main thread
    })
Matt Lacey
  • 8,227
  • 35
  • 58
david m lee
  • 2,547
  • 26
  • 14
29

If you run code in a thread, e.g. do delaying some action, then you need to invoke runOnUiThread from the context. For example, if your code is inside MainActivity class then use this:

MainActivity.this.runOnUiThread(new Runnable() {
    @Override
    public void run() {
        myAction();
    }
});

If your method can be invoked either from main (UI thread) or from other threads you need a check like:

public void myMethod() {
   if( Looper.myLooper() == Looper.getMainLooper() ) {
       myAction();
   }
   else {

}
Alexander Volkov
  • 7,904
  • 1
  • 47
  • 44
  • 7
    OP says he is running threads in a `Service`. You cannot use `runOnUiThread()` in a `Service`. – David Wasser Nov 27 '13 at 09:27
  • @DavidWasser Is that documented anywhere? The method docs don't mention anything about it. http://developer.android.com/reference/android/app/Activity.html#runOnUiThread%28java.lang.Runnable%29 – Greg Brown Aug 26 '15 at 12:49
  • 1
    @GregBrown As you've indicated by your link to the `Activity` documentation, `runOnUiThread()` is a method of `Activity`. It is not a method of `Service`, therefore you cannot use it. What could be clearer than that? – David Wasser Aug 04 '16 at 16:41
  • @DavidWasser Fair enough. I don't even remember why I asked that question now (it was posted almost a year ago). – Greg Brown Aug 07 '16 at 20:42
8

I know this is an old question, but I came across a main thread one-liner that I use in both Kotlin and Java. This may not be the best solution for a service, but for calling something that will change the UI inside of a fragment this is extremely simple and obvious.

Java (8):

 getActivity().runOnUiThread(()->{
      //your main thread code
 });

Kotlin:

this.runOnUiThread {
     //your main thread code
}
Dmytro Rostopira
  • 10,588
  • 4
  • 64
  • 86
mevdev
  • 701
  • 8
  • 16
6

HandlerThread is better option to normal java Threads in Android .

  1. Create a HandlerThread and start it
  2. Create a Handler with Looper from HandlerThread :requestHandler
  3. post a Runnable task on requestHandler

Communication with UI Thread from HandlerThread

  1. Create a Handler with Looper for main thread : responseHandler and override handleMessage method
  2. Inside Runnable task of other Thread ( HandlerThread in this case), call sendMessage on responseHandler
  3. This sendMessage result invocation of handleMessage in responseHandler.
  4. Get attributes from the Message and process it, update UI

Example: Update TextView with data received from a web service. Since web service should be invoked on non-UI thread, created HandlerThread for Network Operation. Once you get the content from the web service, send message to your main thread (UI Thread) handler and that Handler will handle the message and update UI.

Sample code:

HandlerThread handlerThread = new HandlerThread("NetworkOperation");
handlerThread.start();
Handler requestHandler = new Handler(handlerThread.getLooper());

final Handler responseHandler = new Handler(Looper.getMainLooper()) {
    @Override
    public void handleMessage(Message msg) {
        txtView.setText((String) msg.obj);
    }
};

Runnable myRunnable = new Runnable() {
    @Override
    public void run() {
        try {
            Log.d("Runnable", "Before IO call");
            URL page = new URL("http://www.your_web_site.com/fetchData.jsp");
            StringBuffer text = new StringBuffer();
            HttpURLConnection conn = (HttpURLConnection) page.openConnection();
            conn.connect();
            InputStreamReader in = new InputStreamReader((InputStream) conn.getContent());
            BufferedReader buff = new BufferedReader(in);
            String line;
            while ((line = buff.readLine()) != null) {
                text.append(line + "\n");
            }
            Log.d("Runnable", "After IO call:"+ text.toString());
            Message msg = new Message();
            msg.obj = text.toString();
            responseHandler.sendMessage(msg);


        } catch (Exception err) {
            err.printStackTrace();
        }
    }
};
requestHandler.post(myRunnable);

Useful articles:

handlerthreads-and-why-you-should-be-using-them-in-your-android-apps

android-looper-handler-handlerthread-i

Ravindra babu
  • 37,698
  • 11
  • 250
  • 211
6

The simplest way especially if you don't have a context, if you're using RxAndroid you can do:

AndroidSchedulers.mainThread().scheduleDirect {
    runCodeHere()
}
Inn0vative1
  • 2,014
  • 3
  • 27
  • 43
5

More precise Kotlin code using handler :

Handler(Looper.getMainLooper()).post {  
 // your codes here run on main Thread
 }
Hamed Jaliliani
  • 2,789
  • 24
  • 31
5
ContextCompat.getMainExecutor(context).execute {
  // do something
}
philoopher97
  • 772
  • 1
  • 6
  • 18
4

One method I can think of is this:

1) Let the UI bind to the service.
2) Expose a method like the one below by the Binder that registers your Handler:

public void registerHandler(Handler handler) {
    mHandler = handler;
}

3) In the UI thread, call the above method after binding to the service:

mBinder.registerHandler(new Handler());

4) Use the handler in the Service's thread to post your task:

mHandler.post(runnable);
Dheeraj Vepakomma
  • 26,870
  • 17
  • 81
  • 104
4

So most handy is to do sort of:

import android.os.AsyncTask
import android.os.Handler
import android.os.Looper

object Dispatch {
    fun asyncOnBackground(call: ()->Unit) {
        AsyncTask.execute {
            call()
        }
    }

    fun asyncOnMain(call: ()->Unit) {
        Handler(Looper.getMainLooper()).post {
            call()
        }
    }
}

And after:

Dispatch.asyncOnBackground {
    val value = ...// super processing
    Dispatch.asyncOnMain { completion(value)}
}
HotJard
  • 4,598
  • 2
  • 36
  • 36
2

Follow this method. Using this way you can simply update the UI from a background thread. runOnUiThread work on the main(UI) thread . I think this code snippet is less complex and easy, especially for beginners.

AsyncTask.execute(new Runnable() {
            @Override
            public void run() {

            //code you want to run on the background
            someCode();

           //the code you want to run on main thread
 MainActivity.this.runOnUiThread(new Runnable() {

                    public void run() {

/*the code you want to run after the background operation otherwise they will executed earlier and give you an error*/
                        executeAfterOperation();

                   }
                });
            }
        });

in the case of a service

create a handler in the oncreate

 handler = new Handler();

then use it like this

 private void runOnUiThread(Runnable runnable) {
        handler.post(runnable);
    }
MarGin
  • 2,078
  • 1
  • 17
  • 28
1

for Kotlin, you can use Anko corountines:

update

doAsync {
   ...
}

deprecated

async(UI) {
    // Code run on UI thread
    // Use ref() instead of this@MyActivity
}
kuzdu
  • 7,124
  • 1
  • 51
  • 69
Francis
  • 6,788
  • 5
  • 47
  • 64
0
public void mainWork() {
    new Handler(Looper.getMainLooper()).post(new Runnable() {
        @Override
        public void run() {
            //Add Your Code Here
        }
    });
}

This can also work in a service class with no issue.

  • While this code might answer the question you still might consider adding a few explanatory sentences as this increases the value of your answer for other users! – MBT Aug 23 '18 at 12:42