Android - 跟踪线程

时间:2011-08-10 15:39:26

标签: android multithreading

我有一项活动,在执行期间,会启动几个AsyncTask和几个Thread s。

如果在销毁/重新创建活动时这些都会继续,那么就会出现各种错误,所以我的好主意就是让每个非UI线程注册自己,将自己添加到ArrayList<Thread>()ArrayList<AsyncTask>()意味着我可以,onDestroy(),迭代这些ArrayLists并像这样销毁它们:

@Override
public void onDestroy() 
{
    for(AsyncTask task : tasks)
        task.cancel(true);*

    for(Thread thread : threads)
        thread.interrupt();
}

不幸的是,这会在标有*的行上抛出java.util.ConcurrentModificationException。我尝试在for块中包装每个synchronize循环,以确保ArrayList未被任何其他Thread修改。

完成时AsyncTask是否会自行销毁(因此抛出上述错误)?

有没有人知道在Android环境中控制线程的更好方法?

修改

更改代码以使用for(int i =0 : i < array.size() ; i++)似乎可以解决这个问题,但我仍然想知道/为什么/它会发生:

    synchronized(tasks)
    {
        for(int i=0; i < tasks.size(); i++)
            tasks.get(i).cancel(true);
    }

    synchronized(threads)
    {
        for(int i=0; i < threads.size(); i++)
            threads.get(i).interrupt();
    }

4 个答案:

答案 0 :(得分:3)

这是一个非常古老的主题,但无论如何我都会回答它,因为这是人们常遇到的常见问题。

这里发生的是以下代码,

for(AsyncTask task : tasks)
    task.cancel(true);`

使用for-each循环,它需要tasks个对象在迭代它时保持完整。我的猜测是,在你的任务的onPostExecute()中,你要从这个列表中删除它,它会修改它并导致异常。

答案 1 :(得分:1)

据我所知,AsyncTasks一旦运行onPostExecute并且你将实例设置为null或类似的东西就会消失。你在Thread中做了什么,你在Service或AsyncTask中无法做到?您是否在线程中执行UI操作(例如,runOnUIThread或其他东西),当应用程序不在前台时会导致这些线程出错?

关于在服务中执行操作的好处是,您可以广播您即将关闭应用程序,并停止您不再需要运行的服务中的任何操作,基本上休眠服务直到您启动它当应用程序进入前台时再次出现。

答案 2 :(得分:1)

您不会阻止并发修改,除非应用中的所有修改都被synchronized包围;在这里做这件事是不够的。

尝试使用同步集合:

// create the empty list
List tasks = Collections.synchronized(new ArrayList<AsyncTask>());

答案 3 :(得分:0)

当doInBackground完成时,AsyncTask确实会自行终止。就此而言,当run()完成时,java线程会做同样的事情。对cancel()的调用只会返回true或false,具体取决于asyncTask是否能够被取消。

当您尝试修改线程中使用的内容时,抛出ConcurrentModificationException。根据我的理解,你在UI线程中使用数组列表来取消asynctasks,并且它也在两个asynctasks中用于注册自己。我猜你没有同步数组列表集合。

也许:

synchronized(tasks){
    for(int i=0; i < tasks.size(); i++){
       tasks.get(i).cancel(true);
    }
}

会修复它。确保所有asyncTasks中的任务也同步。或者你可以让它变得不稳定。

但无论如何,当你在onDestroy时,你的asyncTasks可能已经完成(或应该是),所以我不明白为什么你需要确保它们被取消。如果你不希望它们在用户离开应用程序时运行,那么你应该把它放在onPause()中。