SETUP:AsyncTask запущен из onPostExecute другого AsyncTask не выполняется должным образом в API 10
У меня есть одноэлементный класс приложения, который имеет метод с именем fetchUpdates()
. Этот метод вызывается классом UpdaterService
(IntentService). fetchUpdates()
метод просто вызывает DownloadDataAsyncTask, который затем вызывает UpdateDbAsyncTask
во время onPostExecute
, если данные были успешно загружены. Оба AsyncTasks находятся в классе приложения (не уверен, что это связано с проблемой).
public synchronized void fetchUpdates() {
String[] mURLs = getURLs();
new DownloadDataAsyncTask().execute(mURLs[0], mURLs[1]);
}
класс DownloadDataAsyncTask
private class DownloadDataAsyncTask extends AsyncTask<String, Void, JSONObject[]> {
@Override
protected synchronized JSONObject[] doInBackground(String... params) {
String urlData = (String) params[0];
String urlId = (String) params[1];
JSONObject[] jSON = new JSONObject[] {
JSONfunctions.getJSONfromURL(urlData),
JSONfunctions.getJSONfromURL(urlId) };
return mJSON;
}
@Override
protected void onPostExecute(JSONObject[] result) {
if (result[0] != null && result[1] != null) {
new UpdateDbAsyncTask().execute(result[0], result[1]);
} else {
displayFailureToast();
}
}
}
класс UpdateDbAsyncTask
private class UpdateDbAsyncTask extends AsyncTask<JSONObject, Void, int[]> {
@Override
protected synchronized int[] doInBackground(JSONObject... params) {
Log.d(TAG, "UpdateDbAsyncTask doInBackground BEGIN");
int[] info = updateDb(params[0], params[1]);
Log.d(TAG, "UpdateDbAsyncTask doInBackground RETURNING RESULT");
return info
}
@Override
protected void onPostExecute(int[] result) {
Log.d(TAG, "UpdateDbAsyncTask onPostExecute BEGIN");
if (result[0] > 0) makeNotification(0);
if (result[1] > 0) makeNotification(1);
}
}
ПРОБЛЕМА:
Все отлично работает в API 16, но исполнение UpdateDbAsyncTask
привалах после doInBackground в API 10. Метод onCancelled (Object) также не называется.
LogCat ВЫХОД
06-22 16:11:51.047: D/dalvikvm(499): VFY: replacing opcode 0x6e at 0x0089
06-22 16:11:51.057: D/dalvikvm(499): VFY: dead code 0x008c-008e in Lcom/daybreak/android/test/MyApplication$UpdateDbAsyncTask;.onPostExecute ([I)V
06-22 16:11:51.087: D/MyApplication(499): UpdateDbAsyncTask doInBackground BEGIN
06-22 16:11:51.187: D/MyApplication(499): UpdateDbAsyncTask doInBackground RETURNING RESULT
06-22 16:11:51.197: W/MessageQueue(499): Handler{40567510} sending message to a Handler on a dead thread
06-22 16:11:51.197: W/MessageQueue(499): java.lang.RuntimeException: Handler{40567510} sending message to a Handler on a dead thread
06-22 16:11:51.197: W/MessageQueue(499): at android.os.MessageQueue.enqueueMessage(MessageQueue.java:196)
06-22 16:11:51.197: W/MessageQueue(499): at android.os.Handler.sendMessageAtTime(Handler.java:457)
06-22 16:11:51.197: W/MessageQueue(499): at android.os.Handler.sendMessageDelayed(Handler.java:430)
06-22 16:11:51.197: W/MessageQueue(499): at android.os.Handler.sendMessage(Handler.java:367)
06-22 16:11:51.197: W/MessageQueue(499): at android.os.Message.sendToTarget(Message.java:349)
06-22 16:11:51.197: W/MessageQueue(499): at android.os.AsyncTask$3.done(AsyncTask.java:214)
06-22 16:11:51.197: W/MessageQueue(499): at java.util.concurrent.FutureTask$Sync.innerSet(FutureTask.java:253)
06-22 16:11:51.197: W/MessageQueue(499): at java.util.concurrent.FutureTask.set(FutureTask.java:113)
06-22 16:11:51.197: W/MessageQueue(499): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:311)
06-22 16:11:51.197: W/MessageQueue(499): at java.util.concurrent.FutureTask.run(FutureTask.java:138)
06-22 16:11:51.197: W/MessageQueue(499): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088)
06-22 16:11:51.197: W/MessageQueue(499): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581)
06-22 16:11:51.197: W/MessageQueue(499): at java.lang.Thread.run(Thread.java:1019)
06-22 16:11:55.717: W/GAV2(499): Thread[Service Reconnect,5,main]: Service unavailable (code=1), using local store.
ДАЛЕЕ ИССЛЕДОВАНИЯ
threading rules для AsyncTask состояния, что:
- Класс AsyncTask должен быть загружен в потоке пользовательского интерфейса. Это делается автоматически с JELLY_BEAN.
- Экземпляр задачи должен быть создан в потоке пользовательского интерфейса.
- execute (Params ...) должен быть вызван в потоке пользовательского интерфейса.
- и т.д ...
В моем понимании (это не так много, только начал программирование) первый UpdateDbAsyncTask
выполнен полностью в обоих API, потому что он не нарушает каких-либо правил пронизывающих. Но второй из них либо нарушает одно из правил потоковой передачи, заставляя его прекратить выполнение после doInBackground, либо это что-то еще полностью вне моего понимания.
Я также нашел кого-то еще с аналогичным issue. И позже он был предложен в вопросе к
просто используя класс AsyncTask для API15 + в мой код во все времена
Но я не совсем уверен, как сделать что либо.
Любая помощь будет высоко оценена. Благодаря!
UPDATE 1
Проблема возникает только тогда, когда я называю класс UpdaterService
IntentService (который вызывает метод fetchUpdates()
в классе Application) от деятельности. Код у меня в MainActivity
ниже:
startService(new Intent(this, UpdaterService.class));
Однако, когда я назвал fetchUpdates()
непосредственно с помощью кода
MyApplication myApp = (MyApplication) getApplication();
myApp.fetchUpdates();
из MainActivity
, все выполнено отлично в API 10.
А также обратите внимание, что также вызывается с использованием класса BroadcastReceiver
, который устанавливается через регулярные интервалы с использованием повторяющегося сигнала тревоги. В этом случае AsyncTasks выполняются как ожидалось ... очень странно.
UPDATE 2
Ответ на Streets Of Boston, кажется, правильный ответ. Но, как ни странно, следующий, кажется, работает так же:
runOnUiThread(new Runnable() {
public void run() {
Intent serviceIntent = new Intent();
serviceIntent.setClass(getApplicationContext(), UpdaterService.class);
startService(serviceIntent);
}
});
Я использовал приведенный выше код, чтобы запустить IntentService
из MainActivity
вместо startService(new Intent(this, UpdaterService.class));
и проблема, кажется, не сохраняются.
http://bon-app-etit.blogspot.in/2013/04/the-dark-side-of-asynctask.html –
Это работает, потому что вы теперь вызываете startService из Activity, а Activity - это так называемый компонент переднего плана. Жизненный цикл службы, которую вы запускаете, теперь привязан к жизненному циклу Деятельности, и пока деятельность находится на переднем плане (то есть видна), ваша служба не будет убита/уничтожена. –