From 4dbc4a7ed3fa503e3d5bfe0cbdf344b0e2f0a0c5 Mon Sep 17 00:00:00 2001
From: Craig Stout
Date: Wed, 3 Sep 2014 10:14:02 -0700
Subject: Fix memory leak when fast scrolling rows.
If a presenter starts a view property animation, then the parent row view
will have transient state which may cause a row to fail to be recycled
during a fast scroll, because RecyclerView checks transient state and
refuses to recycle a view if it or its children has running view property
animation.
This can cause a memory leak because ObjectAdapters have references to
ItemBridgeAdapters via the registered observer mechanism.
Apps should clear any view property animations in Presenter
onViewDetachedFromWindow, but in case they don't we'll do it for them in
the base class.
b/17013302
Change-Id: Ibdf5998e81dd130128f88f85d88243ec27a70dd5
---
.../support/v17/leanback/widget/ImageCardView.java | 7 +++++++
.../v17/leanback/widget/ListRowPresenter.java | 5 +++--
.../support/v17/leanback/widget/Presenter.java | 20 ++++++++++++++++++++
.../support/v17/leanback/widget/RowPresenter.java | 1 +
4 files changed, 31 insertions(+), 2 deletions(-)
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ImageCardView.java b/v17/leanback/src/android/support/v17/leanback/widget/ImageCardView.java
index fb131e0aa1..aa9e3f846e 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/ImageCardView.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ImageCardView.java
@@ -234,4 +234,11 @@ public class ImageCardView extends BaseCardView {
mTitleView.setMaxLines(1);
}
}
+
+ @Override
+ protected void onDetachedFromWindow() {
+ mImageView.animate().cancel();
+ mImageView.setAlpha(1f);
+ super.onDetachedFromWindow();
+ }
}
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ListRowPresenter.java b/v17/leanback/src/android/support/v17/leanback/widget/ListRowPresenter.java
index c13f48a365..8940352390 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/ListRowPresenter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ListRowPresenter.java
@@ -412,14 +412,15 @@ public class ListRowPresenter extends RowPresenter {
super.onBindRowViewHolder(holder, item);
ViewHolder vh = (ViewHolder) holder;
ListRow rowItem = (ListRow) item;
- vh.mItemBridgeAdapter.clear();
vh.mItemBridgeAdapter.setAdapter(rowItem.getAdapter());
vh.mGridView.setAdapter(vh.mItemBridgeAdapter);
}
@Override
protected void onUnbindRowViewHolder(RowPresenter.ViewHolder holder) {
- ((ViewHolder) holder).mGridView.setAdapter(null);
+ ViewHolder vh = (ViewHolder) holder;
+ vh.mGridView.setAdapter(null);
+ vh.mItemBridgeAdapter.clear();
super.onUnbindRowViewHolder(holder);
}
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/Presenter.java b/v17/leanback/src/android/support/v17/leanback/widget/Presenter.java
index ed7714d8b7..9a2b0bf7bc 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/Presenter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/Presenter.java
@@ -103,9 +103,29 @@ public abstract class Presenter {
* the consumer of an presenter's views may choose to cache views offscreen while they
* are not visible, attaching an detaching them as appropriate.
*
+ * Any view property animations should be cancelled here or the view may fail
+ * to be recycled.
+ *
* @param holder Holder of the view being detached
*/
public void onViewDetachedFromWindow(ViewHolder holder) {
+ // If there are view property animations running then RecyclerView won't recycle.
+ cancelAnimationsRecursive(holder.view);
+ }
+
+ /**
+ * Utility method for removing all running animations on a view.
+ */
+ protected static void cancelAnimationsRecursive(View view) {
+ if (view.hasTransientState()) {
+ view.animate().cancel();
+ if (view instanceof ViewGroup) {
+ final int count = ((ViewGroup) view).getChildCount();
+ for (int i = 0; view.hasTransientState() && i < count; i++) {
+ cancelAnimationsRecursive(((ViewGroup) view).getChildAt(i));
+ }
+ }
+ }
}
/**
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/RowPresenter.java b/v17/leanback/src/android/support/v17/leanback/widget/RowPresenter.java
index 27f1975b4e..1c7ed3ddf6 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/RowPresenter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/RowPresenter.java
@@ -415,6 +415,7 @@ public abstract class RowPresenter extends Presenter {
if (vh.mHeaderViewHolder != null) {
mHeaderPresenter.onViewDetachedFromWindow(vh.mHeaderViewHolder);
}
+ cancelAnimationsRecursive(vh.view);
}
/**
--
cgit v1.2.3
From b43872b3b32cf208089c8b88e67e433653084ba5 Mon Sep 17 00:00:00 2001
From: Dake Gu
Date: Tue, 9 Sep 2014 14:27:27 -0700
Subject: fix grey panel on top of settings
Bug introduced because changed layout of headers fragment.
b/17436246
Change-Id: Ie46673099894ceb3b64513b2d0ba315fdccbb2a4
---
v17/leanback/src/android/support/v17/leanback/app/HeadersFragment.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/v17/leanback/src/android/support/v17/leanback/app/HeadersFragment.java b/v17/leanback/src/android/support/v17/leanback/app/HeadersFragment.java
index 288640c1b8..6225a59c0a 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/HeadersFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/HeadersFragment.java
@@ -139,7 +139,7 @@ public class HeadersFragment extends BaseRowFragment {
private void updateListViewVisibility() {
final VerticalGridView listView = getVerticalGridView();
if (listView != null) {
- listView.setVisibility(mHeadersGone ? View.GONE : View.VISIBLE);
+ getView().setVisibility(mHeadersGone ? View.GONE : View.VISIBLE);
if (!mHeadersGone) {
if (mHeadersEnabled) {
listView.setChildrenVisibility(View.VISIBLE);
--
cgit v1.2.3