I ran into a problem with a RecyclerView and I thought you guys can help me. So the problem is: Inflating the item view xml takes too much time. The layout is grid layout with 3 items in a row and each item has a complex UI look.
So first I've used android studio's profiler to analyse it and I saw that the CPU has a significant bump at the point of creation. Even if I remove the entire bind code, It still takes some time when I move into this screen/ scrolling inside the recycler view.
Going into separating the items to smaller items will be crazy because it's already a matrix (3 items in a row as I said).
So I thought about 2 things:
maybe I can create more view holders in advance, any idea how to do that? I saw methods like RecyclerView.setItemViewCacheSize
and LayoutManager.setInitialPrefetchItemCount
but no luck making it happens (it is still calling on create a lot of times)
What about AsyncLayoutInflater? does someone uses it in a RecyclerView?
Any new idea will be great!
This is how the view xml looks like:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
card_view:cardCornerRadius="3dp"
card_view:cardElevation="2.5dp"
card_view:cardUseCompatPadding="true">
<CustomView1>
</CustomView1>
<CustomView2>
</CustomView2>
<CustomView3>
</CustomView3>
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="30dp"
android:layout_gravity="end"
android:layout_marginEnd="2dp"
android:layout_marginStart="2dp"
android:layout_marginTop="2dp"
android:adjustViewBounds="true" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<include layout="@layout/someLayoutToInclude" />
</android.support.v7.widget.CardView>
</FrameLayout>
OnCreateViewHolder looks like:
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
View view = layoutInflater.inflate(viewType, parent, false);
return new ItemViewHolder(view);
Grid Layout initialization:
final GridLayoutManager gridLayoutManager = new GridLayoutManager(getContext(), 3);
gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
return 1;
}
});
Thanks
Here is the solution I did at the end: As I mentioned, my issue was that onCreateViewHolder, creates a complex view with a huge hierarchy that cannot be changed (product-wise), and I had 3 items in a row(GridLayoutManager)
Because of that, I had 2 things that worked bad:
So what I did is:
As I mentioned above , there's an AsyncLayoutInflater. In order to use it, I needed to inflate a dummy ViewGroup, and after that to add the async inflated view to this dummy view. Of course some extra logic should be done for supporting onBindViewHolder.
public ItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
View view = layoutInflater.inflate(R.layout.async_holder_item, parent, false);
AsyncLayoutInflater asyncLayoutInflater = new AsyncLayoutInflater(parent.getContext());
asyncLayoutInflater.inflate(viewType, (ViewGroup) view, new AsyncLayoutInflater.OnInflateFinishedListener() {
@Override
public void onInflateFinished(@NonNull View view, int resid, @Nullable ViewGroup parent) {
parent.addView(view);
}
});
return new ItemViewHolder(view, viewType);
}
You can also use a shimmer or loading state at the dummy view (keep the layout simple!) and add android:animateLayoutChanges="true" to the top view group to make it smoother
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With