我有一项活动,在执行期间,会启动几个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();
}
答案 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()中。