/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.app; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * Internal utility class to keep track of process-global work that's * outstanding and hasn't been finished yet. * * This was created for writing SharedPreference edits out * asynchronously so we'd have a mechanism to wait for the writes in * Activity.onPause and similar places, but we may use this mechanism * for other things in the future. * * @hide */ public class QueuedWork { // The set of Runnables that will finish or wait on any async // activities started by the application. private static final ConcurrentLinkedQueue<Runnable> sPendingWorkFinishers = new ConcurrentLinkedQueue<Runnable>(); private static ExecutorService sSingleThreadExecutor = null; // lazy, guarded by class /** * Returns a single-thread Executor shared by the entire process, * creating it if necessary. */ public static ExecutorService singleThreadExecutor() { synchronized (QueuedWork.class) { if (sSingleThreadExecutor == null) { // TODO: can we give this single thread a thread name? sSingleThreadExecutor = Executors.newSingleThreadExecutor(); } return sSingleThreadExecutor; } } /** * Add a runnable to finish (or wait for) a deferred operation * started in this context earlier. Typically finished by e.g. * an Activity#onPause. Used by SharedPreferences$Editor#startCommit(). * * Note that this doesn't actually start it running. This is just * a scratch set for callers doing async work to keep updated with * what's in-flight. In the common case, caller code * (e.g. SharedPreferences) will pretty quickly call remove() * after an add(). The only time these Runnables are run is from * waitToFinish(), below. */ public static void add(Runnable finisher) { sPendingWorkFinishers.add(finisher); } public static void remove(Runnable finisher) { sPendingWorkFinishers.remove(finisher); } /** * Finishes or waits for async operations to complete. * (e.g. SharedPreferences$Editor#startCommit writes) * * Is called from the Activity base class's onPause(), after * BroadcastReceiver's onReceive, after Service command handling, * etc. (so async work is never lost) */ public static void waitToFinish() { Runnable toFinish; while ((toFinish = sPendingWorkFinishers.poll()) != null) { toFinish.run(); } } /** * Returns true if there is pending work to be done. Note that the * result is out of data as soon as you receive it, so be careful how you * use it. */ public static boolean hasPendingWork() { return !sPendingWorkFinishers.isEmpty(); } }