Is there any problem with using multiple Handlers in the same Activity.
I noticed that in all samples provided in android official website they use a single handler and detect different actions depending on the value of "what", is this because of memory management, and high amount of memory used by the Handler? Or should I call it "bad code" and do it the clean way (Multiple handlers each responsible for a specific task)
Handler handler = new Handler()
{
#Override
public void handleMessage(Message msg) {
if (msg.what == 0){
// do something
}
else if (msg.what == 1){
// do something else
}
}
}
OR
Handler taskHandlerA = new Handler()
{
#Override
public void handleMessage(Message msg) {
// do something
}
}
Handler taskHandlerB = new Handler()
{
#Override
public void handleMessage(Message msg) {
// do something else
}
}
No there isn't such a limit (a Handler is just a message receiver), but if you want to do such a thing the more common approach is to have one Handler that you post Runnable objects to.
Here is some good reading on Loopers and Handlers.
When a Handler is created, it is automatically registered with its' Thread's Looper. This makes me think that you do not need multiple Handler's for a single thread. An Activity, specifically, one that uses multiple Thread's, could use multiple Handler's though.
Related
I've three runnables for three animations and I want to manage this in a good way to avoid any performance issue.
From what I could read create one handler and send then a different message for different operation could be a solution : handler.sendEmptyMessage(msg)
Basically in my code I click on one button which should trigger my 3 animations through a new Handler here
Solution one (S1) onClick button listener :
Handler h = new Handler() {
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == 1) {
postDelayed(rColumnOne, mSpeedc1);
} else if (msg.what == 2) {
postDelayed( rColumnTwo, mSpeedc1);
} else if (msg.what == 3) {
postDelayed( rColumnThree, mSpeedc1);
}
}
};
h.sendEmptyMessage(1);
h.sendEmptyMessage(2);
h.sendEmptyMessage(3);
Solution two (S2) onClick button listener :
Handler handler = new Handler();
handler.postDelayed( rColumnOne, mSpeedc1);
handler.postDelayed( rColumnTwo, mSpeedc2);
handler.postDelayed( rColumnThree, mSpeedc3);
The S1 & S2 are working both of my animations are triggered. But it's seems to be a bit slow sometimes. Most of the time it's okay but sometimes it's not smooth or not all the animations are triggered.
It could be maybe because I don't destroy the runnable/handler at the end but not sure if it's needed in that case. What would be the best practice in that case ? Is there a solution better than the other ?
I'm a little confused about something. Basically, I'm spawning a thread, and in addition I want to run a message loop in that thread. I'm basically doing the following:
This is straight out of the Android Looper class API documentation. However, my application always gets stuck at Looper.loop() and never returns from it. My current work around for this, is to just create a handler in the main thread (or UI thread) and send messages to that thread instead. However, for the sake of cleanliness and to just make the flow of my application make sense, I'd much rather send my messages to the thread I'm creating.
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
// The rest of the code below is a control loop
}
}
Any thoughts on what might cause Looper.loop() to never return?
Looper.loop creates an infinite loop and only stops when you call quit
http://developer.android.com/reference/android/os/Looper.html#loop()
This may work
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
while(true){
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
}
// The rest of the code below is a control loop
}
}
Can I use one handler in my Activity for all runnables or should I have multiple instances of Handler, each for one runnable?
You can use only one handler and to specify from where your are coming use different message.
handler.sendEmptyMessage(messagevalue); //use this to send message from different place
Now handle message
private Handler handler=new Handler(){
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//specify msg value
if(msg.what==10){
//do this
}else if(msg.what==20){
// do this
}else{
//so on....
}
}
};
I would say, that you should have one handler per thread (not per runnable), unless you do not need completely different behavior for different kinds of runnables.
Which is the better way to use a handler. Any advantages. All examples I have come across seem to give the inline version.
Using implements Handler.Callback in the class and implementing interface method.
or
Using inline code version
private Handler mHandler = new Handler(){ ....};
The common term or these inline class definitions is Anonymous Classes.
You can read more about the discussion on these in Java/Android: anonymous local classes vs named classes
Essentially the main differences are readbility, speed of coding, re-use and scope.
From a resource point of view the anonymous class creation may cause an overhead in the garbage collector as discussed in Avoid Creating Unnecessary Objects. I am not certain on the exact details of anonymous class creation, however, it is logical that implementing the interface on the class is more efficient.
#WilliamTMallard has provided an example of what NOT to do. In his example, a long and syntacticly complex handler should be implementented on the class rather than anonymous handler because it is harder to read and edit when defined inline.
http://developer.android.com/reference/android/os/Handler.html
package : android.os
public class
Handler
extends Object
A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue. Each Handler instance is associated with a single thread and that thread's message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it -- from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.
There are two main uses for a Handler:
to schedule messages and runnables to be executed as some point
in the future; and
to enqueue an action to be performed on a different thread than
your own.
Exmaple 1
use handler in app splash page.
if (!isFirstIn) {
mHandler.sendEmptyMessageDelayed(GO_HOME, SPLASH_DELAY_MILLIS);
} else {
mHandler.sendEmptyMessageDelayed(GO_GUIDE, SPLASH_DELAY_MILLIS);
}
/**************************************************************************************
*1. Handler
*/
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
if(isAuto){
switch (msg.what) {
case GO_HOME:
goHome();
break;
case GO_GUIDE:
goGuide();
break;
}
}
super.handleMessage(msg);
}
};
private void goHome() {
Intent intent = new Intent(SplashActivity.this, MainAct.class);
SplashActivity.this.startActivity(intent);
SplashActivity.this.finish();
}
private void goGuide() {
Intent intent = new Intent(SplashActivity.this, GuideActivity.class);
SplashActivity.this.startActivity(intent);
SplashActivity.this.finish();
}
Example 2
use Handler request network in child thread if the request work may takes time.
new Thread(new Runnable(){
#Override
public void run() {
String versionPath = Parameters.getCheckVersionPath();
String result = RequestHelper.doGet(versionPath, null);
Message msg = new Message();
Bundle data = new Bundle();
data.putString("result",result);
msg.setData(data);
handler1.sendMessage(msg);
}
}).start();
handler1 = new Handler(){
#Override
public void handleMessage(Message msg) {
String result = msg.getData().getString("result");
JSONObject obj;
try {
obj = new JSONObject(result);
Map<String, String> versionInfo = Helper.getSoftwareVersion(obj);
if (versionInfo != null) {
newVersion = versionInfo.get("version");
updateUrl = versionInfo.get("url");
}
} catch (JSONException e) {
Log.w("net work error!", e);
}
}
};
Example 3
use Handler and Timer to update progress bar.
logobar = (ImageView) findViewById(R.id.splash_bar);//progress bar.
logobarClipe = (ClipDrawable) logobar.getBackground();
timer = new Timer();
timer.schedule(new TimerTask() {
public void run() {
updateLogoBarHandler.sendEmptyMessage(0);
}}, 0, rate);
/**************************************************************************************
*2. Handler
*/
//update progress bar.
private Handler updateLogoBarHandler = new Handler() {
public void handleMessage(Message msg) {
if(logobarClipe.getLevel() < 10000){
//1.update image.
logobarClipe.setLevel(logobarClipe.getLevel() + rate*2);
//2.update text.
float percent = logobarClipe.getLevel() /100;
String percentTxtVerbose = String.valueOf(percent);
String percentTxt = percentTxtVerbose.substring(0, percentTxtVerbose.indexOf('.')) + "%";
bartxt.setText(percentTxt);
}else{
timer.cancel();
}
super.handleMessage(msg);
}
};
This really isn't an answer to the above question because I don't know what "the best way" is, and it likely depends on what you're doing. However, I'll explain what I'm doing and why.
I'm writing an app that serves as a remote controller. There are several activities that will interact with the controlled device, and different things need to happen based on the result of the command and the activity it came from. Two things I didn't like about handlers are A) that they end up being a sort of "kitchen sink" construct, implementing functionality from different sources, and B) that they separated an action (the send of the command in my case) from the processing of the result of that action. However, using an anonymous (right term? I'm such a noob.) handler as a parameter allows me to keep the logic together. Here's the pseudocode for my approach:
command = "Wake up!";
mDeviceInterface.write(command, new Handler() {
#Override
public void handleMessage(Message msg) {
switch(msg.what) {
case DeviceInterface.MESSAGE_TIMEOUT: // Process the timeout.
announce("Device not responding.");
break;
case DeviceInterface.MESSAGE_READ: // Process the response.
byte[] readBuf = (byte[]) msg.obj;
if (readBuf[0] == 0x05) {
// Success, update device status.
} else {
announce("Error!");
break;
}
}
}
});
(Always remember, this is probably worth exactly what you've paid for it. ;) )
There is a danger in using anonymous classes in Android. As described in this blog post -
In Java, non-static inner and anonymous classes hold an implicit
reference to their outer class.
And here comes an opportunity for a leak.
So, the short answer would be: implement the interface methods or use static inner classes (which don't hold an outer class reference).
For instance, a leak-safe Handler could look like this:
private static class ChangeTextHandler extends Handler {
private final WeakReference activity;
public ChangeTextHandler(MainActivity activity) {
this.activity = new WeakReference<>(activity);
}
#Override
public void handleMessage(Message msg) {
MainActivity activity = this.activity.get();
if (activity == null) {
Log.e(TAG, "Activity is null ChangeTextHandler.handleMessage()!");
return;
}
final String text = (String) msg.getData().get(BUNDLE_KEY);
if (!TextUtils.isEmpty(text)) {
switch (msg.what) {
// do something
}
}
}
}
I made a blog post around usage of Handlers, so might be worth checking as well :)
I have used a lot of asynctask class in my application. Is it possible to write common class and update the user interface value?
As long as Java has no closures, I don't think this makes a lot of sense.
If you are always doing the same task and only want to modify different UI elements, you can go and pass them in a constructor and then later modify them in onPostExecute().
Instead of using async tasks you can post messages to a common handler to handle UI messages
Common UI handler
private Handler messageHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch(msg.what) {
//handle update
//.....
}
}
};
Thread to post the message
Thread t = new Thread() {
public void run() {
while (true) {
mResults = doSomethingExpensive();
//Send update to the main thread
messageHandler.sendMessage(Message.obtain(messageHandler, mResults));
}
}
};
t.start();
}