Home | History | Annotate | Download | only in app
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.app;
     18 
     19 import java.util.concurrent.ConcurrentLinkedQueue;
     20 import java.util.concurrent.ExecutorService;
     21 import java.util.concurrent.Executors;
     22 
     23 /**
     24  * Internal utility class to keep track of process-global work that's
     25  * outstanding and hasn't been finished yet.
     26  *
     27  * This was created for writing SharedPreference edits out
     28  * asynchronously so we'd have a mechanism to wait for the writes in
     29  * Activity.onPause and similar places, but we may use this mechanism
     30  * for other things in the future.
     31  *
     32  * @hide
     33  */
     34 public class QueuedWork {
     35 
     36     // The set of Runnables that will finish or wait on any async
     37     // activities started by the application.
     38     private static final ConcurrentLinkedQueue<Runnable> sPendingWorkFinishers =
     39             new ConcurrentLinkedQueue<Runnable>();
     40 
     41     private static ExecutorService sSingleThreadExecutor = null; // lazy, guarded by class
     42 
     43     /**
     44      * Returns a single-thread Executor shared by the entire process,
     45      * creating it if necessary.
     46      */
     47     public static ExecutorService singleThreadExecutor() {
     48         synchronized (QueuedWork.class) {
     49             if (sSingleThreadExecutor == null) {
     50                 // TODO: can we give this single thread a thread name?
     51                 sSingleThreadExecutor = Executors.newSingleThreadExecutor();
     52             }
     53             return sSingleThreadExecutor;
     54         }
     55     }
     56 
     57     /**
     58      * Add a runnable to finish (or wait for) a deferred operation
     59      * started in this context earlier.  Typically finished by e.g.
     60      * an Activity#onPause.  Used by SharedPreferences$Editor#startCommit().
     61      *
     62      * Note that this doesn't actually start it running.  This is just
     63      * a scratch set for callers doing async work to keep updated with
     64      * what's in-flight.  In the common case, caller code
     65      * (e.g. SharedPreferences) will pretty quickly call remove()
     66      * after an add().  The only time these Runnables are run is from
     67      * waitToFinish(), below.
     68      */
     69     public static void add(Runnable finisher) {
     70         sPendingWorkFinishers.add(finisher);
     71     }
     72 
     73     public static void remove(Runnable finisher) {
     74         sPendingWorkFinishers.remove(finisher);
     75     }
     76 
     77     /**
     78      * Finishes or waits for async operations to complete.
     79      * (e.g. SharedPreferences$Editor#startCommit writes)
     80      *
     81      * Is called from the Activity base class's onPause(), after
     82      * BroadcastReceiver's onReceive, after Service command handling,
     83      * etc.  (so async work is never lost)
     84      */
     85     public static void waitToFinish() {
     86         Runnable toFinish;
     87         while ((toFinish = sPendingWorkFinishers.poll()) != null) {
     88             toFinish.run();
     89         }
     90     }
     91 
     92     /**
     93      * Returns true if there is pending work to be done.  Note that the
     94      * result is out of data as soon as you receive it, so be careful how you
     95      * use it.
     96      */
     97     public static boolean hasPendingWork() {
     98         return !sPendingWorkFinishers.isEmpty();
     99     }
    100 
    101 }
    102