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()中输入
在我有机会关闭