Skip to content

Commit a1723d1

Browse files
chethaaseAndroid (Google) Code Review
authored andcommitted
Merge "Revert "Remove ViewTreeObserver allocations"" into jb-dev
2 parents fefd489 + 0f8ffd8 commit a1723d1

File tree

1 file changed

+45
-161
lines changed

1 file changed

+45
-161
lines changed

core/java/android/view/ViewTreeObserver.java

Lines changed: 45 additions & 161 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import android.graphics.Region;
2121

2222
import java.util.ArrayList;
23+
import java.util.concurrent.CopyOnWriteArrayList;
2324

2425
/**
2526
* A view tree observer is used to register listeners that can be notified of global
@@ -31,12 +32,12 @@
3132
* for more information.
3233
*/
3334
public final class ViewTreeObserver {
34-
private CopyOnWriteArray<OnGlobalFocusChangeListener> mOnGlobalFocusListeners;
35-
private CopyOnWriteArray<OnGlobalLayoutListener> mOnGlobalLayoutListeners;
36-
private CopyOnWriteArray<OnTouchModeChangeListener> mOnTouchModeChangeListeners;
37-
private CopyOnWriteArray<OnComputeInternalInsetsListener> mOnComputeInternalInsetsListeners;
38-
private CopyOnWriteArray<OnScrollChangedListener> mOnScrollChangedListeners;
39-
private CopyOnWriteArray<OnPreDrawListener> mOnPreDrawListeners;
35+
private CopyOnWriteArrayList<OnGlobalFocusChangeListener> mOnGlobalFocusListeners;
36+
private CopyOnWriteArrayList<OnGlobalLayoutListener> mOnGlobalLayoutListeners;
37+
private CopyOnWriteArrayList<OnTouchModeChangeListener> mOnTouchModeChangeListeners;
38+
private CopyOnWriteArrayList<OnComputeInternalInsetsListener> mOnComputeInternalInsetsListeners;
39+
private CopyOnWriteArrayList<OnScrollChangedListener> mOnScrollChangedListeners;
40+
private ArrayList<OnPreDrawListener> mOnPreDrawListeners;
4041
private ArrayList<OnDrawListener> mOnDrawListeners;
4142

4243
private boolean mAlive = true;
@@ -146,7 +147,7 @@ public final static class InternalInsetsInfo {
146147
* windows behind it should be placed.
147148
*/
148149
public final Rect contentInsets = new Rect();
149-
150+
150151
/**
151152
* Offsets from the frame of the window at which windows behind it
152153
* are visible.
@@ -165,13 +166,13 @@ public final static class InternalInsetsInfo {
165166
* can be touched.
166167
*/
167168
public static final int TOUCHABLE_INSETS_FRAME = 0;
168-
169+
169170
/**
170171
* Option for {@link #setTouchableInsets(int)}: the area inside of
171172
* the content insets can be touched.
172173
*/
173174
public static final int TOUCHABLE_INSETS_CONTENT = 1;
174-
175+
175176
/**
176177
* Option for {@link #setTouchableInsets(int)}: the area inside of
177178
* the visible insets can be touched.
@@ -194,7 +195,7 @@ public void setTouchableInsets(int val) {
194195
}
195196

196197
int mTouchableInsets;
197-
198+
198199
void reset() {
199200
contentInsets.setEmpty();
200201
visibleInsets.setEmpty();
@@ -230,7 +231,7 @@ void set(InternalInsetsInfo other) {
230231
mTouchableInsets = other.mTouchableInsets;
231232
}
232233
}
233-
234+
234235
/**
235236
* Interface definition for a callback to be invoked when layout has
236237
* completed and the client can compute its interior insets.
@@ -327,7 +328,7 @@ public void addOnGlobalFocusChangeListener(OnGlobalFocusChangeListener listener)
327328
checkIsAlive();
328329

329330
if (mOnGlobalFocusListeners == null) {
330-
mOnGlobalFocusListeners = new CopyOnWriteArray<OnGlobalFocusChangeListener>();
331+
mOnGlobalFocusListeners = new CopyOnWriteArrayList<OnGlobalFocusChangeListener>();
331332
}
332333

333334
mOnGlobalFocusListeners.add(listener);
@@ -362,7 +363,7 @@ public void addOnGlobalLayoutListener(OnGlobalLayoutListener listener) {
362363
checkIsAlive();
363364

364365
if (mOnGlobalLayoutListeners == null) {
365-
mOnGlobalLayoutListeners = new CopyOnWriteArray<OnGlobalLayoutListener>();
366+
mOnGlobalLayoutListeners = new CopyOnWriteArrayList<OnGlobalLayoutListener>();
366367
}
367368

368369
mOnGlobalLayoutListeners.add(listener);
@@ -412,7 +413,7 @@ public void addOnPreDrawListener(OnPreDrawListener listener) {
412413
checkIsAlive();
413414

414415
if (mOnPreDrawListeners == null) {
415-
mOnPreDrawListeners = new CopyOnWriteArray<OnPreDrawListener>();
416+
mOnPreDrawListeners = new ArrayList<OnPreDrawListener>();
416417
}
417418

418419
mOnPreDrawListeners.add(listener);
@@ -484,7 +485,7 @@ public void addOnScrollChangedListener(OnScrollChangedListener listener) {
484485
checkIsAlive();
485486

486487
if (mOnScrollChangedListeners == null) {
487-
mOnScrollChangedListeners = new CopyOnWriteArray<OnScrollChangedListener>();
488+
mOnScrollChangedListeners = new CopyOnWriteArrayList<OnScrollChangedListener>();
488489
}
489490

490491
mOnScrollChangedListeners.add(listener);
@@ -518,7 +519,7 @@ public void addOnTouchModeChangeListener(OnTouchModeChangeListener listener) {
518519
checkIsAlive();
519520

520521
if (mOnTouchModeChangeListeners == null) {
521-
mOnTouchModeChangeListeners = new CopyOnWriteArray<OnTouchModeChangeListener>();
522+
mOnTouchModeChangeListeners = new CopyOnWriteArrayList<OnTouchModeChangeListener>();
522523
}
523524

524525
mOnTouchModeChangeListeners.add(listener);
@@ -557,7 +558,7 @@ public void addOnComputeInternalInsetsListener(OnComputeInternalInsetsListener l
557558

558559
if (mOnComputeInternalInsetsListeners == null) {
559560
mOnComputeInternalInsetsListeners =
560-
new CopyOnWriteArray<OnComputeInternalInsetsListener>();
561+
new CopyOnWriteArrayList<OnComputeInternalInsetsListener>();
561562
}
562563

563564
mOnComputeInternalInsetsListeners.add(listener);
@@ -621,16 +622,10 @@ final void dispatchOnGlobalFocusChange(View oldFocus, View newFocus) {
621622
// perform the dispatching. The iterator is a safe guard against listeners that
622623
// could mutate the list by calling the various add/remove methods. This prevents
623624
// the array from being modified while we iterate it.
624-
final CopyOnWriteArray<OnGlobalFocusChangeListener> listeners = mOnGlobalFocusListeners;
625+
final CopyOnWriteArrayList<OnGlobalFocusChangeListener> listeners = mOnGlobalFocusListeners;
625626
if (listeners != null && listeners.size() > 0) {
626-
CopyOnWriteArray.Access<OnGlobalFocusChangeListener> access = listeners.start();
627-
try {
628-
int count = access.size();
629-
for (int i = 0; i < count; i++) {
630-
access.get(i).onGlobalFocusChanged(oldFocus, newFocus);
631-
}
632-
} finally {
633-
listeners.end();
627+
for (OnGlobalFocusChangeListener listener : listeners) {
628+
listener.onGlobalFocusChanged(oldFocus, newFocus);
634629
}
635630
}
636631
}
@@ -645,16 +640,10 @@ public final void dispatchOnGlobalLayout() {
645640
// perform the dispatching. The iterator is a safe guard against listeners that
646641
// could mutate the list by calling the various add/remove methods. This prevents
647642
// the array from being modified while we iterate it.
648-
final CopyOnWriteArray<OnGlobalLayoutListener> listeners = mOnGlobalLayoutListeners;
643+
final CopyOnWriteArrayList<OnGlobalLayoutListener> listeners = mOnGlobalLayoutListeners;
649644
if (listeners != null && listeners.size() > 0) {
650-
CopyOnWriteArray.Access<OnGlobalLayoutListener> access = listeners.start();
651-
try {
652-
int count = access.size();
653-
for (int i = 0; i < count; i++) {
654-
access.get(i).onGlobalLayout();
655-
}
656-
} finally {
657-
listeners.end();
645+
for (OnGlobalLayoutListener listener : listeners) {
646+
listener.onGlobalLayout();
658647
}
659648
}
660649
}
@@ -669,17 +658,17 @@ public final void dispatchOnGlobalLayout() {
669658
*/
670659
@SuppressWarnings("unchecked")
671660
public final boolean dispatchOnPreDraw() {
661+
// NOTE: we *must* clone the listener list to perform the dispatching.
662+
// The clone is a safe guard against listeners that
663+
// could mutate the list by calling the various add/remove methods. This prevents
664+
// the array from being modified while we process it.
672665
boolean cancelDraw = false;
673-
final CopyOnWriteArray<OnPreDrawListener> listeners = mOnPreDrawListeners;
674-
if (listeners != null && listeners.size() > 0) {
675-
CopyOnWriteArray.Access<OnPreDrawListener> access = listeners.start();
676-
try {
677-
int count = access.size();
678-
for (int i = 0; i < count; i++) {
679-
cancelDraw |= !(access.get(i).onPreDraw());
680-
}
681-
} finally {
682-
listeners.end();
666+
if (mOnPreDrawListeners != null && mOnPreDrawListeners.size() > 0) {
667+
final ArrayList<OnPreDrawListener> listeners =
668+
(ArrayList<OnPreDrawListener>) mOnPreDrawListeners.clone();
669+
int numListeners = listeners.size();
670+
for (int i = 0; i < numListeners; ++i) {
671+
cancelDraw |= !(listeners.get(i).onPreDraw());
683672
}
684673
}
685674
return cancelDraw;
@@ -704,17 +693,11 @@ public final void dispatchOnDraw() {
704693
* @param inTouchMode True if the touch mode is now enabled, false otherwise.
705694
*/
706695
final void dispatchOnTouchModeChanged(boolean inTouchMode) {
707-
final CopyOnWriteArray<OnTouchModeChangeListener> listeners =
696+
final CopyOnWriteArrayList<OnTouchModeChangeListener> listeners =
708697
mOnTouchModeChangeListeners;
709698
if (listeners != null && listeners.size() > 0) {
710-
CopyOnWriteArray.Access<OnTouchModeChangeListener> access = listeners.start();
711-
try {
712-
int count = access.size();
713-
for (int i = 0; i < count; i++) {
714-
access.get(i).onTouchModeChanged(inTouchMode);
715-
}
716-
} finally {
717-
listeners.end();
699+
for (OnTouchModeChangeListener listener : listeners) {
700+
listener.onTouchModeChanged(inTouchMode);
718701
}
719702
}
720703
}
@@ -727,16 +710,10 @@ final void dispatchOnScrollChanged() {
727710
// perform the dispatching. The iterator is a safe guard against listeners that
728711
// could mutate the list by calling the various add/remove methods. This prevents
729712
// the array from being modified while we iterate it.
730-
final CopyOnWriteArray<OnScrollChangedListener> listeners = mOnScrollChangedListeners;
713+
final CopyOnWriteArrayList<OnScrollChangedListener> listeners = mOnScrollChangedListeners;
731714
if (listeners != null && listeners.size() > 0) {
732-
CopyOnWriteArray.Access<OnScrollChangedListener> access = listeners.start();
733-
try {
734-
int count = access.size();
735-
for (int i = 0; i < count; i++) {
736-
access.get(i).onScrollChanged();
737-
}
738-
} finally {
739-
listeners.end();
715+
for (OnScrollChangedListener listener : listeners) {
716+
listener.onScrollChanged();
740717
}
741718
}
742719
}
@@ -745,11 +722,11 @@ final void dispatchOnScrollChanged() {
745722
* Returns whether there are listeners for computing internal insets.
746723
*/
747724
final boolean hasComputeInternalInsetsListeners() {
748-
final CopyOnWriteArray<OnComputeInternalInsetsListener> listeners =
725+
final CopyOnWriteArrayList<OnComputeInternalInsetsListener> listeners =
749726
mOnComputeInternalInsetsListeners;
750727
return (listeners != null && listeners.size() > 0);
751728
}
752-
729+
753730
/**
754731
* Calls all listeners to compute the current insets.
755732
*/
@@ -758,105 +735,12 @@ final void dispatchOnComputeInternalInsets(InternalInsetsInfo inoutInfo) {
758735
// perform the dispatching. The iterator is a safe guard against listeners that
759736
// could mutate the list by calling the various add/remove methods. This prevents
760737
// the array from being modified while we iterate it.
761-
final CopyOnWriteArray<OnComputeInternalInsetsListener> listeners =
738+
final CopyOnWriteArrayList<OnComputeInternalInsetsListener> listeners =
762739
mOnComputeInternalInsetsListeners;
763740
if (listeners != null && listeners.size() > 0) {
764-
CopyOnWriteArray.Access<OnComputeInternalInsetsListener> access = listeners.start();
765-
try {
766-
int count = access.size();
767-
for (int i = 0; i < count; i++) {
768-
access.get(i).onComputeInternalInsets(inoutInfo);
769-
}
770-
} finally {
771-
listeners.end();
772-
}
773-
}
774-
}
775-
776-
/**
777-
* Copy on write array. This array is not thread safe, and only one loop can
778-
* iterate over this array at any given time. This class avoids allocations
779-
* until a concurrent modification happens.
780-
*
781-
* Usage:
782-
*
783-
* CopyOnWriteArray.Access<MyData> access = array.start();
784-
* try {
785-
* for (int i = 0; i < access.size(); i++) {
786-
* MyData d = access.get(i);
787-
* }
788-
* } finally {
789-
* access.end();
790-
* }
791-
*/
792-
static class CopyOnWriteArray<T> {
793-
private ArrayList<T> mData = new ArrayList<T>();
794-
private ArrayList<T> mDataCopy;
795-
796-
private final Access<T> mAccess = new Access<T>();
797-
798-
private boolean mStart;
799-
800-
static class Access<T> {
801-
private ArrayList<T> mData;
802-
private int mSize;
803-
804-
T get(int index) {
805-
return mData.get(index);
741+
for (OnComputeInternalInsetsListener listener : listeners) {
742+
listener.onComputeInternalInsets(inoutInfo);
806743
}
807-
808-
int size() {
809-
return mSize;
810-
}
811-
}
812-
813-
CopyOnWriteArray() {
814-
}
815-
816-
private ArrayList<T> getArray() {
817-
if (mStart) {
818-
if (mDataCopy == null) mDataCopy = new ArrayList<T>(mData);
819-
return mDataCopy;
820-
}
821-
return mData;
822-
}
823-
824-
Access<T> start() {
825-
if (mStart) throw new IllegalStateException("Iteration already started");
826-
mStart = true;
827-
mDataCopy = null;
828-
mAccess.mData = mData;
829-
mAccess.mSize = mData.size();
830-
return mAccess;
831-
}
832-
833-
void end() {
834-
if (!mStart) throw new IllegalStateException("Iteration not started");
835-
mStart = false;
836-
if (mDataCopy != null) {
837-
mData = mDataCopy;
838-
}
839-
mDataCopy = null;
840-
}
841-
842-
int size() {
843-
return getArray().size();
844-
}
845-
846-
void add(T item) {
847-
getArray().add(item);
848-
}
849-
850-
void addAll(CopyOnWriteArray<T> array) {
851-
getArray().addAll(array.mData);
852-
}
853-
854-
void remove(T item) {
855-
getArray().remove(item);
856-
}
857-
858-
void clear() {
859-
getArray().clear();
860744
}
861745
}
862746
}

0 commit comments

Comments
 (0)