Android Anrs From Code Running In A Handler?
Solution 1:
A Handler
will execute code / handle messages per default (any constructor without Looper
e.g. new Handler()
) in the current thread. That is in almost every case the main thread. If you want it to execute in a different thread you have to tell it which Looper
thread it should use.
Android has a utility class called HandlerThread
that creates a Thread
with a Looper
.
Short example:
publicclassMyActivityextendsActivity {
private Handler mHandler;
@OverrideprotectedvoidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
HandlerThreadhandlerThread=newHandlerThread("background-handler");
handlerThread.start();
Looperlooper= handlerThread.getLooper();
mHandler = newHandler(looper);
mHandler.post(newRunnable() {
publicvoidrun() {
// code executed in handlerThread
}
});
}
@OverrideprotectedvoidonDestroy() {
super.onDestroy();
// stops the HandlerThread
mHandler.getLooper().quit();
}
}
In case your task needs only a some information and does not need to report back, I'd go with an IntentService
. Those don't go mad if your Activity-lifecycle recreates the Activity.
You would create a small Service
in it's own file
publicclassSaveServiceextendsIntentService {
publicSaveService() {
super("SaveService");
}
@OverrideprotectedvoidonHandleIntent(Intent intent) {
if ("com.example.action.SAVE".equals(intent.getAction())) {
Stringplayer= intent.getStringExtra("com.example.player");
intscore= intent.getIntExtra("com.example.score", -1);
magicHttpSave(player, score); // assuming there is an implementation here
}
}
}
Add it to the AndroidManifest.xml
<application....
<serviceandroid:name=".SaveService" /></application>
And in your code start it with
Intent intent = newIntent(this/* context */, SaveService.class);
intent.setAction("com.example.action.SAVE");
intent.putExtra("com.example.player", "John123");
intent.putExtra("com.example.score", 5123);
startService(intent);
IntentService#onHandleIntent()
runs on a background thread already so you don't have to bother about that.
Solution 2:
Your Handler runs on the main thread. That is what causes ANR. Even if you create it in the Application, by default (no parameters given to Handler) will be created on the main thread. You have to create a Looper, with its own Thread. See here.
A Handler initialized with your own Looper, that is a viable option to solve ANR...
A more simple alternative solution can be, if you place your async network operation into an AsyncTask. A simple approach is to place the AsyncTask into your Activity. A somewhat more complex could be to create a Service (holder for non-ui related functionality), that does the communication, and cleans itself from memory, once the communication is over...
I'd use AsyncTask and place it into the Activity / fire it up from the Activity...
Finally, HERE you can find a nice tutorial on threads in android.
Post a Comment for "Android Anrs From Code Running In A Handler?"