If I want to update my UI from a background thread when a message is received from a web service call, would the below be considered a safe option? I'm worried about potential memory leaks having the handler in my Application class
public class MyApplication extends Application {
private static long uiThreadId;
private static Handler uiHandler;
#Override
public void onCreate() {
super.onCreate();
uiThreadId = Thread.currentThread().getId();
uiHandler = new Handler();
}
public static void customRunOnUiThread(Runnable action) {
if (Thread.currentThread().getId() != uiThreadId) {
uiHandler.post(action);
} else {
action.run();
}
} }
And then in the class that deals with the messages received in the separate threads:
new Thread(
new Runnable() {
#Override
public void run() {
// make web service call
MyApplication.customRunOnUiThread(new Runnable() {
#Override
public void run() {
httpResponseHandler.onSuccess();
}
});
}
}
}).start();
My alternative is to use parallel AsyncTasks doing the work in the doInBackground method and updating the UI in the onPostExecute method. Both of these options work, but I'm not sure which one is 'most' correct so to speak.
Better way is to register BroadcastReceiver and using LocalBroadcastManager send the broadcast on receiving any message
Related
Can I create onClickListener() for a button in more than 1 threads that are executing simultaneously?
Would that listener be called individually in every thread?
No, a button has only one onClickListener. Setting a second one overwrites any listener set previously. And that function will only be called on the UI thread. You can pass messages to multiple threads from that function though.
There are a lot of ways to communicate between threads. Since you are wondering how to pass something over to the thread, here is a simple example:
public class MainActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
...
//Start a thread you need to
anotherThread = new AnotherThread();
anotherThread.start();
}
protected void onResume() {
...
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
anotherThread.sendData(message);
}
});
}
}
public class AnotherThread extends Thread {
//Instantiate handler to associate it with the current thread.
//Handler enqueues all tasks in the MessageQueue using Looper
//and execute them upon coming out of queue;
private Handler handler;
#Override
public void run() {
try {
//Here we create a unique Looper for this thread.
//The main purpose of which to keep thread alive looping through
//MessageQueue and send task to corresponding handler.
Looper.prepare();
handler = new Handler() {
#Override
public void handleMessage(Message msg) {
//manage incoming messages here
String value = msg.getData().getString("key");
}
};
Looper.loop();
} catch (Throwable e) {
e.printStackTrace();
}
}
public synchronized void sendData(Message message) {
handler.post(new Runnable() {
#Override
public void run() {
handler.sendMessage(message);
}
});
}
}
To get more about thread communication I'd recommend you the following:
1, 2, 3.
I am trying to run all of my service requests on a background thread. To do this, I make a ExecutorService and redirect all calls to the main handler (handleMessage) to a handler on the new thread (handleMessageHelper):
ExecutorService background = Executors.newSingleThreadExecutor();
//handles messages from client
class IncomingHandler extends Handler {
#Override
public void handleMessage(final Message msg) {
background.execute(new Runnable() {
#Override
public void run() {
handleMessageHelper(msg); //actually handles the request
}
});
super.handleMessage(msg);
}
}
However, somehow the msg is getting corrupted between when the new Runnable is created, and when the run() function is called. Any way to prevent this?
I need to create a UI fragment that can be updated by many background threads. Does making the handler publicly accessible in the way shown below, have any complications? I have not come across anyone doing this and so I am a bit worried.
public class MainFragment extends Fragment {
private static class MyHandler extends Handler {
WeakReference<MainFragment> mFrag;
MyHandler(MainFragment aFragment) {
mFrag = new WeakReference<MainFragment>(aFragment);
}
#Override
public void handleMessage(Message message) {
// Unpack message and handle specific UI updates
// calling MainFragment's methods using the
// weak reference 'mFrag'
}
}
private static MyHandler mHandler;
// Create handler on resume
#Override
public void onResume() {
super.onResume();
mHandler = new MyHandler(this);
}
#Override
// Destroy handler on pause
public void onPause() {
super.onPause();
mHandler = null;
}
// When a background thread wants to update the main
// UI, it calls this method as
// MainFragment.getHandler().post(message)
public static Handler getHandler() {
return mHandler;
}
}
That's not a very clean design but it should not leak memory if that's your concern.
I need a timer which will send a message for its' handler. I've made a class that implements Runnable and I feed its' object to the thread runnable constructor. When I start the thread it hangs application and it obviously isn't working asyncroniously. I could've used AsyncTask but I've also heard that they're designed for short-term operations while my background timer must work throughout activity onResumed state. Would you mind pointing out my mistake and maybe giving useful links on the subject of threads in android. Thanks.
Here's the code I've written:
#Override
public void onResume() {
// TODO Auto-generated method stub
super.onResume();
_myTimerInstance = new MyTimer(new Handler() {
#Override
public void dispatchMessage(Message msg) {
super.dispatchMessage(msg);
// ...
}
});
_myThread = new Thread(_myTimerInstance);
_myThread.run();
}
private static class MyTimer implements Runnable {
private Handler _myHandler;
private boolean _activityHasBeenLeft;
public MyTimer(Handler myHandler) {
_myHandler = myHandler;
}
public void setActivityHasBeenLeft(boolean b) {
_activityHasBeenLeft = b;
}
#Override
public void run() {
while (!_activityHasBeenLeft) {
try {
Thread.sleep(2000);
_myHandler.sendEmptyMessage(0);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
You should always use Thread.start() not Thread.run()
Thread.run() is like a normal method call and is run on the same thread.
use
_myThread.start();
I have the following:-
public class resApp extends MapActivity implements Runnable {
public void run() {
searchImage.setVisibility(View.GONE);
}
}
I also have a background thread that runs before this but that seems to run ok.
When i run the app the run() never gets called.
Can you help?
This code did work about 6 months ago but the device was 2.1.
Thanks
Chris
edit
I had already implemented
private Handler handler;
handler = new Handler() {
#Override
public void handleMessage(Message msg) {
if (msg.toString().equalsIgnoreCase("1")) {
ad.dismiss();
} else {
pd.dismiss();
}
}
};
as an example and I already have an asynchronous task that runs in the back ground and in 2.1 I could have getters and setters in there. I have now had to pull these out and put them into the run() method as 2.2 doesn't like setting onclicklistener in an async task.
All I need to do is call the run() method on post execute but have tried everything:-
protected void onPostExecute(Object result) {
// Pass the result data back to the main activity
if (dialog != null) {
resApp.this.dialog.dismiss();
}
}
Could I just do:-
handler = new Handler() {
#Override
public void handleMessage(Message msg) {
this.resApp.run();
}
};
You can call the run() method by using Handler.
Handler myHandler = new Handler();
resApp myObj;
And call it by using myHandler.post(myObj);