java - Android 后台任务、UI 线程和配置更改

标签 java android multithreading executorservice

为了解决跨配置更改保存后台任务的问题,我决定不保留 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/

相关文章:

android - Android 上的 Appium - SendKeys to EditText 也输入默认文本

c# - 替换 AppDomain.GetCurrentThreadId();使用 ManagedThreadId

java - 使用AtomicInteger时进行同步

java - 如何用 spring 拦截器替换 servlet 过滤器中的代码?

java - 如何在全新线程上启动某个类的每个实例?

java - 如何使用接口(interface)正确实现多态性?

android - 检测软键盘中的删除按钮

c# - 使用任务时如何使用上一个任务的结果继续使用另一个函数?

java - Java 中的类变量是否在线程之间共享?

java - 如果我想使用Java从网页中获取数据,我应该从哪里开始呢?