即使应用程序被销毁,AsyncTask仍将持续运行?

19

我有一个应用程序,因为不能在主线程上执行网络操作,所以我正在使用AsyncTask,那么问题是,一旦我execute()AsyncTask,然后立即finish()该活动,甚至用户可能会finish()整个应用程序,那么我想知道的是:

  1. 只要在应用程序运行时调用了execute(),即使应用程序被关闭,AsyncTask是否始终会完成doInBackground()onPostExecute()

4
你应该使用活动生命周期来取消正在运行的任务,使用Asynctask的cancel方法。即使你的UI已被销毁,继续进行网络操作也是无用的。但是,当网络操作完成并尝试更新UI时,应用程序会遇到问题。 - minhaz
5个回答

16

你将能够测试这个功能。是的,它有效。如果执行被调用,你会看到Asynctask仍然会执行,除非它对前台或UI相关做了一些事情(可能导致启动器崩溃)。


但是,如果它被系统关闭,它可能会继续执行方法,也可能不会。我已经在这里进行了测试并回答了评论。 回复评论:

@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        new Worker().execute();
    }
private class Worker extends AsyncTask<Void, Void, String> {

    @Override
    protected String doInBackground(Void... arg0) {
        Log.i("SomeTag",
                "start do in background at " + System.currentTimeMillis());
        String data = null;

        try {
            DefaultHttpClient httpClient = new DefaultHttpClient();
            HttpGet httpGet = new HttpGet(
                    "https://stackoverflow.com/questions/tagged/android");

            HttpResponse httpResponse = httpClient.execute(httpGet);
            HttpEntity httpEntity = httpResponse.getEntity();
            data = EntityUtils.toString(httpEntity);
            Log.i("SomeTag",
                    "doInBackGround done at " + System.currentTimeMillis());
        } catch (Exception e) {
        }
        return data;
    }

    @Override
    protected void onPostExecute(String result) {
        super.onPostExecute(result);
        Log.i("SomeTag", System.currentTimeMillis() / 1000L
                + " post execute \n" + result);
    }
}

@Override
protected void onDestroy() {
    super.onDestroy();
    Log.i("SomeTag", System.currentTimeMillis() / 1000L + "  onDestory()");
}

04-24 21:42:57.981: I/SomeTag(5961): start do in background at 1366854177994
04-24 21:43:00.974: I/SomeTag(5961): 1366854180  onDestory()
04-24 21:43:02.946: I/SomeTag(5961): doInBackGround done at 1366854182946
04-24 21:43:02.946: I/SomeTag(5961): 1366854182 post execute 
04-24 21:43:02.946: I/SomeTag(5961): <!DOCTYPE html>
04-24 21:43:02.946: I/SomeTag(5961): <html>
04-24 21:43:02.946: I/SomeTag(5961): <head>
04-24 21:43:02.946: I/SomeTag(5961):         
04-24 21:43:02.946: I/SomeTag(5961):     <title>Newest &#39;android&#39; Questions - Stack Overflow</title>
04-24 21:43:02.946: I/SomeTag(5961):     <link rel="shortcut icon" href="http://cdn.sstatic.net/stackoverflow/img/favicon.ico">
//....

谢谢,这正是我想知道的。根据你所说,我需要去做一些更改,尽力第一次就把它做对,你知道的。感谢你的时间。 - JRowan
我在这里稍微有些不同意。AsyncTasks 应该是与 UI 相关的。onPostExecute() 总是在 UI 线程上运行,所以在那种情况下它永远不会被调用。 - ddmps
@Pescis 已更新并测试。如发现我的测试有误,请指出错误。 - wtsang02
2
显然,在onDestroy()之后UI线程仍然可以运行 - 我没有预料到这一点。因此,取消任何UI任务以释放资源可能是一个非常好的主意。 - ddmps

9

onPostExecute()是从UI线程调用的,所以如果UI线程不再运行,它将不会继续运行。然而,doInBackground()是从单独的工作线程运行的,因此它将一直运行直到完成(或者如果JVM进程被操作系统杀死,这也是可能的)。请注意,AsyncTasks仅建议用于较短的UI绑定后台任务,而不是长时间运行的后台工作(几秒钟)。

简而言之,您不能假设它会继续运行,并且绝对不能假设它会发布其进度或调用onPostExecute()


6
当你在Activity上调用finish()方法时,这个Activity会被销毁,但是主线程并不会被销毁。[注意:Activity运行在主线程上,但Activity不是主线程。]
因此,在后台线程上执行doInBackground()方法,在主线程上执行onPostExecute()方法。然而,如果onPostExecute()方法执行与UI相关的任务,由于此时没有UI界面,你将会遇到ANR错误。
例如,如果你只是在onPostExecute()方法中打印Log.d()语句,那么这个语句将会在Logcat中显示。
** 这些仅在进程仍然存活,且未被Android低内存杀手程序杀死时才可能发生。

1
请查看图片以了解哪些方法在哪个线程中执行。

enter image description here


1
你可以轻松测试这个,只需让doInBackground()持续更长时间,例如添加Thread.sleep(5000),然后尝试各种场景:
  • 如果您完成了启动AsyncTask的Activity,或者导航离开它,AsyncTask会正常完成,但是如果您保留对周围Activity(如UI元素)的引用,而该Activity不再“活动”,则可能会导致内存泄漏或在onPostExecute()中崩溃。
  • 如果按下“主页”按钮最小化应用程序,则它将再次正常完成,但可能会在onPostExecute()中崩溃。
  • 如果终止应用程序进程(或系统这样做),它将终止您想要执行的作业doInBackground()的AsyncTask。如果您只是使用new Thread(new Runnable(){... 启动线程,则情况也是如此。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接