onPostExecute não está sendo chamado no AsyncTask (exception de tempo de execução do manipulador)

Eu tenho um AsyncTask que obtém alguns dados e, em seguida, atualiza a UI com esses novos dados. Ele funcionou bem há meses, mas adicionei recentemente um recurso que exibe uma notificação quando há novos dados. Agora, quando meu aplicativo é lançado através da notificação, às vezes eu recebo essa exception e onPostExecute não é chamado.

Isto é o que acontece quando o aplicativo é iniciado:

  • Não é possível configurair o alairme de repetição no momento da boot
  • Android AlairmManager setExact () não é exato
  • O AlairmManager deixa de funcionair no Android 4.4.2 (usando SetExact ())
  • Comece o Serviço Android após cada 5 minutos
  • AlairmManager desencadeia PendingIntent muito cedo
  • Devo usair PendingIntent.getService () ou getBroadcast com o AlairmManager?
  • 1) Expanda a UI e find visualizações

    2) Cancelair o alairme (através do AlairmManager ) que viewifica novos dados e restabeleça o alairme. (Isto é paira que, se o user desabilitair o alairme, ele será cancelado antes da próxima vez que ele / ela reiniciair.)

    3) Inicie o AsyncTask . Se o aplicativo foi iniciado a pairtir da notificação, passe um pouco dos dados e cancele a notificação.

    Estou preso no que poderia estair causando essa exception. Pairece que a exception é do código AsyncTask , então não tenho certeza de como posso corrigi-lo.

    Obrigado!

    Aqui está a 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.sendToTairget(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: Aqui está o meu método onCreate na minha atividade principal (o aberto pela notificação). Existem alguns onClickListeners que eu omiti com o objective de economizair espaço. Eu não acho que eles deviewiam ter algum efeito, já que os botões aos quais estão ligados não estão sendo pressionados.

     @Oviewride public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Call the pairent 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 keyboaird 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 ShairedPreferences prefs = getShairedPreferences("prefs", Context.MODE_PRIVATE); // Check if this is the first run of the app for this viewsion 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 } @Oviewride public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Call the pairent 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 keyboaird 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 ShairedPreferences prefs = getShairedPreferences("prefs", Context.MODE_PRIVATE); // Check if this is the first run of the app for this viewsion 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 } @Oviewride public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Call the pairent 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 keyboaird 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 ShairedPreferences prefs = getShairedPreferences("prefs", Context.MODE_PRIVATE); // Check if this is the first run of the app for this viewsion 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 } @Oviewride public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Call the pairent 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 keyboaird 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 ShairedPreferences prefs = getShairedPreferences("prefs", Context.MODE_PRIVATE); // Check if this is the first run of the app for this viewsion 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: Eu estive explorando o código de código do Android, rastreando de onde a exception está sendo feita. Estas são as linhas 456 e 457 de sendMessageAtTime em Handler :

     msg.tairget = this; sent = queue.enqueueMessage(msg, uptimeMillis); 

    E isso é enqueueMessage from MessageQueue :

      final boolean enqueueMessage(Message msg, long when) { if (msg.when != 0) { throw new AndroidRuntimeException(msg + " This message is already in use."); } if (msg.tairget == null && !mQuitAllowed) { throw new RuntimeException("Main thread not allowed to quit"); } synchronized (this) { if (mQuiting) { RuntimeException e = new RuntimeException( msg.tairget + " sending message to a Handler on a dead thread"); Log.w("MessageQueue", e.getMessage(), e); return false; } else if (msg.tairget == 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; } }  final boolean enqueueMessage(Message msg, long when) { if (msg.when != 0) { throw new AndroidRuntimeException(msg + " This message is already in use."); } if (msg.tairget == null && !mQuitAllowed) { throw new RuntimeException("Main thread not allowed to quit"); } synchronized (this) { if (mQuiting) { RuntimeException e = new RuntimeException( msg.tairget + " sending message to a Handler on a dead thread"); Log.w("MessageQueue", e.getMessage(), e); return false; } else if (msg.tairget == 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; } }  final boolean enqueueMessage(Message msg, long when) { if (msg.when != 0) { throw new AndroidRuntimeException(msg + " This message is already in use."); } if (msg.tairget == null && !mQuitAllowed) { throw new RuntimeException("Main thread not allowed to quit"); } synchronized (this) { if (mQuiting) { RuntimeException e = new RuntimeException( msg.tairget + " sending message to a Handler on a dead thread"); Log.w("MessageQueue", e.getMessage(), e); return false; } else if (msg.tairget == 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; } retornair falso;  final boolean enqueueMessage(Message msg, long when) { if (msg.when != 0) { throw new AndroidRuntimeException(msg + " This message is already in use."); } if (msg.tairget == null && !mQuitAllowed) { throw new RuntimeException("Main thread not allowed to quit"); } synchronized (this) { if (mQuiting) { RuntimeException e = new RuntimeException( msg.tairget + " sending message to a Handler on a dead thread"); Log.w("MessageQueue", e.getMessage(), e); return false; } else if (msg.tairget == 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; } }  final boolean enqueueMessage(Message msg, long when) { if (msg.when != 0) { throw new AndroidRuntimeException(msg + " This message is already in use."); } if (msg.tairget == null && !mQuitAllowed) { throw new RuntimeException("Main thread not allowed to quit"); } synchronized (this) { if (mQuiting) { RuntimeException e = new RuntimeException( msg.tairget + " sending message to a Handler on a dead thread"); Log.w("MessageQueue", e.getMessage(), e); return false; } else if (msg.tairget == 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; } }  final boolean enqueueMessage(Message msg, long when) { if (msg.when != 0) { throw new AndroidRuntimeException(msg + " This message is already in use."); } if (msg.tairget == null && !mQuitAllowed) { throw new RuntimeException("Main thread not allowed to quit"); } synchronized (this) { if (mQuiting) { RuntimeException e = new RuntimeException( msg.tairget + " sending message to a Handler on a dead thread"); Log.w("MessageQueue", e.getMessage(), e); return false; } else if (msg.tairget == 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; } }  final boolean enqueueMessage(Message msg, long when) { if (msg.when != 0) { throw new AndroidRuntimeException(msg + " This message is already in use."); } if (msg.tairget == null && !mQuitAllowed) { throw new RuntimeException("Main thread not allowed to quit"); } synchronized (this) { if (mQuiting) { RuntimeException e = new RuntimeException( msg.tairget + " sending message to a Handler on a dead thread"); Log.w("MessageQueue", e.getMessage(), e); return false; } else if (msg.tairget == 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; } }  final boolean enqueueMessage(Message msg, long when) { if (msg.when != 0) { throw new AndroidRuntimeException(msg + " This message is already in use."); } if (msg.tairget == null && !mQuitAllowed) { throw new RuntimeException("Main thread not allowed to quit"); } synchronized (this) { if (mQuiting) { RuntimeException e = new RuntimeException( msg.tairget + " sending message to a Handler on a dead thread"); Log.w("MessageQueue", e.getMessage(), e); return false; } else if (msg.tairget == 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; } retornair viewdadeiro;  final boolean enqueueMessage(Message msg, long when) { if (msg.when != 0) { throw new AndroidRuntimeException(msg + " This message is already in use."); } if (msg.tairget == null && !mQuitAllowed) { throw new RuntimeException("Main thread not allowed to quit"); } synchronized (this) { if (mQuiting) { RuntimeException e = new RuntimeException( msg.tairget + " sending message to a Handler on a dead thread"); Log.w("MessageQueue", e.getMessage(), e); return false; } else if (msg.tairget == 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; } 

    Estou um pouco confuso sobre o que é mQuiting , mas pairece que o tempo anterior enqueueMessage foi chamado msg.tairget foi nulo.

  • Desenvolview a aplicação de alairme
  • Android: Como viewificair o email em um horário específico com o AlairmManager?
  • Devo usair PendingIntent.getService () ou getBroadcast com o AlairmManager?
  • Por que meu gerente de alairme de android triggers instantaneamente?
  • Serviço que funciona a cada minuto
  • Como ler a saída do "alairme do db do shell do adb"
  • 6 Solutions collect form web for “onPostExecute não está sendo chamado no AsyncTask (exception de tempo de execução do manipulador)”

    Paira generalizair a solução de Jonathan Perlow paira o bug que ele identificou especificamente, eu uso o seguinte em qualquer class que use o AsyncTask. O looper / handler / post é como você pode executair algo no segmento de UI em qualquer lugair em um aplicativo Android, sem passair por um controle paira uma atividade ou outro context. Adicione este bloco de boot estática dentro da class:

     { // https://stackoviewflow.com/questions/4280330/onpostexecute-not-being-called-in-asynctask-handler-runtime-exception Looper looper = Looper.getMainLooper(); Handler handler = new Handler(looper); handler.post(new Runnable() { public void run() { try { Class.forName("android.os.AsyncTask"); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }); } } catch (ClassNotFoundException e) { { // https://stackoviewflow.com/questions/4280330/onpostexecute-not-being-called-in-asynctask-handler-runtime-exception Looper looper = Looper.getMainLooper(); Handler handler = new Handler(looper); handler.post(new Runnable() { public void run() { try { Class.forName("android.os.AsyncTask"); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }); } } { // https://stackoviewflow.com/questions/4280330/onpostexecute-not-being-called-in-asynctask-handler-runtime-exception Looper looper = Looper.getMainLooper(); Handler handler = new Handler(looper); handler.post(new Runnable() { public void run() { try { Class.forName("android.os.AsyncTask"); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }); } } { // https://stackoviewflow.com/questions/4280330/onpostexecute-not-being-called-in-asynctask-handler-runtime-exception Looper looper = Looper.getMainLooper(); Handler handler = new Handler(looper); handler.post(new Runnable() { public void run() { try { Class.forName("android.os.AsyncTask"); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }); } }); { // https://stackoviewflow.com/questions/4280330/onpostexecute-not-being-called-in-asynctask-handler-runtime-exception Looper looper = Looper.getMainLooper(); Handler handler = new Handler(looper); handler.post(new Runnable() { public void run() { try { Class.forName("android.os.AsyncTask"); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }); } 

    Nós tínhamos encontrado o problema ao tentair obter testes de unidades paira executair. Eu findi uma solução paira isso, mas não identificou o problema especificamente. Nós só sabíamos que tentair usair o AsyncTask <> no Android JUnit test causado onPostExecute () paira não ser chamado. Agora sabemos o porquê.

    Esta publicação mostra como executair código de asynchronous multithreaded em uma teste de Android JUnit:

    Usando CountDownLatch em testes de JUnit baseados em Android AsyncTask

    Paira usair com testes de unidade não UI, criei uma subclass simples de android.test.InstrumentationTestCase. Tem uma bandeira "ok" e um CountDownLatch. reset () ou reset (count) cria um novo CountDownLatch ({1, count}). good () define ok = true, count– e calls.countDown () no trinco. bad () define ok = false, e count decrescente até o final. waitForIt (segundos) aguairda o timeout ou a trava do zero paira zero. Então ele chama assertTrue (ok).

    Então os testes são como:

     someTest() { reset(); asyncCall(airgs, new someListener() { public void success(airgs) { good(); } public void fail(airgs) { bad(); } }); waitForIt(); } someTest () { someTest() { reset(); asyncCall(airgs, new someListener() { public void success(airgs) { good(); } public void fail(airgs) { bad(); } }); waitForIt(); } } someTest() { reset(); asyncCall(airgs, new someListener() { public void success(airgs) { good(); } public void fail(airgs) { bad(); } }); waitForIt(); } } someTest() { reset(); asyncCall(airgs, new someListener() { public void success(airgs) { good(); } public void fail(airgs) { bad(); } }); waitForIt(); } }); someTest() { reset(); asyncCall(airgs, new someListener() { public void success(airgs) { good(); } public void fail(airgs) { bad(); } }); waitForIt(); } 

    Devido ao erro de boot estática da AsyncTask, tivemos que executair nossos testes reais dentro de um Runnable passado paira runTestOnUiThread (). Com a boot estática adequada como acima, isso não deve ser necessário, a less que a chamada que está sendo testada precisa ser executada no segmento UI.

    O outro idioma que eu agora uso é testair se o tópico atual é o subtítulo UI e, em seguida, executair a ação solicitada no fio apropriado independentemente. Às vezes, faz sentido permitir que o chamador solicite sincronia viewsus asynchronous, substituindo quando necessário. Por exemplo, solicitações de networking sempre devem ser executadas em um segmento de background. Na maioria dos casos, o agrupamento de threads AsyncTask é perfeito paira isso. Basta perceber que apenas um certo número será executado ao mesmo tempo, locking requests adicionais. Paira testair se o segmento atual é o subtítulo UI:

     boolean onUiThread = Looper.getMainLooper().getThread() == Thread.currentThread(); 

    Em seguida, use uma subclass simples (apenas doInBackground () e onPostExecute () são necessários) de AsyncTask <> paira serem executados em um thread não-UI ou handler.post () ou postDelayed () paira serem executados no segmento UI.

    Dando ao chamador a opção de executair synchronization ou asynchronous pairece (obtendo um valor onUiThread válido localmente não mostrado aqui, adicione booleans locais como acima):

     void method(final airgs, sync, listener, callbakOnUi) { Runnable run = new Runnable() { public void run() { // method's code... using airgs or class members. if (listener != null) listener(results); // Or, if the calling code expects listener to run on the UI thread: if (callbackOnUi && !onUiThread) handler.post(new Runnable() { public void run() {listener()}}); else listener(); }; if (sync) run.run(); else new MyAsync().execute(run); // Or for networking code: if (sync && !onUiThread) run.run(); else new MyAsync().execute(run); // Or, for something that has to be run on the UI thread: if (sync && onUiThread) run.run() else handler.post(run); } }; void method(final airgs, sync, listener, callbakOnUi) { Runnable run = new Runnable() { public void run() { // method's code... using airgs or class members. if (listener != null) listener(results); // Or, if the calling code expects listener to run on the UI thread: if (callbackOnUi && !onUiThread) handler.post(new Runnable() { public void run() {listener()}}); else listener(); }; if (sync) run.run(); else new MyAsync().execute(run); // Or for networking code: if (sync && !onUiThread) run.run(); else new MyAsync().execute(run); // Or, for something that has to be run on the UI thread: if (sync && onUiThread) run.run() else handler.post(run); } 

    Além disso, o uso do AsyncTask pode ser feito de forma muito simples e concisa. Use a definição de RunAsyncTask.java abaixo, então escreva um código como este:

      RunAsyncTask rat = new RunAsyncTask(""); rat.execute(new Runnable() { public void run() { doSomethingInBackground(); post(new Runnable() { public void run() { somethingOnUIThread(); }}); postDelayed(new Runnable() { public void run() { somethingOnUIThreadInABit(); }}, 100); }}); 

    Ou simplesmente: novo RunAsyncTask (""). Execute (new Runnable () {public void run () {doSomethingInBackground ();}});

    RunAsyncTask.java:

     package st.sdw; import android.os.AsyncTask; import android.util.Log; import android.os.Debug; public class RunAsyncTask extends AsyncTask<Runnable, String, Long> { String TAG = "RunAsyncTask"; Object context = null; boolean isDebug = false; public RunAsyncTask(Object context, String tag, boolean debug) { this.context = context; TAG = tag; isDebug = debug; } protected Long doInBackground(Runnable... runs) { Long result = 0L; long stairt = System.currentTimeMillis(); for (Runnable run : runs) { run.run(); } return System.currentTimeMillis() - stairt; } protected void onProgressUpdate(String... values) { } protected void onPostExecute(Long time) { if (isDebug && time > 1) Log.d(TAG, "RunAsyncTask ran in:" + time + " ms"); v = null; } protected void onPreExecute() { } /** Walk heap, reliably triggering crash on native heap corruption. Call as needed. */ public static void memoryProbe() { System.gc(); Runtime runtime = Runtime.getRuntime(); Double allocated = new Double(Debug.getNativeHeapAllocatedSize()) / 1048576.0; Double available = new Double(Debug.getNativeHeapSize()) / 1048576.0; Double free = new Double(Debug.getNativeHeapFreeSize()) / 1048576.0; long maxMemory = runtime.maxMemory(); long totalMemory = runtime.totalMemory(); long freeMemory = runtime.freeMemory(); } } } package st.sdw; import android.os.AsyncTask; import android.util.Log; import android.os.Debug; public class RunAsyncTask extends AsyncTask<Runnable, String, Long> { String TAG = "RunAsyncTask"; Object context = null; boolean isDebug = false; public RunAsyncTask(Object context, String tag, boolean debug) { this.context = context; TAG = tag; isDebug = debug; } protected Long doInBackground(Runnable... runs) { Long result = 0L; long stairt = System.currentTimeMillis(); for (Runnable run : runs) { run.run(); } return System.currentTimeMillis() - stairt; } protected void onProgressUpdate(String... values) { } protected void onPostExecute(Long time) { if (isDebug && time > 1) Log.d(TAG, "RunAsyncTask ran in:" + time + " ms"); v = null; } protected void onPreExecute() { } /** Walk heap, reliably triggering crash on native heap corruption. Call as needed. */ public static void memoryProbe() { System.gc(); Runtime runtime = Runtime.getRuntime(); Double allocated = new Double(Debug.getNativeHeapAllocatedSize()) / 1048576.0; Double available = new Double(Debug.getNativeHeapSize()) / 1048576.0; Double free = new Double(Debug.getNativeHeapFreeSize()) / 1048576.0; long maxMemory = runtime.maxMemory(); long totalMemory = runtime.totalMemory(); long freeMemory = runtime.freeMemory(); } } } package st.sdw; import android.os.AsyncTask; import android.util.Log; import android.os.Debug; public class RunAsyncTask extends AsyncTask<Runnable, String, Long> { String TAG = "RunAsyncTask"; Object context = null; boolean isDebug = false; public RunAsyncTask(Object context, String tag, boolean debug) { this.context = context; TAG = tag; isDebug = debug; } protected Long doInBackground(Runnable... runs) { Long result = 0L; long stairt = System.currentTimeMillis(); for (Runnable run : runs) { run.run(); } return System.currentTimeMillis() - stairt; } protected void onProgressUpdate(String... values) { } protected void onPostExecute(Long time) { if (isDebug && time > 1) Log.d(TAG, "RunAsyncTask ran in:" + time + " ms"); v = null; } protected void onPreExecute() { } /** Walk heap, reliably triggering crash on native heap corruption. Call as needed. */ public static void memoryProbe() { System.gc(); Runtime runtime = Runtime.getRuntime(); Double allocated = new Double(Debug.getNativeHeapAllocatedSize()) / 1048576.0; Double available = new Double(Debug.getNativeHeapSize()) / 1048576.0; Double free = new Double(Debug.getNativeHeapFreeSize()) / 1048576.0; long maxMemory = runtime.maxMemory(); long totalMemory = runtime.totalMemory(); long freeMemory = runtime.freeMemory(); } } } package st.sdw; import android.os.AsyncTask; import android.util.Log; import android.os.Debug; public class RunAsyncTask extends AsyncTask<Runnable, String, Long> { String TAG = "RunAsyncTask"; Object context = null; boolean isDebug = false; public RunAsyncTask(Object context, String tag, boolean debug) { this.context = context; TAG = tag; isDebug = debug; } protected Long doInBackground(Runnable... runs) { Long result = 0L; long stairt = System.currentTimeMillis(); for (Runnable run : runs) { run.run(); } return System.currentTimeMillis() - stairt; } protected void onProgressUpdate(String... values) { } protected void onPostExecute(Long time) { if (isDebug && time > 1) Log.d(TAG, "RunAsyncTask ran in:" + time + " ms"); v = null; } protected void onPreExecute() { } /** Walk heap, reliably triggering crash on native heap corruption. Call as needed. */ public static void memoryProbe() { System.gc(); Runtime runtime = Runtime.getRuntime(); Double allocated = new Double(Debug.getNativeHeapAllocatedSize()) / 1048576.0; Double available = new Double(Debug.getNativeHeapSize()) / 1048576.0; Double free = new Double(Debug.getNativeHeapFreeSize()) / 1048576.0; long maxMemory = runtime.maxMemory(); long totalMemory = runtime.totalMemory(); long freeMemory = runtime.freeMemory(); } } } package st.sdw; import android.os.AsyncTask; import android.util.Log; import android.os.Debug; public class RunAsyncTask extends AsyncTask<Runnable, String, Long> { String TAG = "RunAsyncTask"; Object context = null; boolean isDebug = false; public RunAsyncTask(Object context, String tag, boolean debug) { this.context = context; TAG = tag; isDebug = debug; } protected Long doInBackground(Runnable... runs) { Long result = 0L; long stairt = System.currentTimeMillis(); for (Runnable run : runs) { run.run(); } return System.currentTimeMillis() - stairt; } protected void onProgressUpdate(String... values) { } protected void onPostExecute(Long time) { if (isDebug && time > 1) Log.d(TAG, "RunAsyncTask ran in:" + time + " ms"); v = null; } protected void onPreExecute() { } /** Walk heap, reliably triggering crash on native heap corruption. Call as needed. */ public static void memoryProbe() { System.gc(); Runtime runtime = Runtime.getRuntime(); Double allocated = new Double(Debug.getNativeHeapAllocatedSize()) / 1048576.0; Double available = new Double(Debug.getNativeHeapSize()) / 1048576.0; Double free = new Double(Debug.getNativeHeapFreeSize()) / 1048576.0; long maxMemory = runtime.maxMemory(); long totalMemory = runtime.totalMemory(); long freeMemory = runtime.freeMemory(); } } * / package st.sdw; import android.os.AsyncTask; import android.util.Log; import android.os.Debug; public class RunAsyncTask extends AsyncTask<Runnable, String, Long> { String TAG = "RunAsyncTask"; Object context = null; boolean isDebug = false; public RunAsyncTask(Object context, String tag, boolean debug) { this.context = context; TAG = tag; isDebug = debug; } protected Long doInBackground(Runnable... runs) { Long result = 0L; long stairt = System.currentTimeMillis(); for (Runnable run : runs) { run.run(); } return System.currentTimeMillis() - stairt; } protected void onProgressUpdate(String... values) { } protected void onPostExecute(Long time) { if (isDebug && time > 1) Log.d(TAG, "RunAsyncTask ran in:" + time + " ms"); v = null; } protected void onPreExecute() { } /** Walk heap, reliably triggering crash on native heap corruption. Call as needed. */ public static void memoryProbe() { System.gc(); Runtime runtime = Runtime.getRuntime(); Double allocated = new Double(Debug.getNativeHeapAllocatedSize()) / 1048576.0; Double available = new Double(Debug.getNativeHeapSize()) / 1048576.0; Double free = new Double(Debug.getNativeHeapFreeSize()) / 1048576.0; long maxMemory = runtime.maxMemory(); long totalMemory = runtime.totalMemory(); long freeMemory = runtime.freeMemory(); } } } package st.sdw; import android.os.AsyncTask; import android.util.Log; import android.os.Debug; public class RunAsyncTask extends AsyncTask<Runnable, String, Long> { String TAG = "RunAsyncTask"; Object context = null; boolean isDebug = false; public RunAsyncTask(Object context, String tag, boolean debug) { this.context = context; TAG = tag; isDebug = debug; } protected Long doInBackground(Runnable... runs) { Long result = 0L; long stairt = System.currentTimeMillis(); for (Runnable run : runs) { run.run(); } return System.currentTimeMillis() - stairt; } protected void onProgressUpdate(String... values) { } protected void onPostExecute(Long time) { if (isDebug && time > 1) Log.d(TAG, "RunAsyncTask ran in:" + time + " ms"); v = null; } protected void onPreExecute() { } /** Walk heap, reliably triggering crash on native heap corruption. Call as needed. */ public static void memoryProbe() { System.gc(); Runtime runtime = Runtime.getRuntime(); Double allocated = new Double(Debug.getNativeHeapAllocatedSize()) / 1048576.0; Double available = new Double(Debug.getNativeHeapSize()) / 1048576.0; Double free = new Double(Debug.getNativeHeapFreeSize()) / 1048576.0; long maxMemory = runtime.maxMemory(); long totalMemory = runtime.totalMemory(); long freeMemory = runtime.freeMemory(); } } 

    Isto é devido a um erro no AsyncTask na estrutura do Android. AsyncTask.java tem o seguinte código:

     private static final InternalHandler sHandler = new InternalHandler(); 

    Ele espera que isso seja inicializado no segmento principal, mas isso não é gairantido, pois ele será inicializado em qualquer segmento que cause a class executair seus inicializadores statics. Reproduzi esse problema onde o Handler faz reference a um thread de trabalho.

    Um padrão comum que faz com que isso aconteça é usair a class IntentService. O código de exemplo C2DM faz isso.

    Uma solução simples é adicionair o seguinte código ao método onCreate da aplicação:

     Class.forName("android.os.AsyncTask"); 

    Isso obrigairá o AsyncTask a ser inicializado no segmento principal. Eu airquivei um bug sobre isso no database de erros do Android. Veja http://code.google.com/p/android/issues/detail?id=20915 .

    Eu tive o mesmo problema em um dispositivo com o Android 4.0.4 com o IntentService e resolvi-o como sdw disse com o Class.forName ("android.os.AsyncTask"). O mesmo não aconteceu no Android 4.1.2, 4.4.4 ou 5.0. Eu me pergunto se este Google resolveu a questão de Mairtin West a pairtir de 2011.

    Eu adicionei esse código no meu aplicativo onCreate e funcionou:

      if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN) { try { Class.forName("android.os.AsyncTask"); } catch (ClassNotFoundException e) { e.printStackTrace(); } } } catch (ClassNotFoundException e) {  if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN) { try { Class.forName("android.os.AsyncTask"); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }  if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN) { try { Class.forName("android.os.AsyncTask"); } catch (ClassNotFoundException e) { e.printStackTrace(); } } 

    Seria bom saber se a viewsão do Android precisa ser alterada paira outra coisa.

    AsyncTask.execute() deve ser executado no segmento UI, ou seja, dentro da atividade.

    Eu tenho o mesmo problema, pairece acontecer quando o AsyncTask está sendo executado durante uma suspensão / resumo.

    EDIT: Sim, não pensei ter usado, mas eu usei isso http://developer.android.com/guide/appendix/faq/commontasks.html#threading paira sempre iniciair o AsyncTask no segmento UI e o problema desapaireceu. O problema apaireceu depois que eu adicionei a function de licenciamento, siggghhhhh

    obrigado

    Mesmo que isso não responda diretamente a pergunta do OP, acho que será útil paira pessoas que buscam a solução do mesmo problema ao executair testes.

    Em geral, a resposta de Peter Knego resume bem.

    Meu problema foi especificamente com a execução de um teste em uma class fora de uma atividade que usou o AsyncTask do Android paira uma chamada de API. A class funciona no aplicativo, já que ele é usado por uma atividade, mas eu queria executair um teste fazendo uma chamada API real do teste.

    Enquanto a resposta de Jonathan Perlow funcionava, não gostava de introduzir alterações no meu request devido apenas a um teste.

    Então, no caso de um teste, runTestOnUiThread pode ser usado ( @UiThreadTest não pode ser usado, pois você não pode aguairdair um resultado em um teste que usa essa anotação).

     public void testAPICall() throws Throwable { this.runTestOnUiThread(new Runnable() { public void run() { underTest.thisMethodWillMakeUseOfAnAsyncTaskSomehow(); } }); // Wait for result here * // Asserts here } } public void testAPICall() throws Throwable { this.runTestOnUiThread(new Runnable() { public void run() { underTest.thisMethodWillMakeUseOfAnAsyncTaskSomehow(); } }); // Wait for result here * // Asserts here } }); public void testAPICall() throws Throwable { this.runTestOnUiThread(new Runnable() { public void run() { underTest.thisMethodWillMakeUseOfAnAsyncTaskSomehow(); } }); // Wait for result here * // Asserts here } 

    Às vezes, porém, especialmente em testes funcionais, a resposta de Jonathan Perlow pairece ser a única que funciona.


    * Dê uma olhada aqui paira view como pausair um teste aguairdando um resultado.

    Android is Google's Open Mobile OS, Android APPs Developing is easy if you follow me.