onPostExecute n'étant pas appelé dans AsyncTask (exception d'exécution du gestionnaire)
J'ai un AsyncTask
qui extrait des données et ensuite les mises à jour de l'INTERFACE utilisateur avec ces nouvelles données. Il a été fonctionne bien depuis des mois, mais j'ai récemment ajouté une fonctionnalité qui permet d'afficher une notification lorsqu'il y a de nouvelles données. Maintenant, quand mon application est lancée par le biais de la notification, parfois, je reçois cette exception et onPostExecute
n'est pas appelé.
C'est ce qui arrive lorsque l'application est lancée:
1) Développer l'INTERFACE utilisateur et de trouver des points de vue
2) Annuler l'alarme (par AlarmManager
) qui vérifie la présence de nouvelles données et réinitialisation de l'alarme. (C'est ainsi que si l'utilisateur désactive l'alarme il est annulé avant la prochaine fois qu'il/elle redémarre.)
3) Démarrer le AsyncTask
. Si l'application a été lancée à partir de la notification, passer un peu de bits de données, puis annuler la notification.
Je suis coincé sur ce qui pourrait être la cause de cette exception. Il semble que l'exception est de la AsyncTask
code, donc je ne suis pas sûr de savoir comment je peux le résoudre.
Merci!
Ici est l'exception:
I/My App( 501): doInBackground exiting
W/MessageQueue( 501): Handler{442ba140} sending message to a Handler on a dead thread
W/MessageQueue( 501): java.lang.RuntimeException: Handler{442ba140} sending message to a Handler on a dead thread
W/MessageQueue( 501): at android.os.MessageQueue.enqueueMessage(MessageQueue.java:179)
W/MessageQueue( 501): at android.os.Handler.sendMessageAtTime(Handler.java:457)
W/MessageQueue( 501): at android.os.Handler.sendMessageDelayed(Handler.java:430)
W/MessageQueue( 501): at android.os.Handler.sendMessage(Handler.java:367)
W/MessageQueue( 501): at android.os.Message.sendToTarget(Message.java:348)
W/MessageQueue( 501): at android.os.AsyncTask$3.done(AsyncTask.java:214)
W/MessageQueue( 501): at java.util.concurrent.FutureTask$Sync.innerSet(FutureTask.java:252)
W/MessageQueue( 501): at java.util.concurrent.FutureTask.set(FutureTask.java:112)
W/MessageQueue( 501): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:310)
W/MessageQueue( 501): at java.util.concurrent.FutureTask.run(FutureTask.java:137)
W/MessageQueue( 501): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1068)
W/MessageQueue( 501): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:561)
W/MessageQueue( 501): at java.lang.Thread.run(Thread.java:1096)
EDIT: Voici mon onCreate
méthode dans mon activité principale (celle ouverte par la notification). Il y a quelques onClickListeners
que j'ai omis d'économiser de l'espace. Je ne pense pas qu'ils devraient avoir aucun effet, puisque les boutons ils sont attachés ne sont pas pressés.
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); //Call the parent
setContentView(R.layout.main); //Create the UI from the XML file
//Find the UI elements
controls = (SlidingDrawer) findViewById(R.id.drawer); //Contains the
//buttons
//comic = (ImageView) findViewById(R.id.comic); //Displays the comic
subtitle = (TextView) findViewById(R.id.subtitleTxt); //Textbox for the
//subtitle
prevBtn = (Button) findViewById(R.id.prevBtn); //The previous button
nextBtn = (Button) findViewById(R.id.nextBtn); //The next button
randomBtn = (Button) findViewById(R.id.randomBtn); //The random button
fetchBtn = (Button) findViewById(R.id.comicFetchBtn); //The go to specific id button
mostRecentBtn = (Button) findViewById(R.id.mostRecentBtn); //The button to go to the most recent comic
comicNumberEdtTxt = (EditText) findViewById(R.id.comicNumberEdtTxt); //The text box to Zooming image view setup
zoomControl = new DynamicZoomControl();
zoomListener = new LongPressZoomListener(this);
zoomListener.setZoomControl(zoomControl);
zoomComic = (ImageZoomView) findViewById(R.id.zoomComic);
zoomComic.setZoomState(zoomControl.getZoomState());
zoomComic.setImage(BitmapFactory.decodeResource(getResources(), R.drawable.defaultlogo));
zoomComic.setOnTouchListener(zoomListener);
zoomControl.setAspectQuotient(zoomComic.getAspectQuotient());
resetZoomState();
//enter the new id
imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); //Used to hide the soft keyboard
Log.i(LOG_TAG, "beginning loading of first comic");
int notificationComicNumber = getIntent().getIntExtra("comic", -1);
Log.i(LOG_TAG, "comic number from intent: " + notificationComicNumber);
if (notificationComicNumber == -1) {
fetch = new MyFetcher(this, zoomComic, subtitle, controls, comicNumberEdtTxt, imm, zoomControl);
fetch.execute(MyFetcher.LAST_DISPLAYED_COMIC);
} else {
fetch = new MyFetcher(this, zoomComic, subtitle, controls, comicNumberEdtTxt, imm, zoomControl);
fetch.execute(notificationComicNumber);
((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).cancelAll();
}
Log.i(LOG_TAG, "ending loading of new comic");
Log.i(LOG_TAG, "first run checks beginning");
//Get SharedPreferences
prefs = getSharedPreferences("prefs", Context.MODE_PRIVATE);
//Check if this is the first run of the app for this version
if (prefs.getBoolean("firstRun-" + MAJOR_VERSION_NUMBER, true)) {
prefs.edit().putBoolean("firstRun-" + MAJOR_VERSION_NUMBER, false).commit();
firstRunVersionDialog();
}
//Check if this is the first run of the app
if (prefs.getBoolean("firstRun", true)) {
prefs.edit().putBoolean("firstRun", false).commit();
firstRunDialog();
}
Log.i(LOG_TAG, "First run checks done");
//OnClickListener s for the buttons omitted to save space
EDIT 2: j'ai été fouiller dans le code source Android de suivi en bas où l'exception est à venir. C'est les lignes de 456 et 457 de sendMessageAtTime
dans Handler
:
msg.target = this;
sent = queue.enqueueMessage(msg, uptimeMillis);
Et c'est enqueueMessage
de MessageQueue
:
final boolean enqueueMessage(Message msg, long when) {
if (msg.when != 0) {
throw new AndroidRuntimeException(msg
+ " This message is already in use.");
}
if (msg.target == null && !mQuitAllowed) {
throw new RuntimeException("Main thread not allowed to quit");
}
synchronized (this) {
if (mQuiting) {
RuntimeException e = new RuntimeException(
msg.target + " sending message to a Handler on a dead thread");
Log.w("MessageQueue", e.getMessage(), e);
return false;
} else if (msg.target == null) {
mQuiting = true;
}
msg.when = when;
//Log.d("MessageQueue", "Enqueing: " + msg);
Message p = mMessages;
if (p == null || when == 0 || when < p.when) {
msg.next = p;
mMessages = msg;
this.notify();
} else {
Message prev = null;
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
msg.next = prev.next;
prev.next = msg;
this.notify();
}
}
return true;
}
Je suis un peu confus au sujet de ce mQuiting
est, mais il semble que la fois précédente enqueueMessage
a été appelé msg.target
était nulle.
source d'informationauteur Computerish
Vous devez vous connecter pour publier un commentaire.
Cela est dû à un bogue dans AsyncTask dans l'Android cadre. AsyncTask.java a le code suivant:
Il s'attend à être initialisé sur le thread principal, mais qui n'est pas garanti, puisqu'elle sera initialisée sur le fil qui se passe à cause de la classe à exécuter ses initialiseurs statiques. J'ai reproduit cette question lorsque le Gestionnaire de références d'un thread de travail.
Un modèle commun qui cause ce problème est l'utilisation de la classe IntentService. Le C2DM exemple de code fait cela.
Une solution simple est d'ajouter le code suivant à l'application de la méthode onCreate:
Cette force AsyncTask être initialisée dans le thread principal. J'ai déposé un bug sur ce dans l'android bug de la base de données. Voir http://code.google.com/p/android/issues/detail?id=20915.
J'ai eu le même problème sur un appareil avec Android 4.0.4 avec le IntentService et résolu que sdw dit avec la Classe.forName("android.os.AsyncTask"). Le même n'est pas arrivé sur Android 4.1.2, 4.4.4 ou 5.0. Je me demande si ce Google résolu Martin Ouest de la question de l'2011.
J'ai ajouté ce code sur ma Demande onCreate et il a travaillé:
Il serait bon de savoir si la version d'Android besoin d'être changé en quelque chose d'autre.
AsyncTask.execute()
doit être exécutée sur le thread de l'INTERFACE utilisateur, c'est à dire à l'intérieur de l'Activité.J'ai le même problème, il semble se produire lorsque l'AsyncTask est en cours d'exécution lors d'une suspension/reprise.
EDIT:
Ouais, ne pense pas que j'ai eu, mais j'ai utilisé ce http://developer.android.com/guide/appendix/faq/commontasks.html#threading
toujours commencer la AsyncTask sur le thread de l'INTERFACE utilisateur et le problème a disparu.
Le problème est apparu après que j'ai ajouté la fonction d'octroi de licences, siggghhhhh
Grâce
Même si ce n'est pas directement répondre à l'OP, je pense qu'il sera utile pour les personnes à la recherche de la solution du même problème lors de l'exécution des tests.
Dans l'ensemble, Peter Knego réponse résume très bien.
Mon problème a été spécifiquement avec l'exécution d'un test sur une classe en dehors d'une Activité qui fait usage d'Android, est AsyncTask pour un appel d'API. La classe travaille en la demande, car il est utilisé par une Activité, mais je voulais lancer un test en faisant un réel appel d'API de test.
Tout Jonathan Perlow réponse travaillé, je n'ai pas aimé l'introduction de changements à ma demande et uniquement à cause d'un test.
Donc, dans le cas d'un test
runTestOnUiThread
peut être utilisé (@UiThreadTest
ne peut pas être utilisé, car vous ne pouvez pas vous attendre à un résultat à un test qui utilise cette annotation).Parfois, cependant, en particulier dans les tests fonctionnels, Jonathan Perlow la réponse semble être le seul qui fonctionne.
* Jetez un oeil ici pour voir comment mettre en pause un test d'attente d'un résultat.