Merge "Revert "Remove ViewTreeObserver allocations"" into jb-dev
This commit is contained in:
@ -20,6 +20,7 @@ import android.graphics.Rect;
|
||||
import android.graphics.Region;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
/**
|
||||
* A view tree observer is used to register listeners that can be notified of global
|
||||
@ -31,12 +32,12 @@ import java.util.ArrayList;
|
||||
* for more information.
|
||||
*/
|
||||
public final class ViewTreeObserver {
|
||||
private CopyOnWriteArray<OnGlobalFocusChangeListener> mOnGlobalFocusListeners;
|
||||
private CopyOnWriteArray<OnGlobalLayoutListener> mOnGlobalLayoutListeners;
|
||||
private CopyOnWriteArray<OnTouchModeChangeListener> mOnTouchModeChangeListeners;
|
||||
private CopyOnWriteArray<OnComputeInternalInsetsListener> mOnComputeInternalInsetsListeners;
|
||||
private CopyOnWriteArray<OnScrollChangedListener> mOnScrollChangedListeners;
|
||||
private CopyOnWriteArray<OnPreDrawListener> mOnPreDrawListeners;
|
||||
private CopyOnWriteArrayList<OnGlobalFocusChangeListener> mOnGlobalFocusListeners;
|
||||
private CopyOnWriteArrayList<OnGlobalLayoutListener> mOnGlobalLayoutListeners;
|
||||
private CopyOnWriteArrayList<OnTouchModeChangeListener> mOnTouchModeChangeListeners;
|
||||
private CopyOnWriteArrayList<OnComputeInternalInsetsListener> mOnComputeInternalInsetsListeners;
|
||||
private CopyOnWriteArrayList<OnScrollChangedListener> mOnScrollChangedListeners;
|
||||
private ArrayList<OnPreDrawListener> mOnPreDrawListeners;
|
||||
private ArrayList<OnDrawListener> mOnDrawListeners;
|
||||
|
||||
private boolean mAlive = true;
|
||||
@ -146,7 +147,7 @@ public final class ViewTreeObserver {
|
||||
* windows behind it should be placed.
|
||||
*/
|
||||
public final Rect contentInsets = new Rect();
|
||||
|
||||
|
||||
/**
|
||||
* Offsets from the frame of the window at which windows behind it
|
||||
* are visible.
|
||||
@ -165,13 +166,13 @@ public final class ViewTreeObserver {
|
||||
* can be touched.
|
||||
*/
|
||||
public static final int TOUCHABLE_INSETS_FRAME = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Option for {@link #setTouchableInsets(int)}: the area inside of
|
||||
* the content insets can be touched.
|
||||
*/
|
||||
public static final int TOUCHABLE_INSETS_CONTENT = 1;
|
||||
|
||||
|
||||
/**
|
||||
* Option for {@link #setTouchableInsets(int)}: the area inside of
|
||||
* the visible insets can be touched.
|
||||
@ -194,7 +195,7 @@ public final class ViewTreeObserver {
|
||||
}
|
||||
|
||||
int mTouchableInsets;
|
||||
|
||||
|
||||
void reset() {
|
||||
contentInsets.setEmpty();
|
||||
visibleInsets.setEmpty();
|
||||
@ -230,7 +231,7 @@ public final class ViewTreeObserver {
|
||||
mTouchableInsets = other.mTouchableInsets;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Interface definition for a callback to be invoked when layout has
|
||||
* completed and the client can compute its interior insets.
|
||||
@ -327,7 +328,7 @@ public final class ViewTreeObserver {
|
||||
checkIsAlive();
|
||||
|
||||
if (mOnGlobalFocusListeners == null) {
|
||||
mOnGlobalFocusListeners = new CopyOnWriteArray<OnGlobalFocusChangeListener>();
|
||||
mOnGlobalFocusListeners = new CopyOnWriteArrayList<OnGlobalFocusChangeListener>();
|
||||
}
|
||||
|
||||
mOnGlobalFocusListeners.add(listener);
|
||||
@ -362,7 +363,7 @@ public final class ViewTreeObserver {
|
||||
checkIsAlive();
|
||||
|
||||
if (mOnGlobalLayoutListeners == null) {
|
||||
mOnGlobalLayoutListeners = new CopyOnWriteArray<OnGlobalLayoutListener>();
|
||||
mOnGlobalLayoutListeners = new CopyOnWriteArrayList<OnGlobalLayoutListener>();
|
||||
}
|
||||
|
||||
mOnGlobalLayoutListeners.add(listener);
|
||||
@ -412,7 +413,7 @@ public final class ViewTreeObserver {
|
||||
checkIsAlive();
|
||||
|
||||
if (mOnPreDrawListeners == null) {
|
||||
mOnPreDrawListeners = new CopyOnWriteArray<OnPreDrawListener>();
|
||||
mOnPreDrawListeners = new ArrayList<OnPreDrawListener>();
|
||||
}
|
||||
|
||||
mOnPreDrawListeners.add(listener);
|
||||
@ -484,7 +485,7 @@ public final class ViewTreeObserver {
|
||||
checkIsAlive();
|
||||
|
||||
if (mOnScrollChangedListeners == null) {
|
||||
mOnScrollChangedListeners = new CopyOnWriteArray<OnScrollChangedListener>();
|
||||
mOnScrollChangedListeners = new CopyOnWriteArrayList<OnScrollChangedListener>();
|
||||
}
|
||||
|
||||
mOnScrollChangedListeners.add(listener);
|
||||
@ -518,7 +519,7 @@ public final class ViewTreeObserver {
|
||||
checkIsAlive();
|
||||
|
||||
if (mOnTouchModeChangeListeners == null) {
|
||||
mOnTouchModeChangeListeners = new CopyOnWriteArray<OnTouchModeChangeListener>();
|
||||
mOnTouchModeChangeListeners = new CopyOnWriteArrayList<OnTouchModeChangeListener>();
|
||||
}
|
||||
|
||||
mOnTouchModeChangeListeners.add(listener);
|
||||
@ -557,7 +558,7 @@ public final class ViewTreeObserver {
|
||||
|
||||
if (mOnComputeInternalInsetsListeners == null) {
|
||||
mOnComputeInternalInsetsListeners =
|
||||
new CopyOnWriteArray<OnComputeInternalInsetsListener>();
|
||||
new CopyOnWriteArrayList<OnComputeInternalInsetsListener>();
|
||||
}
|
||||
|
||||
mOnComputeInternalInsetsListeners.add(listener);
|
||||
@ -621,16 +622,10 @@ public final class ViewTreeObserver {
|
||||
// perform the dispatching. The iterator is a safe guard against listeners that
|
||||
// could mutate the list by calling the various add/remove methods. This prevents
|
||||
// the array from being modified while we iterate it.
|
||||
final CopyOnWriteArray<OnGlobalFocusChangeListener> listeners = mOnGlobalFocusListeners;
|
||||
final CopyOnWriteArrayList<OnGlobalFocusChangeListener> listeners = mOnGlobalFocusListeners;
|
||||
if (listeners != null && listeners.size() > 0) {
|
||||
CopyOnWriteArray.Access<OnGlobalFocusChangeListener> access = listeners.start();
|
||||
try {
|
||||
int count = access.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
access.get(i).onGlobalFocusChanged(oldFocus, newFocus);
|
||||
}
|
||||
} finally {
|
||||
listeners.end();
|
||||
for (OnGlobalFocusChangeListener listener : listeners) {
|
||||
listener.onGlobalFocusChanged(oldFocus, newFocus);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -645,16 +640,10 @@ public final class ViewTreeObserver {
|
||||
// perform the dispatching. The iterator is a safe guard against listeners that
|
||||
// could mutate the list by calling the various add/remove methods. This prevents
|
||||
// the array from being modified while we iterate it.
|
||||
final CopyOnWriteArray<OnGlobalLayoutListener> listeners = mOnGlobalLayoutListeners;
|
||||
final CopyOnWriteArrayList<OnGlobalLayoutListener> listeners = mOnGlobalLayoutListeners;
|
||||
if (listeners != null && listeners.size() > 0) {
|
||||
CopyOnWriteArray.Access<OnGlobalLayoutListener> access = listeners.start();
|
||||
try {
|
||||
int count = access.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
access.get(i).onGlobalLayout();
|
||||
}
|
||||
} finally {
|
||||
listeners.end();
|
||||
for (OnGlobalLayoutListener listener : listeners) {
|
||||
listener.onGlobalLayout();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -669,17 +658,17 @@ public final class ViewTreeObserver {
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public final boolean dispatchOnPreDraw() {
|
||||
// NOTE: we *must* clone the listener list to perform the dispatching.
|
||||
// The clone is a safe guard against listeners that
|
||||
// could mutate the list by calling the various add/remove methods. This prevents
|
||||
// the array from being modified while we process it.
|
||||
boolean cancelDraw = false;
|
||||
final CopyOnWriteArray<OnPreDrawListener> listeners = mOnPreDrawListeners;
|
||||
if (listeners != null && listeners.size() > 0) {
|
||||
CopyOnWriteArray.Access<OnPreDrawListener> access = listeners.start();
|
||||
try {
|
||||
int count = access.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
cancelDraw |= !(access.get(i).onPreDraw());
|
||||
}
|
||||
} finally {
|
||||
listeners.end();
|
||||
if (mOnPreDrawListeners != null && mOnPreDrawListeners.size() > 0) {
|
||||
final ArrayList<OnPreDrawListener> listeners =
|
||||
(ArrayList<OnPreDrawListener>) mOnPreDrawListeners.clone();
|
||||
int numListeners = listeners.size();
|
||||
for (int i = 0; i < numListeners; ++i) {
|
||||
cancelDraw |= !(listeners.get(i).onPreDraw());
|
||||
}
|
||||
}
|
||||
return cancelDraw;
|
||||
@ -704,17 +693,11 @@ public final class ViewTreeObserver {
|
||||
* @param inTouchMode True if the touch mode is now enabled, false otherwise.
|
||||
*/
|
||||
final void dispatchOnTouchModeChanged(boolean inTouchMode) {
|
||||
final CopyOnWriteArray<OnTouchModeChangeListener> listeners =
|
||||
final CopyOnWriteArrayList<OnTouchModeChangeListener> listeners =
|
||||
mOnTouchModeChangeListeners;
|
||||
if (listeners != null && listeners.size() > 0) {
|
||||
CopyOnWriteArray.Access<OnTouchModeChangeListener> access = listeners.start();
|
||||
try {
|
||||
int count = access.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
access.get(i).onTouchModeChanged(inTouchMode);
|
||||
}
|
||||
} finally {
|
||||
listeners.end();
|
||||
for (OnTouchModeChangeListener listener : listeners) {
|
||||
listener.onTouchModeChanged(inTouchMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -727,16 +710,10 @@ public final class ViewTreeObserver {
|
||||
// perform the dispatching. The iterator is a safe guard against listeners that
|
||||
// could mutate the list by calling the various add/remove methods. This prevents
|
||||
// the array from being modified while we iterate it.
|
||||
final CopyOnWriteArray<OnScrollChangedListener> listeners = mOnScrollChangedListeners;
|
||||
final CopyOnWriteArrayList<OnScrollChangedListener> listeners = mOnScrollChangedListeners;
|
||||
if (listeners != null && listeners.size() > 0) {
|
||||
CopyOnWriteArray.Access<OnScrollChangedListener> access = listeners.start();
|
||||
try {
|
||||
int count = access.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
access.get(i).onScrollChanged();
|
||||
}
|
||||
} finally {
|
||||
listeners.end();
|
||||
for (OnScrollChangedListener listener : listeners) {
|
||||
listener.onScrollChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -745,11 +722,11 @@ public final class ViewTreeObserver {
|
||||
* Returns whether there are listeners for computing internal insets.
|
||||
*/
|
||||
final boolean hasComputeInternalInsetsListeners() {
|
||||
final CopyOnWriteArray<OnComputeInternalInsetsListener> listeners =
|
||||
final CopyOnWriteArrayList<OnComputeInternalInsetsListener> listeners =
|
||||
mOnComputeInternalInsetsListeners;
|
||||
return (listeners != null && listeners.size() > 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calls all listeners to compute the current insets.
|
||||
*/
|
||||
@ -758,105 +735,12 @@ public final class ViewTreeObserver {
|
||||
// perform the dispatching. The iterator is a safe guard against listeners that
|
||||
// could mutate the list by calling the various add/remove methods. This prevents
|
||||
// the array from being modified while we iterate it.
|
||||
final CopyOnWriteArray<OnComputeInternalInsetsListener> listeners =
|
||||
final CopyOnWriteArrayList<OnComputeInternalInsetsListener> listeners =
|
||||
mOnComputeInternalInsetsListeners;
|
||||
if (listeners != null && listeners.size() > 0) {
|
||||
CopyOnWriteArray.Access<OnComputeInternalInsetsListener> access = listeners.start();
|
||||
try {
|
||||
int count = access.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
access.get(i).onComputeInternalInsets(inoutInfo);
|
||||
}
|
||||
} finally {
|
||||
listeners.end();
|
||||
for (OnComputeInternalInsetsListener listener : listeners) {
|
||||
listener.onComputeInternalInsets(inoutInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy on write array. This array is not thread safe, and only one loop can
|
||||
* iterate over this array at any given time. This class avoids allocations
|
||||
* until a concurrent modification happens.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* CopyOnWriteArray.Access<MyData> access = array.start();
|
||||
* try {
|
||||
* for (int i = 0; i < access.size(); i++) {
|
||||
* MyData d = access.get(i);
|
||||
* }
|
||||
* } finally {
|
||||
* access.end();
|
||||
* }
|
||||
*/
|
||||
static class CopyOnWriteArray<T> {
|
||||
private ArrayList<T> mData = new ArrayList<T>();
|
||||
private ArrayList<T> mDataCopy;
|
||||
|
||||
private final Access<T> mAccess = new Access<T>();
|
||||
|
||||
private boolean mStart;
|
||||
|
||||
static class Access<T> {
|
||||
private ArrayList<T> mData;
|
||||
private int mSize;
|
||||
|
||||
T get(int index) {
|
||||
return mData.get(index);
|
||||
}
|
||||
|
||||
int size() {
|
||||
return mSize;
|
||||
}
|
||||
}
|
||||
|
||||
CopyOnWriteArray() {
|
||||
}
|
||||
|
||||
private ArrayList<T> getArray() {
|
||||
if (mStart) {
|
||||
if (mDataCopy == null) mDataCopy = new ArrayList<T>(mData);
|
||||
return mDataCopy;
|
||||
}
|
||||
return mData;
|
||||
}
|
||||
|
||||
Access<T> start() {
|
||||
if (mStart) throw new IllegalStateException("Iteration already started");
|
||||
mStart = true;
|
||||
mDataCopy = null;
|
||||
mAccess.mData = mData;
|
||||
mAccess.mSize = mData.size();
|
||||
return mAccess;
|
||||
}
|
||||
|
||||
void end() {
|
||||
if (!mStart) throw new IllegalStateException("Iteration not started");
|
||||
mStart = false;
|
||||
if (mDataCopy != null) {
|
||||
mData = mDataCopy;
|
||||
}
|
||||
mDataCopy = null;
|
||||
}
|
||||
|
||||
int size() {
|
||||
return getArray().size();
|
||||
}
|
||||
|
||||
void add(T item) {
|
||||
getArray().add(item);
|
||||
}
|
||||
|
||||
void addAll(CopyOnWriteArray<T> array) {
|
||||
getArray().addAll(array.mData);
|
||||
}
|
||||
|
||||
void remove(T item) {
|
||||
getArray().remove(item);
|
||||
}
|
||||
|
||||
void clear() {
|
||||
getArray().clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user