Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android: proper way to pass a message from background thread to UI thread?

I have been reading a lot about threads, handlers, loopers, etc and I am very confused. In my app I want to have the first Activity start a background worker. This background worker will continually request data from a TCP socket and (hopefully) post the new info to the UI thread as the data arrives. If the user transitions to a new Activity the background needs to keep doing it's thing but only send different messages to the UI thread so it can update the new layout accordingly.

here is what i have so far...This is in my main activity file

public class MyTCPTest extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // set the layout
        setContentView(R.layout.main);
        // create a handler to handle messages from bg thread
        Handler handler = new Handler();

        BgWorkerThread bgw = new BgWorkerThread();
        bgw.start();
 }

in another file i define my background worker thread like this...

public class BgWorkerThread extends Thread {    
@Override
public void run(){

    while(true)
    {
        try {
        // simulate a delay (send request for data, receive and interpret response) 
        sleep(1000);

                    // How do I send data here to the UI thread?

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
} 

If the UI switches to a different Activity will this thread remain running? Also, how does the this thread know which activity to send the message to? Obviously I want it to always send the data to the Activity that is currently active. Does that happen automatically?

Finally, when the UI switches to a different activity the bgworker needs to be notified so that it can begin requesting data that is relevant to the new Activity layout. What is the best way to inform the worker of the change? Couldn't I just create a public method in the BgWorkerThread class that could be called when Activities load?

like image 575
PICyourBrain Avatar asked Sep 10 '11 04:09

PICyourBrain


People also ask

Can we update UI from background thread?

In this case, to update the UI from a background thread, you can create a handler attached to the UI thread, and then post an action as a Runnable : Handler handler = new Handler(Looper. getMainLooper()); handler. post(new Runnable() { @Override public void run() { // update the ui from here } });

How do threads communicate with each other Android?

The most common thread communication use case in Android is between the UI thread and worker threads. Hence, the Android platform defines its own message passing mechanism for communication between threads. The UI thread can offload long tasks by sending data messages to be processed on background threads.


1 Answers

I've illustrated the same code and a more detailed steps in the followingSO Question. To summarize, in order to notify your UI and give it different context, I suggest the following:

  • Have a map that map requestId to a Handler (assuming you have the context of request id). You would register appropriate Handler in the Activity thus you could have the handlers behave differently for each Activity (e.g. updating various UI elements when it received the response from the server)
  • Change to AsyncTask for Threading Model as it has onProgressUpdate method that makes it easier to code in order to notify the UI Thread from the Background Thread

Here is the stub/pseudocode for your BackgroundThread

public class ResponseHandler extends AsyncTask<Void, String, Integer> {
    boolean isConnectionClosed = false;
    Map<Integer, Handler> requestIdToMapHandler;

    public ResponseHandler() {
        this.requestIdToMapHandler = new HashMap<Integer, Handler>();
    }

    @Override
    protected Integer doInBackground(Void... params) {
        int errorCode = 0;

        try {
            // while not connection is not close
            while(!isConnectionClosed){
                // blocking call from the device/server
                String responseData = getResponse();

                // once you get the data, you publish the progress
                // this would be executed in the UI Thread
                publishProgress(responseData);
            }
        } catch(Exception e) {
            // error handling code that assigns appropriate error code
        }

        return errorCode;

    }

    @Override
    protected void onPostExecute(Integer errorCode) {
        // handle error on UI Thread
    }

    @Override
    protected void onProgressUpdate(String... values) {
        super.onProgressUpdate(values);
        String responseData = values[0];

        // the response contains the requestId that we need to extract
        int requestId = extractId(responseData);

        // next use the requestId to get the appropriate handler
        Handler uiHandler = getUIHandler(requestId);

        // send the message with data, note that this is just the illustration
        // your data not necessary be jut String
        Message message = uiHandler.obtainMessage();
        message.obj = responseData;
        uiHandler.sendMessage(message);
    }

    /***
     * Stub code for illustration only
     * Get the handler from the Map of requestId map to a Handler that you register from the UI
     * @param requestId Request id that is mapped to a particular handler
     * @return
     */
    private Handler getUIHandler(int requestId) {
        return null;
    }

    /***
     * Stub code for illustration only, parse the response and get the request Id
     * @param responseId
     * @return
     */
    private int extractId(String responseId) {
        return 0;
    }

    /***
     * Stub code for illustration only
     * Call the server to get the TCP data. This is a blocking socket call that wait
     * for the server response
     * @return
     */
    private String getResponse() {
        return null;
    }
}
like image 197
momo Avatar answered Nov 10 '22 05:11

momo