Java Android后台任务、UI线程和配置更改
为了解决跨配置更改保存后台任务的问题,我决定执行以下操作,而不是保留一个片段:Java Android后台任务、UI线程和配置更改,java,android,multithreading,executorservice,Java,Android,Multithreading,Executorservice,为了解决跨配置更改保存后台任务的问题,我决定执行以下操作,而不是保留一个片段: 在存储实例状态(Bundle savedState)中: 取消任何当前正在运行的任务 把他们的身份证放在包裹里 在恢复安装状态(Bundle savedState)中: 重新启动id在捆绑包中的所有任务 由于我正在处理的任务不是特别长,重新启动它们不是问题,这不像我正在下载一个大文件或什么的 下面是我的TaskManager的外观: public class BackgroundTaskManager {
- 在存储实例状态(Bundle savedState)中:
- 取消任何当前正在运行的任务
- 把他们的身份证放在包裹里
- 在恢复安装状态(Bundle savedState)中:
- 重新启动id在捆绑包中的所有任务
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]));
}
}
}
公共类背景任务管理器{
//要在其上运行任务的Executor服务
私人最终执行人服务执行人;
//当前任务列表
私人最终地图挂起任务;
//在UI线程上执行内容的处理程序
私人最终处理人;
公共背景任务经理(最终执行人服务执行人){
this.executor=执行人;
this.pendingTasks=newhashmap();
this.handler=新处理程序(Looper.getMainLooper());
}
私有void executeTask(最终后台任务){
//在后台执行后台作业
执行者提交(新的可运行(){
@凌驾
公开募捐{
task.doInBackground();
handler.post(新的Runnable(){
@凌驾
公开募捐{
//操纵某些视图
task.onPostExecute();
//从当前任务列表中删除该任务
remove(task.getId());
//检查当前任务列表是否为空
}
});
}
});
}
/**
*将任务添加到管理器并在后台执行
*
*@param任务
*要添加的任务
*/
public void addTask(最终后台任务任务){
pendingTasks.put(task.getId(),task);
执行任务;
}
SaveInstanceState上的公共无效(Bundle savedInstanceState){
//检查是否有挂起的任务
如果(!pendingTasks.isEmpty()){
executor.shutdown();
savedInstanceState.putStringArray(“挂起的任务”,pendingTasks.keySet().toArray(新字符串[1]);
}
}
}
因此,pendingTasks.put()
和pendingTasks.remove()
仅在UI线程上执行,前提是我在UI线程中调用addTask()
,因此我不需要任何同步
在这一点上,我有一些问题:
- 是否在UI线程上执行了活动生命周期方法
和onSaveInstanceState()
onRestoreInstanceState()
executor.shutdown()是否立即返回
executor.shutdown()
等待以前提交的任务完成。因此,从executor服务的角度来看,任务在执行其最后一个命令后完成,在本例中为handler.post()
。因此,如果我在onSaveInstanceState()
中时有任何挂起的任务,那么在执行器关闭后,UI线程可能会有一些已发布的可运行程序要执行,对吗?由于我在onSaveInstanceState()
中,活动可能会被销毁,而在onRestoreInstanceState()
中,我将有一个新的活动?那么我操纵一些旧视图的Runnable会发生什么呢?这些可运行文件是否会在重新创建活动后立即执行?如果在我向UI线程发布runnable之前,我检查执行器当前是否正在关闭,并且只有在它没有关闭时才执行,这不是更好吗?在这种情况下,我是否可以绝对确定在调用executor.shutDown()
后executor.isShutdown()将返回true
,或者我是否必须等待任何任务完成?
- 是否在UI线程上执行了onSaveInstanceState()和onRestoreInstanceState()的活动生命周期方法
对
- 文档中说executor.shutdown()等待以前提交的任务完成
没有。你在哪里看到的文件?读取:
此方法不等待以前提交的任务完成执行。使用此选项可执行此操作
- 那么我操纵一些旧视图的Runnable会发生什么呢李>
没什么好的。他们处理的活动已被销毁。您应该升起一个标志并放弃任务.onPostExecute()
,或者将其保存,直到重新创建活动为止。注意:您不能将它们保存在onSaveInstanceState()
中-无论活动是否处于活动状态,都应该考虑可运行程序本身
- 这些可运行文件是否会在重新创建活动后立即执行
不,除非你照顾好他们。重新创建活动不仅应重新启动后台任务,还应使用onPostExecute
运行
对不起,我应该说得更清楚些。我的意思是,在调用executor.shutdown()
之后,所有当前正在运行的任务都将完成,而不是过早终止。executor.shutdown()
是否立即返回,我是否可以依赖executor.isShutdown()
之后返回true
?executor.shutdown()立即返回,executor.isShutdown()变为true,但要检查是否所有任务都已完成,请使用isTerminated()。如果在saveInstanceState()中输入
在我有机会关闭