/*
* Copyright 2015 Google Inc. All Rights Reserved.
*
* 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 com.google.android.agera;
import android.os.Looper;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import java.util.ArrayDeque;
import java.util.PriorityQueue;
import java.util.Queue;
import static com.google.android.agera.Preconditions.checkNotNull;
import static com.google.android.agera.Result.absentIfNull;
/**
* Utility methods for creating {@link Reservoir} instances.
*
* <p>Any {@link Reservoir} created by this class has to be created from a {@link Looper} thread
* or the method will throw an {@link IllegalStateException}.
*
* Reservoir 的工具类
* 可以获取 Reservoir
*/
public final class Reservoirs {
/**
* Returns a {@link Reservoir} for the given value type.
*
* <p>The returned reservoir uses a standard unbounded FIFO queue as its backing storage. As a
* result, all values are accepted and no duplication checks are used, and they are dequeued in
* the same order.
*
* 构造一个 指定类型 T 的
* 同步水库
*/
@NonNull
public static <T> Reservoir<T> reservoirOf(
@SuppressWarnings("unused") @Nullable final Class<T> clazz) {
return reservoir();
}
/**
* Same as {@link #reservoirOf(Class)}. This variant is useful for when the value type is more
* readily inferrable from the context, such as when used as a variable initializer or a return
* value, so client code could simply write, for example,
*
* <pre>{@code Reservoir<String> stringReservoir = reservoir();}</pre>
*
* where this method is statically imported. This also helps in-line creation of a reservoir
* whose
* value type is generic, such as {@code List<String>}, so client code could write
* {@code Reservoirs.<List<String>>reservoir()} instead of the less readable
* {@code reservoirOf((Class<List<String>>) null)}.
*
* 实例化一个 队列为双端队列 的
* 同步水库,没有数据
*/
@NonNull
public static <T> Reservoir<T> reservoir() {
return reservoir(new ArrayDeque<T>());
}
/**
* Returns a {@link Reservoir} that uses the given {@code queue} as the backing storage for
* enqueuing and dequeuing values. It is up to the concrete {@link Queue#offer} implementation
* of
* the {@code queue} instance whether and how to accept each value to be enqueued.
*
* @param queue The backing storage of the reservoir. Any valid {@link Queue} implementation
* can
* be used, including non-FIFO queues such as {@link PriorityQueue}. Only these methods are
* used: {@link Queue#offer} for attempting to enqueue a value, {@link Queue#poll} for
* attempting to dequeue a value, and {@link Queue#isEmpty} for state check. All accesses are
* synchronized on this {@code queue} instance; if the queue must also be accessed elsewhere,
* those accesses must also be synchronized on this {@code queue} instance. Also note that
* modifications to the queue outside the {@link Reservoir} interface will not update the
* reservoir or its registered {@link Updatable}s.
*
* 根据一个 队列
* 构造一个 同步水库
*/
@NonNull
public static <T> Reservoir<T> reservoir(@NonNull final Queue<T> queue) {
return new SynchronizedReservoir<>(checkNotNull(queue));
}
/**
* 同步水库
*
* @param <T> 水库数据类型
*/
private static final class SynchronizedReservoir<T> extends BaseObservable
implements Reservoir<T> {
/**
* 内置的一个队列
* 用于存储 水库的 数据
*/
@NonNull
private final Queue<T> queue;
private SynchronizedReservoir(@NonNull final Queue<T> queue) {
this.queue = checkNotNull(queue);
}
/**
* Reservoir 作为一个 Receiver 的特性
* 可以接收 数据
*
* @param value 要接收的数据
*/
@Override
public void accept(@NonNull T value) {
boolean shouldDispatchUpdate;
// 锁住队列
synchronized (queue) {
// 队列内是否为没有数据
boolean wasEmpty = queue.isEmpty();
// 接收的数据 是否成功放入队列内
boolean added = queue.offer(value);
// 以上都符合的话,做一个标记
shouldDispatchUpdate = wasEmpty && added;
}
/*
* 如果 符合
* 1. 队列内是否为没有数据
* 2. 接收的数据 是否成功放入队列内
* 通知观察者
*/
if (shouldDispatchUpdate) {
dispatchUpdate();
}
}
/**
* Reservoir 作为一个 Repository 的特性
*
* @return 存储的数据
*/
@NonNull
@Override
public Result<T> get() {
T nullableValue;
boolean shouldDispatchUpdate;
synchronized (queue) {
nullableValue = queue.poll();
// 队列是否还有数据
shouldDispatchUpdate = !queue.isEmpty();
}
/*
* 如果队列还有数据
* 通知观察者
*/
if (shouldDispatchUpdate) {
dispatchUpdate();
}
/*
* 判断 传入的结果 是否为 null
* null 的话,返回 缺少参数的 错误 Result
* 不为 null 的话,返回 成功 Result
*/
return absentIfNull(nullableValue);
}
/**
* 观察者被激活时
* 队列内如果还有数据
* 通知观察者
*/
@Override
protected void observableActivated() {
synchronized (queue) {
if (queue.isEmpty()) {
return;
}
}
dispatchUpdate();
}
}
/**
* 屏蔽默认的构造方法
*/
private Reservoirs() {}
}