J'ai un problème très étrange. J'ai un AsyncTask
qui semble bloquer le fil de l'interface utilisateur lorsque je fais tourner le téléphone. Tout d'abord, permettez-moi de dire que je suis à l'aise avec mon Activity
étant détruit et recréé à la rotation. J'enregistre le AsyncTask
dans onRetainNonConfigurationInstance()
, détachez l'activité de celui-ci dans onDestroy()
, et rattachez-le à onCreate()
en utilisant getLastNonConfigurationInstance()
.Android AsyncTask bloque l'interface utilisateur lors du changement d'orientation
Tout va bien, tant que le AsyncTask
ne fait pas de gros travaux. Par exemple, pour déboguer mon problème, j'ai cela, et il fonctionne exactement comme prévu sans blocage de l'interface utilisateur:
@Override
protected Boolean doInBackground(Void... params) {
boolean success = false;
final DbAdapter dbAdapter = dbService.getAdapter();
try {
// pretend to do some complicated work
Thread.sleep(20000);
success = true;
} catch (Exception e) {
e.printStackTrace();
}
return success;
}
Cependant, si je change pour faire un travail réel dans l'arrière-plan, puis-je obtenir un très long délai entre onPause()
étant appelé pour démarrer la rotation, et onResume()
étant appelé plus tard dans la nouvelle orientation. Ce délai est dans les dizaines de secondes, période pendant laquelle l'interface utilisateur est dans un état incohérent (ancienne mise en page recadrée dans la nouvelle orientation) et il semble que la rotation bloque sur le AsyncTask
. Le seul changement est les deux lignes à l'intérieur du bloc try:
@Override
protected Boolean doInBackground(Void... params) {
boolean success = false;
final DbAdapter dbAdapter = dbService.getAdapter();
try {
// actually do some complicated work
XmlParser parser = new XmlParser(context, dbAdapter);
success = parser.parse(source);
} catch (Exception e) {
e.printStackTrace();
}
return success;
}
Le context
est un contexte d'application globale adoptée pour le constructeur de AsyncTask
, donc je ne pense pas que je retiens accidentellement une référence à la sortant Activity
.
Quoi d'autre pourrait mal se passer?
Merci de m'indiquer dans la bonne direction. C'est la contention de base de données; l'opération de base de données à exécution longue est enveloppée dans une transaction. Si je désactive la transaction, cela fonctionne bien (mais prend 10 fois plus longtemps). Fait intéressant, la contention n'est pas dans l'activité visible; mon activité est l'une de plusieurs dans un Tabhost, et c'est l'une des autres activités (non visible au moment de la rotation) qui attend le déblocage de la base de données. –
En ce qui concerne votre suggestion IntentService ... je crois comprendre qu'il est plus difficile de communiquer les résultats à l'interface utilisateur, par exemple pour fermer une boîte de dialogue de progression. Pouvez-vous me donner une bonne explication de pourquoi un IntentService peut être meilleur qu'un AsyncTask? –
@Graham Borland: Dans certaines circonstances, il ne peut pas être mieux que 'IntentService'. Vous n'avez pas besoin de mettre à jour une interface utilisateur dans votre question. Gardez à l'esprit que même si vous fuyez le 'AsyncTask' lorsque l'utilisateur appuie sur BACK, le travail en arrière-plan peut ne pas être terminé, car Android peut terminer le processus avant que vous ayez terminé, car il peut penser qu'il n'y a rien d'autre pour justifier processus autour.C'est ce que vous offre IntentService: un conteneur pour les longues actions en arrière-plan qui peuvent survivre à l'activité en cours et qui permet à Android de savoir que quelque chose est toujours là. – CommonsWare