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      */
singleThreadExecutor()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      */
add(Runnable finisher)69     public static void add(Runnable finisher) {
70         sPendingWorkFinishers.add(finisher);
71     }
72 
remove(Runnable finisher)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      */
waitToFinish()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      */
hasPendingWork()97     public static boolean hasPendingWork() {
98         return !sPendingWorkFinishers.isEmpty();
99     }
100 
101 }
102