1

设置:

我有一个单例应用程序类,它有一个名为fetchUpdates(). 此方法由UpdaterService(一个 IntentService)类调用。fetchUpdates()方法只需调用 DownloadDataAsyncTask,如果数据成功下载,则在调用UpdateDbAsyncTask期间调用。onPostExecute两个 AsyncTask 都驻留在应用程序类中(不确定这是否与问题相关)。

public synchronized void fetchUpdates() {
    String[] mURLs = getURLs();
    new DownloadDataAsyncTask().execute(mURLs[0], mURLs[1]);
}

下载DataAsyncTask 类

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在 API 10 中的 doInBackground 之后执行暂停。也没有调用 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.

进一步的研究

AsyncTask的线程规则指出:

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

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

我还发现其他人也有类似的问题。后来在问题中建议

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

但我也不太确定该怎么做。

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

更新 1

仅当我从 Activity 调用UpdaterServiceIntentService 类(调用fetchUpdates()Application 类中的方法)时才会出现问题。我的代码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,问题似乎并没有持续存在。MainActivitystartService(new Intent(this, UpdaterService.class));

4

3 回答 3

6

首先,IntentService 中代码的执行已经在后台线程中运行。无需使用 AsyncTask。

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

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

于 2013-06-22T13:19:51.057 回答
1

解决方案很简单,在postExecuteDownloadDataAsyncTask,简单地这样做:

@Override
protected void onPostExecute(final JSONObject[] result) {
     if (result[0] != null && result[1] != null) {
         runOnUiThread(new Runnable() {
             @Override
             public void run() {
                 new UpdateDbAsyncTask().execute(result[0], result[1]);
             }
         });
     } else {
         displayFailureToast();
     }
}
于 2013-06-22T11:33:01.670 回答
0

UpdateDbAsyncTask( )线程类 的doInBackground() 中,在rubInUiThread () 中编写代码

于 2013-06-22T12:38:23.073 回答