Android后台任务,UI线程和配置更改

时间:2014-04-14 07:47:06

标签: java android multithreading executorservice

为了解决跨配置更改保存后台任务的问题,我决定不执行以下操作而不是保留片段:

  • onSaveInstanceState(Bundle savedState)中:
    • 取消当前正在运行的任务
    • 将他们的id放入包中
  • onRestoreInstanceState(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]));
        }
    }
}

因此,pendingTasks.put()pendingTasks.remove()仅在UI线程上执行,前提是我在UI线程中调用addTask(),因此我不需要任何同步。

此时,我有一些问题:

  • 是否在UI线程上执行了活动生命周期方法onSaveInstanceState()onRestoreInstanceState()
  • executor.shutdown()会立即返回吗?

文档说executor.shutdown()等待以前提交的任何任务完成。因此,从执行程序服务的角度来看,任务在执行完最后一个命令后完成,在本例中为handler.post()。所以,如果我在onSaveInstanceState()时有任何挂起的任务,那么在执行程序关闭之后,UI线程可能会有一些已发布的runnables来执行,对吧?因为我在onSaveInstanceState(),活动可能会被破坏,在onRestoreInstanceState()我会有一个新的活动?那么runnables会发生什么呢?我操纵一些旧观点?重新创建活动后,是否会立即执行这些runnable?如果在我将一个runnable发布到UI线程之前,我检查执行程序当前是否正在关闭并且仅在它不是时执行它,那不是更好吗?在这种情况下,我可以绝对确定executor.isShutdown()在我致电true后会返回executor.shutDown()还是我必须等待任何任务完成?

1 个答案:

答案 0 :(得分:2)

  • 是否在UI线程上执行了活动生命周期方法onSaveInstanceState()和onRestoreInstanceState()?

  • 文档说,executor.shutdown()等待任何以前提交的任务完成。

    没有。你在哪里看到那些文件? ExecutorService.shutdown读取:This method does not wait for previously submitted tasks to complete execution. Use awaitTermination to do that

    • 那么runnables会发生什么,我操纵了一些旧视图?

    没什么好的。他们所处理的活动已被破坏。您应该举起一个标志并放弃task.onPostExecute(),或者保存它直到重新创建活动。请注意,您无法将它们保存在onSaveInstanceState()中 - 无论活动是否存在,runnables本身都应该考虑在内。

    • 重新创建活动后会立即执行这些runnable吗?

    不,直到你照顾他们。重新创建活动不仅应该重新启动后台任务,还应该使用onPostExecute重新启动运行。

相关问题