2011-03-09 4 views
1

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?

Répondre

1

Il est possible que votre activité essaie également d'utiliser dbAdapter et que vous ayez une synchronisation correcte en cours pour empêcher deux threads d'utiliser dbAdapter en même temps.

Votre activité essaie peut-être de charger des éléments du système de fichiers sur le thread d'application principal, et vos opérations de base de données causent trop de conflits. Sur le matériel, YAFFS2 est effectivement un seul thread pour les opérations d'E/S.

Vous pouvez utiliser Traceview pour essayer d'obtenir plus d'informations sur ce qui prend votre temps, et vous pouvez utiliser StrictMode sur Android 2.2 et supérieur pour voir où votre activité pourrait essayer de faire des E/S de fichiers sur l'application principale fil.

En outre, si votre AsyncTask est de convertir XML dans les entrées de la base de données, peut-être cela est une meilleure utilisation d'un IntentService plutôt que d'un AsyncTask.

+0

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. –

+0

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? –

+0

@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

Questions connexes