From c3a97eece385d93a85a215281ef48bdea728af0b Mon Sep 17 00:00:00 2001 From: Ajay Nadathur Date: Tue, 16 Aug 2016 16:38:20 -0700 Subject: [PATCH] [SetupWizard] Setup Wizard crash on scrolling the list in Select Wi-Fi screen - Setupwizard was crashing because RecyclerView during keyboard scrolls invokes onCreateViewHolder(ViewGroup, int) for header view more than once. We return the same headerView object each time which causes problems later on. - Fixed the problem by wrapping the header in a framelayout and inserting the header to the current framelayout in onBindViewHeader(ViewHolder, int). Testing: ------- - Verified by running on Pixel C, no crashes observed - Also attempted scrolling using touchscreen, works as usual. bug:30789424 Change-Id: I89ac09e14f21ceec3628f249f2cd2a391f020072 --- .../view/HeaderRecyclerView.java | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/library/full-support/src/com/android/setupwizardlib/view/HeaderRecyclerView.java b/library/full-support/src/com/android/setupwizardlib/view/HeaderRecyclerView.java index e0c0e46..29329b4 100644 --- a/library/full-support/src/com/android/setupwizardlib/view/HeaderRecyclerView.java +++ b/library/full-support/src/com/android/setupwizardlib/view/HeaderRecyclerView.java @@ -25,6 +25,7 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.accessibility.AccessibilityEvent; +import android.widget.FrameLayout; import com.android.setupwizardlib.DividerItemDecoration; import com.android.setupwizardlib.R; @@ -102,8 +103,21 @@ public class HeaderRecyclerView extends RecyclerView { @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + /* + * Returning the same view (mHeader) results in crash ".. but view is not a real child." + * The framework creates more than one instance of header because of "disappear" + * animations applied on the header and this necessitates creation of another headerview + * to use after the animation. We work around this restriction by returning an empty + * framelayout to which the header is attached using #onBindViewHolder method. + */ if (viewType == HEADER_VIEW_TYPE) { - return new HeaderViewHolder(mHeader); + FrameLayout frameLayout = new FrameLayout(parent.getContext()); + FrameLayout.LayoutParams params = new FrameLayout.LayoutParams( + FrameLayout.LayoutParams.MATCH_PARENT, + FrameLayout.LayoutParams.WRAP_CONTENT + ); + frameLayout.setLayoutParams(params); + return new HeaderViewHolder(frameLayout); } else { return mAdapter.onCreateViewHolder(parent, viewType); } @@ -115,7 +129,14 @@ public class HeaderRecyclerView extends RecyclerView { if (mHeader != null) { position--; } - if (position >= 0) { + + if (holder instanceof HeaderViewHolder) { + if (mHeader.getParent() != null) { + ((ViewGroup) mHeader.getParent()).removeView(mHeader); + } + FrameLayout mHeaderParent = (FrameLayout) holder.itemView; + mHeaderParent.addView(mHeader); + } else { mAdapter.onBindViewHolder(holder, position); } }