从另一个AsyncTask的onPostExecute启动的asyncTask在API 10中无法正确执行

时间:2013-06-22 11:20:56

标签: android asynctaskloader

SETUP:

我有一个单例应用程序类,它有一个名为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中一切正常,但在API 10中的doInBackground之后暂停执行UpdateDbAsyncTask。也不会调用onCancelled(Object)方法。

LOGCAT OUTPUT

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.

进一步研究

AsyncTask的threading rules表示:

  • 必须在UI线程上加载AsyncTask类。这是从JELLY_BEAN开始自动完成的。
  • 必须在UI线程上创建任务实例。
  • 必须在UI线程上调用
  • execute(Params ...)。
  • 等...

根据我的理解(这不是很多,刚开始编程)第一个UpdateDbAsyncTask在两个API中都完全执行,因为它不违反任何线程规则。但是第二个是违反其中一个线程规则,导致它在doInBackground之后停止执行,或者它完全超出了我的理解。

我还找到了其他类似issue的人。后来在问题中提出了

  

在我的代码中始终只使用AsyncTask类API15 +

但我也不太确定如何做到这一点。

非常感谢任何帮助。谢谢!

更新1

只有从Activity调用UpdaterService IntentService类(在Application类中调用fetchUpdates()方法)时才会出现问题。我在MainActivity中的代码如下:

startService(new Intent(this, UpdaterService.class));

但是,当我直接使用代码

调用fetchUpdates()
MyApplication myApp = (MyApplication) getApplication();
myApp.fetchUpdates();
来自MainActivity

,一切都在API 10中完美执行。

并且还要注意,UpdaterService也是使用BroadcastReceiver类调用的,该类使用重复警报定期调用。在这种情况下,AsyncTasks按预期执行......非常奇怪。

更新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));,问题似乎不会持久。

3 个答案:

答案 0 :(得分:6)

首先,IntentService中的代码执行已经在后台线程中运行。没有必要使用AsyncTask。

我发现这个错误并不奇怪。我很惊讶你的第二个AsyncTask被调用了。当您的IntentService完成调用fetchUpdates方法时,您的服务已完成,您的进程和/或线程可能被安排销毁/终止。根据操作系统的激进程度,可能会立即或几分钟后发生。这意味着你的代码将在一个死线程上运行,这就是所发生的事情。

解决方案: 不要在IntentService中使用AsyncTasks。相反,只需直接从IntentService中的AsyncTasks调用代码即可。

答案 1 :(得分:1)

解决方案很简单,在postExecute的{​​{1}}中,只需这样做:

DownloadDataAsyncTask

答案 2 :(得分:0)

rubInUiThread()

rubInUiThread()更新DbAsyncTask()线程类的 doInBackground()