Merge "Ensure AdapterView doesn't post selection notifications forever" into lmp-mr1-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
183cef06df
@@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user