Merge "Ensure AdapterView doesn't post selection notifications forever" into lmp-mr1-dev

This commit is contained in:
Alan Viverette
2014-10-23 00:04:03 +00:00
committed by Android (Google) Code Review

View File

@@ -215,7 +215,12 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup {
private boolean mDesiredFocusableState; private boolean mDesiredFocusableState;
private boolean mDesiredFocusableInTouchModeState; private boolean mDesiredFocusableInTouchModeState;
/** Lazily-constructed runnable for dispatching selection events. */
private SelectionNotifier mSelectionNotifier; private SelectionNotifier mSelectionNotifier;
/** Selection notifier that's waiting for the next layout pass. */
private SelectionNotifier mPendingSelectionNotifier;
/** /**
* When set to true, calls to requestLayout() will not propagate up the parent hierarchy. * When set to true, calls to requestLayout() will not propagate up the parent hierarchy.
* This is used to layout the children during a layout pass. * This is used to layout the children during a layout pass.
@@ -854,39 +859,50 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup {
private class SelectionNotifier implements Runnable { private class SelectionNotifier implements Runnable {
public void run() { public void run() {
mPendingSelectionNotifier = null;
if (mDataChanged) { if (mDataChanged) {
// Data has changed between when this SelectionNotifier // Data has changed between when this SelectionNotifier was
// was posted and now. We need to wait until the AdapterView // posted and now. Postpone the notification until the next
// has been synched to the new data. // layout is complete and we run checkSelectionChanged().
if (getAdapter() != null) { if (getAdapter() != null) {
post(this); mPendingSelectionNotifier = this;
} }
} else { } else {
fireOnSelected(); dispatchOnItemSelected();
performAccessibilityActionsOnSelected();
} }
} }
} }
void selectionChanged() { void selectionChanged() {
// We're about to post or run the selection notifier, so we don't need
// a pending notifier.
mPendingSelectionNotifier = null;
if (mOnItemSelectedListener != null if (mOnItemSelectedListener != null
|| AccessibilityManager.getInstance(mContext).isEnabled()) { || AccessibilityManager.getInstance(mContext).isEnabled()) {
if (mInLayout || mBlockLayoutRequests) { if (mInLayout || mBlockLayoutRequests) {
// If we are in a layout traversal, defer notification // If we are in a layout traversal, defer notification
// by posting. This ensures that the view tree is // by posting. This ensures that the view tree is
// in a consistent state and is able to accomodate // in a consistent state and is able to accommodate
// new layout or invalidate requests. // new layout or invalidate requests.
if (mSelectionNotifier == null) { if (mSelectionNotifier == null) {
mSelectionNotifier = new SelectionNotifier(); mSelectionNotifier = new SelectionNotifier();
} else {
removeCallbacks(mSelectionNotifier);
} }
post(mSelectionNotifier); post(mSelectionNotifier);
} else { } else {
fireOnSelected(); dispatchOnItemSelected();
performAccessibilityActionsOnSelected();
} }
} }
} }
private void dispatchOnItemSelected() {
fireOnSelected();
performAccessibilityActionsOnSelected();
}
private void fireOnSelected() { private void fireOnSelected() {
if (mOnItemSelectedListener == null) { if (mOnItemSelectedListener == null) {
return; return;
@@ -1042,12 +1058,22 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup {
notifySubtreeAccessibilityStateChangedIfNeeded(); notifySubtreeAccessibilityStateChangedIfNeeded();
} }
/**
* Called after layout to determine whether the selection position needs to
* be updated. Also used to fire any pending selection events.
*/
void checkSelectionChanged() { void checkSelectionChanged() {
if ((mSelectedPosition != mOldSelectedPosition) || (mSelectedRowId != mOldSelectedRowId)) { if ((mSelectedPosition != mOldSelectedPosition) || (mSelectedRowId != mOldSelectedRowId)) {
selectionChanged(); selectionChanged();
mOldSelectedPosition = mSelectedPosition; mOldSelectedPosition = mSelectedPosition;
mOldSelectedRowId = mSelectedRowId; mOldSelectedRowId = mSelectedRowId;
} }
// If we have a pending selection notification -- and we won't if we
// just fired one in selectionChanged() -- run it now.
if (mPendingSelectionNotifier != null) {
mPendingSelectionNotifier.run();
}
} }
/** /**