为了解决跨配置更改保存后台任务的问题,我决定不保留 fragment ,而是执行以下操作:
- 在
onSaveInstanceState(Bundle savingState)
中:- 取消任何当前正在运行的任务
- 将他们的 ID 放入 bundle 中
- 在
onRestoreInstanceState(Bundle savingState)
中:- 重新启动 ID 在 bundle 中的所有任务
由于我正在处理的任务不是特别长,因此重新启动它们不是问题,这不像我正在下载大文件或其他东西。
这是我的 TaskManager
的样子:
public class BackgroundTaskManager {
// Executor Service to run the tasks on
private final ExecutorService executor;
// list of current tasks
private final Map<String, BackgroundTask> pendingTasks;
// handler to execute stuff on the UI thread
private final Handler handler;
public BackgroundTaskManager(final ExecutorService executor) {
this.executor = executor;
this.pendingTasks = new HashMap<String, BackgroundTask>();
this.handler = new Handler(Looper.getMainLooper());
}
private void executeTask(final BackgroundTask task) {
// execute the background job in the background
executor.submit(new Runnable() {
@Override
public void run() {
task.doInBackground();
handler.post(new Runnable() {
@Override
public void run() {
// manipulate some views
task.onPostExecute();
// remove the task from the list of current tasks
pendingTasks.remove(task.getId());
// check if the list of current tasks is empty
}
});
}
});
}
/**
* Adds a task to the manager and executes it in the background
*
* @param task
* the task to be added
*/
public void addTask(final BackgroundTask task) {
pendingTasks.put(task.getId(), task);
executeTask(task);
}
public void onSaveInstanceState(Bundle savedInstanceState) {
// check if there are pendingTasks
if (!pendingTasks.isEmpty()) {
executor.shutdown();
savedInstanceState.putStringArray("pending tasks", pendingTasks.keySet().toArray(new String [1]));
}
}
}
因此,如果我调用 addTask()
,pendingTasks.put()
和 pendingTasks.remove()
仅在 UI 线程上执行code> 在 UI 线程中,所以我不需要任何同步。
此时,我有一些问题:
- Activity 生命周期方法
onSaveInstanceState()
和onRestoreInstanceState()
是否在 UI 线程上执行? executor.shutdown()
是否立即返回?
文档说 executor.shutdown()
等待任何先前提交的任务完成。因此,从执行程序服务的角度来看,任务在执行最后一个命令(在本例中为 handler.post()
)后完成。因此,如果我在 onSaveInstanceState()
中有任何待处理的任务,那么在执行程序关闭后,UI 线程可能会有一些已发布的可运行对象要执行,对吗?由于我处于 onSaveInstanceState()
中,该 Activity 可能会被销毁,而在 onRestoreInstanceState()
中我将有一个新 Activity ?那么,当我在其中操纵一些旧 View 时,可运行对象会发生什么情况呢?重新创建 Activity 后,这些可运行对象会立即执行吗?如果在将可运行程序发布到 UI 线程之前,检查执行器当前是否正在关闭,并且只有在没有关闭时才执行此操作,不是更好吗?在这种情况下,我可以绝对确定在调用 executor.shutDown()
后 executor.isShutdown()
将返回 true
或执行以下操作我必须等待任何任务完成吗?
最佳答案
Activity 生命周期方法 onSaveInstanceState() 和 onRestoreInstanceState() 是否在 UI 线程上执行?
是的
文档说 executor.shutdown() 等待任何先前提交的任务完成。
没有。您在哪里看到该文档? ExecutorService.shutdown内容如下:
该方法不等待先前提交的任务完成执行。使用awaitTermination 来做到这一点
。- 那么当我在其中操作一些旧 View 时,可运行对象会发生什么情况?
没什么好东西。他们所针对的 Activity 已经被破坏了。您应该提出一个标志并放弃
task.onPostExecute()
,或者保存它直到重新创建 Activity 。请注意,您无法将它们保存在onSaveInstanceState()
中 - runnables 本身应该考虑到 Activity 是否处于 Activity 状态。- 重新创建 Activity 后,这些可运行对象是否会立即执行?
不,除非你照顾好他们。重新创建 Activity 不仅应该重新启动后台任务,还应该使用
onPostExecute
重新启动可运行程序。
关于java - Android 后台任务、UI 线程和配置更改,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23054690/