Fix scrollbar keeping a reference to the adapter
There was a NPE, and a memory leak because of an observer to adapter
data changes was not unregistered.
Fix: 175603917
Test: manual
Change-Id: I287ba6c651427d6a89a4f327fee23113d3b6c639
Merged-In: I4c649c59236bf406ae721092de3984b84cb8f1ac
diff --git a/car-ui-lib/src/com/android/car/ui/recyclerview/CarUiRecyclerView.java b/car-ui-lib/src/com/android/car/ui/recyclerview/CarUiRecyclerView.java
index 36ed154..ee1257f 100644
--- a/car-ui-lib/src/com/android/car/ui/recyclerview/CarUiRecyclerView.java
+++ b/car-ui-lib/src/com/android/car/ui/recyclerview/CarUiRecyclerView.java
@@ -490,6 +490,16 @@
removeItemDecoration(mDividerItemDecorationGrid);
}
+ @Override
+ public void setAdapter(@Nullable Adapter adapter) {
+ if (mScrollBar != null) {
+ // Make sure this is called before super so that scrollbar can get a reference to
+ // the adapter using RecyclerView#getAdapter()
+ mScrollBar.adapterChanged(adapter);
+ }
+ super.setAdapter(adapter);
+ }
+
private static RuntimeException andLog(String msg, Throwable t) {
Log.e(TAG, msg, t);
throw new RuntimeException(msg, t);
diff --git a/car-ui-lib/src/com/android/car/ui/recyclerview/DefaultScrollBar.java b/car-ui-lib/src/com/android/car/ui/recyclerview/DefaultScrollBar.java
index fec2618..326c569 100644
--- a/car-ui-lib/src/com/android/car/ui/recyclerview/DefaultScrollBar.java
+++ b/car-ui-lib/src/com/android/car/ui/recyclerview/DefaultScrollBar.java
@@ -134,6 +134,22 @@
mScrollView.getPaddingRight(), paddingEnd);
}
+ @Override
+ public void adapterChanged(@Nullable RecyclerView.Adapter adapter) {
+ try {
+ if (mRecyclerView.getAdapter() != null) {
+ mRecyclerView.getAdapter().unregisterAdapterDataObserver(mAdapterChangeObserver);
+ }
+ if (adapter != null) {
+ adapter.registerAdapterDataObserver(mAdapterChangeObserver);
+ }
+ } catch (IllegalStateException e) {
+ // adapter is already registered. and we're trying to register again.
+ // or adapter was not registered and we're trying to unregister again.
+ // ignore.
+ }
+ }
+
/**
* Sets whether or not the up button on the scroll bar is clickable.
*
@@ -301,27 +317,12 @@
}
}
- private boolean mIsAdapterChangeObserverRegistered = false;
- @Nullable
- private RecyclerView.Adapter mCurrentAdapter;
private final RecyclerView.OnScrollListener mRecyclerViewOnScrollListener =
new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
updatePaginationButtons(false);
cacheChildrenHeight(recyclerView.getLayoutManager());
- if (mCurrentAdapter != recyclerView.getAdapter()) {
- mIsAdapterChangeObserverRegistered = false;
- if (mCurrentAdapter != null) {
- mCurrentAdapter.unregisterAdapterDataObserver(mAdapterChangeObserver);
- }
- }
- if (!mIsAdapterChangeObserverRegistered
- && recyclerView.getAdapter() != null) {
- mIsAdapterChangeObserverRegistered = true;
- mCurrentAdapter = recyclerView.getAdapter();
- mCurrentAdapter.registerAdapterDataObserver(mAdapterChangeObserver);
- }
}
};
private final SparseArray<Integer> mChildHeightByAdapterPosition = new SparseArray();
@@ -359,7 +360,10 @@
cacheChildrenHeight(mRecyclerView.getLayoutManager());
}
- private void cacheChildrenHeight(RecyclerView.LayoutManager layoutManager) {
+ private void cacheChildrenHeight(@Nullable RecyclerView.LayoutManager layoutManager) {
+ if (layoutManager == null) {
+ return;
+ }
for (int i = 0; i < layoutManager.getChildCount(); i++) {
View child = layoutManager.getChildAt(i);
int childPosition = layoutManager.getPosition(child);
diff --git a/car-ui-lib/src/com/android/car/ui/recyclerview/ScrollBar.java b/car-ui-lib/src/com/android/car/ui/recyclerview/ScrollBar.java
index ce58897..069238d 100644
--- a/car-ui-lib/src/com/android/car/ui/recyclerview/ScrollBar.java
+++ b/car-ui-lib/src/com/android/car/ui/recyclerview/ScrollBar.java
@@ -39,4 +39,9 @@
/** Sets the padding of the scrollbar, relative to the padding of the RecyclerView. */
void setPadding(int padddingStart, int paddingEnd);
+
+ /**
+ * Called when recyclerview's setAdapter is called.
+ */
+ void adapterChanged(RecyclerView.Adapter adapter);
}