我有一个活动,它在执行过程中启动了几个AsyncTask
和几个Thread
。
如果这些继续当活动被销毁/重新创建,那么各种各样的错误发生,所以我的聪明的想法是让每个非UI线程注册自己,将自己添加到ArrayList<Thread>()
和ArrayList<AsyncTask>()
意味着我可以,onDestroy(),通过这些数组列表迭代并销毁它们,像这样:
@Override
public void onDestroy()
{
for(AsyncTask task : tasks)
task.cancel(true);*
for(Thread thread : threads)
thread.interrupt();
}
不幸的是,这会在用*标记的行上抛出java.util.ConcurrentModificationException
。我尝试在synchronize
块中包装每个for
循环,以确保ArrayList
s不会被任何其他Thread
s修改。
AsyncTask
s在完成时销毁自己(因此抛出上述错误)?
有谁知道在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();
}
这是一个非常古老的问题,但我还是会回答它,因为这是人们经常遇到的问题。
这里发生的是下面的代码
for(AsyncTask task : tasks)
task.cancel(true);`
使用for-each循环,需要tasks
对象在迭代时保持完整。我的猜测是,在您的任务的onPostExecute()
中,您正在从此列表中删除它,这会修改它并导致异常。
据我所知,AsyncTasks消失,一旦他们运行onPostExecute,你已经设置实例为空,或类似的东西。你在线程中做什么,你不能在服务或AsyncTask中做?你做UI操作在你的线程(如,runonuthread或其他东西),这将导致这些线程错误时,应用程序不是在前台?
在服务中做事情的好处是,你可以广播你即将关闭应用程序,并停止服务中不再需要运行的任何操作,本质上是休眠服务,直到应用程序进入前台时再次启动它。
你不能阻止并发修改,除非应用程序中的所有修改都被synchronized
包围;只在这里做是不够的。
尝试使用同步集合:
// create the empty list
List tasks = Collections.synchronized(new ArrayList<AsyncTask>());
当doInBackground完成时,AsyncTask确实会杀死自己。对于这个问题,java线程在run()完成时做同样的事情。cancel()的调用将只返回true或false,这取决于是否能够取消asyncTask。
当你试图修改线程中正在使用的东西时,ConcurrentModificationException会被抛出。据我所知,你的数组列表正在UI线程中用于取消asynctasks,它也在两个asynctasks中用于注册自己。我猜你在某个地方没有同步数组列表集合。 也许:
synchronized(tasks){
for(int i=0; i < tasks.size(); i++){
tasks.get(i).cancel(true);
}
}
将修复它。确保在所有asyncTasks中也同步了task。或者你可以让它挥发。
但是无论如何,当你在onDestroy时,你的asyncTasks可能已经完成了(或者应该完成),所以我不明白为什么你需要确保它们被取消。如果你不想让它们在用户离开应用程序时运行,那么你应该把它放在onPause()中。