Running code in main thread from another thread

前端 未结 16 1824
一个人的身影
一个人的身影 2020-11-22 13:50

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

相关标签:
16条回答
  • 2020-11-22 14:15

    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);
    
    0 讨论(0)
  • 2020-11-22 14:18

    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 where no context available, then use

    Handler(Looper.getMainLooper()).post {  
        //code that runs in main
    }
    
    0 讨论(0)
  • 2020-11-22 14:18

    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 {
    
    }
    
    0 讨论(0)
  • 2020-11-22 14:18

    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
    }
    
    0 讨论(0)
  • 2020-11-22 14:20

    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

    0 讨论(0)
  • 2020-11-22 14:21

    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);
    
    0 讨论(0)
提交回复
热议问题