ConcurrentState.java revision 63204dc989dbd0eba56f65086fde0ebe29ed6bdb
1/* 2 * Copyright (C) 2014 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 17package com.android.camera.async; 18 19import java.util.Set; 20import java.util.concurrent.CopyOnWriteArraySet; 21import java.util.concurrent.Executor; 22 23import javax.annotation.CheckReturnValue; 24import javax.annotation.Nonnull; 25import javax.annotation.ParametersAreNonnullByDefault; 26import javax.annotation.concurrent.GuardedBy; 27 28/** 29 * Generic asynchronous state wrapper which supports two methods of interaction: 30 * polling for the latest value and listening for updates. 31 */ 32@ParametersAreNonnullByDefault 33public class ConcurrentState<T> implements Updatable<T>, Observable<T> { 34 private static class ExecutorListenerPair implements Runnable { 35 private final Executor mExecutor; 36 private final Runnable mListener; 37 38 public ExecutorListenerPair(Executor executor, Runnable listener) { 39 mExecutor = executor; 40 mListener = listener; 41 } 42 43 /** 44 * Runs the callback on the executor. 45 */ 46 @Override 47 public void run() { 48 mExecutor.execute(mListener); 49 } 50 } 51 52 private final Set<ExecutorListenerPair> mListeners; 53 private volatile T mValue; 54 55 public ConcurrentState(T initialValue) { 56 // Callbacks are typically only added and removed at startup/shutdown, 57 // but {@link #update} is often called at high-frequency. So, using a 58 // read-optimized data structure is appropriate here. 59 mListeners = new CopyOnWriteArraySet<>(); 60 mValue = initialValue; 61 } 62 63 /** 64 * Updates the state to the latest value, notifying all listeners. 65 */ 66 @Override 67 public void update(T newValue) { 68 mValue = newValue; 69 for (ExecutorListenerPair pair : mListeners) { 70 pair.run(); 71 } 72 } 73 74 @CheckReturnValue 75 @Nonnull 76 @Override 77 public SafeCloseable addCallback(Runnable callback, Executor executor) { 78 final ExecutorListenerPair pair = new ExecutorListenerPair(executor, callback); 79 mListeners.add(pair); 80 return new SafeCloseable() { 81 @Override 82 public void close() { 83 mListeners.remove(pair); 84 } 85 }; 86 } 87 88 /** 89 * Polls for the latest value. 90 * 91 * @return The latest state. 92 */ 93 @Nonnull 94 @Override 95 public T get() { 96 return mValue; 97 } 98} 99