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