am e79e8758: Merge "Remove ViewTreeObserver allocations" into jb-dev
* commit 'e79e87581280f4f3b26b1d4496b34cbb9aa39ae5': Remove ViewTreeObserver allocations
This commit is contained in:
@@ -20,7 +20,6 @@ import android.graphics.Rect;
|
|||||||
import android.graphics.Region;
|
import android.graphics.Region;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A view tree observer is used to register listeners that can be notified of global
|
* A view tree observer is used to register listeners that can be notified of global
|
||||||
@@ -32,12 +31,12 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
|||||||
* for more information.
|
* for more information.
|
||||||
*/
|
*/
|
||||||
public final class ViewTreeObserver {
|
public final class ViewTreeObserver {
|
||||||
private CopyOnWriteArrayList<OnGlobalFocusChangeListener> mOnGlobalFocusListeners;
|
private CopyOnWriteArray<OnGlobalFocusChangeListener> mOnGlobalFocusListeners;
|
||||||
private CopyOnWriteArrayList<OnGlobalLayoutListener> mOnGlobalLayoutListeners;
|
private CopyOnWriteArray<OnGlobalLayoutListener> mOnGlobalLayoutListeners;
|
||||||
private CopyOnWriteArrayList<OnTouchModeChangeListener> mOnTouchModeChangeListeners;
|
private CopyOnWriteArray<OnTouchModeChangeListener> mOnTouchModeChangeListeners;
|
||||||
private CopyOnWriteArrayList<OnComputeInternalInsetsListener> mOnComputeInternalInsetsListeners;
|
private CopyOnWriteArray<OnComputeInternalInsetsListener> mOnComputeInternalInsetsListeners;
|
||||||
private CopyOnWriteArrayList<OnScrollChangedListener> mOnScrollChangedListeners;
|
private CopyOnWriteArray<OnScrollChangedListener> mOnScrollChangedListeners;
|
||||||
private ArrayList<OnPreDrawListener> mOnPreDrawListeners;
|
private CopyOnWriteArray<OnPreDrawListener> mOnPreDrawListeners;
|
||||||
private ArrayList<OnDrawListener> mOnDrawListeners;
|
private ArrayList<OnDrawListener> mOnDrawListeners;
|
||||||
|
|
||||||
private boolean mAlive = true;
|
private boolean mAlive = true;
|
||||||
@@ -328,7 +327,7 @@ public final class ViewTreeObserver {
|
|||||||
checkIsAlive();
|
checkIsAlive();
|
||||||
|
|
||||||
if (mOnGlobalFocusListeners == null) {
|
if (mOnGlobalFocusListeners == null) {
|
||||||
mOnGlobalFocusListeners = new CopyOnWriteArrayList<OnGlobalFocusChangeListener>();
|
mOnGlobalFocusListeners = new CopyOnWriteArray<OnGlobalFocusChangeListener>();
|
||||||
}
|
}
|
||||||
|
|
||||||
mOnGlobalFocusListeners.add(listener);
|
mOnGlobalFocusListeners.add(listener);
|
||||||
@@ -363,7 +362,7 @@ public final class ViewTreeObserver {
|
|||||||
checkIsAlive();
|
checkIsAlive();
|
||||||
|
|
||||||
if (mOnGlobalLayoutListeners == null) {
|
if (mOnGlobalLayoutListeners == null) {
|
||||||
mOnGlobalLayoutListeners = new CopyOnWriteArrayList<OnGlobalLayoutListener>();
|
mOnGlobalLayoutListeners = new CopyOnWriteArray<OnGlobalLayoutListener>();
|
||||||
}
|
}
|
||||||
|
|
||||||
mOnGlobalLayoutListeners.add(listener);
|
mOnGlobalLayoutListeners.add(listener);
|
||||||
@@ -413,7 +412,7 @@ public final class ViewTreeObserver {
|
|||||||
checkIsAlive();
|
checkIsAlive();
|
||||||
|
|
||||||
if (mOnPreDrawListeners == null) {
|
if (mOnPreDrawListeners == null) {
|
||||||
mOnPreDrawListeners = new ArrayList<OnPreDrawListener>();
|
mOnPreDrawListeners = new CopyOnWriteArray<OnPreDrawListener>();
|
||||||
}
|
}
|
||||||
|
|
||||||
mOnPreDrawListeners.add(listener);
|
mOnPreDrawListeners.add(listener);
|
||||||
@@ -485,7 +484,7 @@ public final class ViewTreeObserver {
|
|||||||
checkIsAlive();
|
checkIsAlive();
|
||||||
|
|
||||||
if (mOnScrollChangedListeners == null) {
|
if (mOnScrollChangedListeners == null) {
|
||||||
mOnScrollChangedListeners = new CopyOnWriteArrayList<OnScrollChangedListener>();
|
mOnScrollChangedListeners = new CopyOnWriteArray<OnScrollChangedListener>();
|
||||||
}
|
}
|
||||||
|
|
||||||
mOnScrollChangedListeners.add(listener);
|
mOnScrollChangedListeners.add(listener);
|
||||||
@@ -519,7 +518,7 @@ public final class ViewTreeObserver {
|
|||||||
checkIsAlive();
|
checkIsAlive();
|
||||||
|
|
||||||
if (mOnTouchModeChangeListeners == null) {
|
if (mOnTouchModeChangeListeners == null) {
|
||||||
mOnTouchModeChangeListeners = new CopyOnWriteArrayList<OnTouchModeChangeListener>();
|
mOnTouchModeChangeListeners = new CopyOnWriteArray<OnTouchModeChangeListener>();
|
||||||
}
|
}
|
||||||
|
|
||||||
mOnTouchModeChangeListeners.add(listener);
|
mOnTouchModeChangeListeners.add(listener);
|
||||||
@@ -558,7 +557,7 @@ public final class ViewTreeObserver {
|
|||||||
|
|
||||||
if (mOnComputeInternalInsetsListeners == null) {
|
if (mOnComputeInternalInsetsListeners == null) {
|
||||||
mOnComputeInternalInsetsListeners =
|
mOnComputeInternalInsetsListeners =
|
||||||
new CopyOnWriteArrayList<OnComputeInternalInsetsListener>();
|
new CopyOnWriteArray<OnComputeInternalInsetsListener>();
|
||||||
}
|
}
|
||||||
|
|
||||||
mOnComputeInternalInsetsListeners.add(listener);
|
mOnComputeInternalInsetsListeners.add(listener);
|
||||||
@@ -622,10 +621,16 @@ public final class ViewTreeObserver {
|
|||||||
// perform the dispatching. The iterator is a safe guard against listeners that
|
// 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
|
// could mutate the list by calling the various add/remove methods. This prevents
|
||||||
// the array from being modified while we iterate it.
|
// the array from being modified while we iterate it.
|
||||||
final CopyOnWriteArrayList<OnGlobalFocusChangeListener> listeners = mOnGlobalFocusListeners;
|
final CopyOnWriteArray<OnGlobalFocusChangeListener> listeners = mOnGlobalFocusListeners;
|
||||||
if (listeners != null && listeners.size() > 0) {
|
if (listeners != null && listeners.size() > 0) {
|
||||||
for (OnGlobalFocusChangeListener listener : listeners) {
|
CopyOnWriteArray.Access<OnGlobalFocusChangeListener> access = listeners.start();
|
||||||
listener.onGlobalFocusChanged(oldFocus, newFocus);
|
try {
|
||||||
|
int count = access.size();
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
access.get(i).onGlobalFocusChanged(oldFocus, newFocus);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
listeners.end();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -640,10 +645,16 @@ public final class ViewTreeObserver {
|
|||||||
// perform the dispatching. The iterator is a safe guard against listeners that
|
// 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
|
// could mutate the list by calling the various add/remove methods. This prevents
|
||||||
// the array from being modified while we iterate it.
|
// the array from being modified while we iterate it.
|
||||||
final CopyOnWriteArrayList<OnGlobalLayoutListener> listeners = mOnGlobalLayoutListeners;
|
final CopyOnWriteArray<OnGlobalLayoutListener> listeners = mOnGlobalLayoutListeners;
|
||||||
if (listeners != null && listeners.size() > 0) {
|
if (listeners != null && listeners.size() > 0) {
|
||||||
for (OnGlobalLayoutListener listener : listeners) {
|
CopyOnWriteArray.Access<OnGlobalLayoutListener> access = listeners.start();
|
||||||
listener.onGlobalLayout();
|
try {
|
||||||
|
int count = access.size();
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
access.get(i).onGlobalLayout();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
listeners.end();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -658,17 +669,17 @@ public final class ViewTreeObserver {
|
|||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public final boolean dispatchOnPreDraw() {
|
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;
|
boolean cancelDraw = false;
|
||||||
if (mOnPreDrawListeners != null && mOnPreDrawListeners.size() > 0) {
|
final CopyOnWriteArray<OnPreDrawListener> listeners = mOnPreDrawListeners;
|
||||||
final ArrayList<OnPreDrawListener> listeners =
|
if (listeners != null && listeners.size() > 0) {
|
||||||
(ArrayList<OnPreDrawListener>) mOnPreDrawListeners.clone();
|
CopyOnWriteArray.Access<OnPreDrawListener> access = listeners.start();
|
||||||
int numListeners = listeners.size();
|
try {
|
||||||
for (int i = 0; i < numListeners; ++i) {
|
int count = access.size();
|
||||||
cancelDraw |= !(listeners.get(i).onPreDraw());
|
for (int i = 0; i < count; i++) {
|
||||||
|
cancelDraw |= !(access.get(i).onPreDraw());
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
listeners.end();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return cancelDraw;
|
return cancelDraw;
|
||||||
@@ -693,11 +704,17 @@ public final class ViewTreeObserver {
|
|||||||
* @param inTouchMode True if the touch mode is now enabled, false otherwise.
|
* @param inTouchMode True if the touch mode is now enabled, false otherwise.
|
||||||
*/
|
*/
|
||||||
final void dispatchOnTouchModeChanged(boolean inTouchMode) {
|
final void dispatchOnTouchModeChanged(boolean inTouchMode) {
|
||||||
final CopyOnWriteArrayList<OnTouchModeChangeListener> listeners =
|
final CopyOnWriteArray<OnTouchModeChangeListener> listeners =
|
||||||
mOnTouchModeChangeListeners;
|
mOnTouchModeChangeListeners;
|
||||||
if (listeners != null && listeners.size() > 0) {
|
if (listeners != null && listeners.size() > 0) {
|
||||||
for (OnTouchModeChangeListener listener : listeners) {
|
CopyOnWriteArray.Access<OnTouchModeChangeListener> access = listeners.start();
|
||||||
listener.onTouchModeChanged(inTouchMode);
|
try {
|
||||||
|
int count = access.size();
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
access.get(i).onTouchModeChanged(inTouchMode);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
listeners.end();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -710,10 +727,16 @@ public final class ViewTreeObserver {
|
|||||||
// perform the dispatching. The iterator is a safe guard against listeners that
|
// 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
|
// could mutate the list by calling the various add/remove methods. This prevents
|
||||||
// the array from being modified while we iterate it.
|
// the array from being modified while we iterate it.
|
||||||
final CopyOnWriteArrayList<OnScrollChangedListener> listeners = mOnScrollChangedListeners;
|
final CopyOnWriteArray<OnScrollChangedListener> listeners = mOnScrollChangedListeners;
|
||||||
if (listeners != null && listeners.size() > 0) {
|
if (listeners != null && listeners.size() > 0) {
|
||||||
for (OnScrollChangedListener listener : listeners) {
|
CopyOnWriteArray.Access<OnScrollChangedListener> access = listeners.start();
|
||||||
listener.onScrollChanged();
|
try {
|
||||||
|
int count = access.size();
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
access.get(i).onScrollChanged();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
listeners.end();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -722,7 +745,7 @@ public final class ViewTreeObserver {
|
|||||||
* Returns whether there are listeners for computing internal insets.
|
* Returns whether there are listeners for computing internal insets.
|
||||||
*/
|
*/
|
||||||
final boolean hasComputeInternalInsetsListeners() {
|
final boolean hasComputeInternalInsetsListeners() {
|
||||||
final CopyOnWriteArrayList<OnComputeInternalInsetsListener> listeners =
|
final CopyOnWriteArray<OnComputeInternalInsetsListener> listeners =
|
||||||
mOnComputeInternalInsetsListeners;
|
mOnComputeInternalInsetsListeners;
|
||||||
return (listeners != null && listeners.size() > 0);
|
return (listeners != null && listeners.size() > 0);
|
||||||
}
|
}
|
||||||
@@ -735,12 +758,105 @@ public final class ViewTreeObserver {
|
|||||||
// perform the dispatching. The iterator is a safe guard against listeners that
|
// 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
|
// could mutate the list by calling the various add/remove methods. This prevents
|
||||||
// the array from being modified while we iterate it.
|
// the array from being modified while we iterate it.
|
||||||
final CopyOnWriteArrayList<OnComputeInternalInsetsListener> listeners =
|
final CopyOnWriteArray<OnComputeInternalInsetsListener> listeners =
|
||||||
mOnComputeInternalInsetsListeners;
|
mOnComputeInternalInsetsListeners;
|
||||||
if (listeners != null && listeners.size() > 0) {
|
if (listeners != null && listeners.size() > 0) {
|
||||||
for (OnComputeInternalInsetsListener listener : listeners) {
|
CopyOnWriteArray.Access<OnComputeInternalInsetsListener> access = listeners.start();
|
||||||
listener.onComputeInternalInsets(inoutInfo);
|
try {
|
||||||
|
int count = access.size();
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
access.get(i).onComputeInternalInsets(inoutInfo);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
listeners.end();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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