【发布时间】:2014-07-03 08:26:20
【问题描述】:
我正在使用 AsyncTask 运行后台操作。当然,在已经在后台线程中工作时切换到另一个线程通常没有多大意义,除了另一个线程是 UI 线程。这就是我想要的:当任务运行时,我需要“访问”用户界面,例如显示一个对话框,询问用户如何继续。
- 运行后台任务
- 停止任务以获取用户反馈
- 切换到 UI 线程以显示对话框并要求输入
- 切换回后台任务并继续工作
如何做到这一点?我以为我可以将Runnable 与myActivity.runOnUiThread(runnable) 一起使用,但这不起作用:
private void copyFiles() {
CopyTask copyTask = new CopyTask(this);
copyTask.execute();
}
// CustomAsyncTask is a AsyncTask subclass that takes a reference to the current
// activity as parameter
private class CopyTask extends CustomAsyncTask<Void, Void, Void> {
private doCopy;
@Override
protected Boolean doInBackground(Void... params) {
// Custom code, e.g. copy files from A to B and check for conflict
for (File file : allFiles) {
doCopy = true;
if (isConflict(file)) {
// Stop current thread and ask for user feedback on UI Thread
Runnable uiRunnable = new Runnable() {
public void run() {
// Pos 1. --> Execute custom code, e.g. use AlertDialog to ask user if file should be replaced...
doCopy = false;
synchronized (this) {
this.notify();
}
}
});
synchronized(uiRunnable) {
// Execute code on UI thread
activity.runOnUiThread(uiRunnable);
// Wait until runnable finished
try {
uiRunnable.wait();
}
catch (InterruptedException e ) {
e.printStackTrace();
}
}
}
// Pos 2. --> Continue work
if (doCopy)
copyFromAToB(File);
}
return null;
}
}
在doInBackground() 内(--> 在后台线程中)AsyncTask 调用activity.runOnUiThread(uiRunnable)。接下来调用uiRunnable.wait()。关于docu wait() 应该做到以下几点:
使调用线程等待直到另一个线程调用 此对象的 notify() 或 notifyAll() 方法。
因此,后台线程应该等到this.notify() (== uiRunnable.notifiy()) 在另一个线程(= UI 线程)上被调用后才能继续工作,不是吗?
好吧,id 不等待! 调用uiRunnable.wait() 后,后台线程立即继续跳转到if (doCopy)...。似乎后台线程和主线程是并行执行的(这并不奇怪,因为这是线程所做的......),因此无论是 UI 线程上的 doCopy = false 还是后台线程上的 if (doCopy) 都是竞争条件最先到达。
这怎么可能?为什么wait() 没有按描述工作? 还是我有什么问题?
非常感谢!
编辑: 为了避免误解:我当然知道 AsyncTask 的生命周期方法,但据我了解,它们不是我想要的(请参阅我对评论的回复)。
一旦需要 UI 交互就中断 AsyncTask,当然可以查询 UI 并启动一个新的 AsyncTask。然而,这会导致代码非常难以阅读/理解/维护。
据我了解wait() 的文档,这里一切正常。主要问题不是如何在 AsyncTask 的生命周期中进行 UI 交互,而是为什么 wait() 不能按预期工作。
【问题讨论】:
-
请阅读异步任务的生命周期方法!
-
当然,我知道这些方法。但它们只允许在任务运行之前或之后进行 UI 更改。
onProgressUpdate()可以在执行期间使用,但关于文档,不保证该方法何时运行。后台线程将继续其工作,而不是等待onProgressUpdate()返回。但这就是我要找的。因此,在这种特殊情况下,这些方法没有帮助,不是吗? -
然后基本上你需要将你的任务分成几部分——处理然后更新 UI——处理然后更新 UI 否则你可能想要考虑一个 Handler 线程。
-
谢谢。请看看我的编辑。将进程拆分为多个 AsyncTask 可以解决问题,但我认为这不是一个很好的解决方案。此外,主要问题是为什么
wait()没有按预期工作,而不是如何规避它没有的事实:) -
顺便声明
activity在哪里?我只是一起完成了您的代码的几乎完全相同的副本,它工作正常。也许它没有等待,因为isConflict(file)是真的,所以等待/通知可运行部分无论如何都不会运行。
标签: java android multithreading android-asynctask runnable