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?
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 } });
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.
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:
onProgressUpdate
method that makes it easier to code in order to notify the UI Thread from the Background ThreadHere 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;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With