2014-04-14 30 views
0

为了解决跨保存配置更改后台任务的问题,我已经决定,而不是保持一个片段,做到以下几点:Android的后台任务,UI线程和配置更改

    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线程上执行,前提是我称之为addTask()在UI线程,所以我不需要任何同步。

在这一点上,我有一些问题:

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

该文档说,executor.shutdown()等待任何以前提交的任务来完成。因此,从执行程序服务的角度来看,任务在执行最后一个命令后完成,在这种情况下为handler.post()。因此,如果我在onSaveInstanceState()中有任何未完成的任务,那么在执行程序关闭后,UI线程可能会发布一些可执行的runnables,对吧?因为我在onSaveInstanceState()该活动可能会被破坏,并在onRestoreInstanceState()我会有一个新的活动?那么对于可运行的应用程序会发生什么,我在哪些操作过程中操纵了一些旧视图?活动重新创建后,这些可运行的程序会立即执行吗?如果在我发布一个可运行的UI线程之前,我检查执行程序是否正在关闭,并且只有在它不是时才执行它?在这种情况下,我可以绝对确定executor.isShutdown()将在我调用executor.shutDown()后返回true,还是必须等待任何任务完成?

回答

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

  • 文档说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() - 可运行程序本身应考虑到活动是否存在。

    • 在活动重新创建后,这些可运行的程序会立即执行吗?

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

+0

对不起,我应该让自己更清楚。我的意思是在'executor.shutdown()'被调用之后,任何当前正在运行的任务都将被完成,而不是过早终止。那么'executor.shutdown()'立即返回,我可以依靠'executor.isShutdown()'事后返回'true'吗? –

+0

executor.shutdown()立即返回并且executor.isShutdown()变为true,但检查所有任务是否已完成使用isTerminated()。 –

+0

如果当我输入'onSaveInstanceState()'时,以及在更改关闭执行程序之前,UI线程已经发布了一些可运行的函数。是否可以通过UI线程输入'onSaveInstanceState()'来发布一些等待执行的runnables,或者Android确保不会发生? –