0

I'm trying to make Recyclerview like Shareit app. It uses sticky header and something like Cardview. I searched and found somethings for implementing sticky header with itemdecoration and it's okay. But for Cardview part, I tried to make nested Recyclerview but performance was so bad, Because using two vertical Recyclerview is not good at all. Is there any better way to achieve this? The problem with performance is for when i scroll down. It makes lag on creating second item in parent Recyclerview.

enter image description here

AppheaderAdapter:

    @Override
    public AppHeaderAdapter.HeaderHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        final View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_media_header, parent, false);
        HeaderHolder headerHolder = new HeaderHolder(view);
        return headerHolder;
    }

class HeaderHolder extends RecyclerView.ViewHolder { //story
        final ImageView arrow;
        final TextView tarikh;
        final TextView tedad;
        final CheckBox tick;
        final RecyclerView item_recyc;

        HeaderHolder(View itemView) {
            super(itemView);

            arrow = itemView.findViewById(R.id.header_arrow);
            tarikh = itemView.findViewById(R.id.header_tarikh);
            tedad = itemView.findViewById(R.id.header_tedad);
            tick = itemView.findViewById(R.id.header_tick);
            item_recyc = itemView.findViewById(R.id.header_recyc);
        }
    }

@Override
    public void onBindViewHolder(@NonNull AppHeaderAdapter.HeaderHolder headerHolder, int position) {
        final AppHeader appHeader = appHeaders.get(position);

        ...

        GridLayoutManager gridLayoutManager = new GridLayoutManager(context, span);
        gridLayoutManager.setRecycleChildrenOnDetach(true);
        headerHolder.item_recyc.setLayoutManager(gridLayoutManager);
        headerHolder.item_recyc.setNestedScrollingEnabled(false);

        AppItemAdapter adapter = new AppItemAdapter(context, appHeader.getAppList(), fr_parent, width);
        headerHolder.item_recyc.swapAdapter(adapter, true);

        ...
    }

item_media_header.xml:

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/header_container"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="10dp"
    android:background="@drawable/so_round_so_white"
    app:cardCornerRadius="10dp"
    app:cardElevation="5dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <ImageView
                android:id="@+id/header_arrow"
                android:layout_width="30dp"
                android:layout_height="30dp"
                android:padding="8dp"
                android:src="@drawable/header_arrow"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintLeft_toLeftOf="parent"
                app:layout_constraintTop_toTopOf="parent" />

            <TextView
                android:id="@+id/header_tarikh"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textSize="@dimen/fragment_file"
                android:textStyle="bold"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintLeft_toRightOf="@id/header_arrow"
                app:layout_constraintTop_toTopOf="parent" />

            <TextView
                android:id="@+id/header_tedad"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="2dp"
                android:textColor="#AAAAAA"
                android:textSize="@dimen/fragment_file"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintLeft_toRightOf="@id/header_tarikh"
                app:layout_constraintTop_toTopOf="parent" />

            <CheckBox
                android:id="@+id/header_tick"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginRight="10dp"
                android:button="@null"
                android:clickable="false"
                android:drawableRight="@drawable/file_checkbox"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintRight_toRightOf="parent"
                app:layout_constraintTop_toTopOf="parent" />
        </androidx.constraintlayout.widget.ConstraintLayout>

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/header_recyc"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </LinearLayout>
</androidx.cardview.widget.CardView>

EDIT 1: I find that just first Cardview is loaded and second one is not loaded until I scroll to end of first one and then load second CardView item and it lags because of second RecyclerView. I found that Shareit use previous created adapter and just change its internal datalist, So i do that, but still has lag on second item.

Edite 2: I use one time created adapter on all RecyclerView but still has lag.

Edit 3: It's a known bug that innerRecyclerView load all items at first and that cause my lag too. because inner Recyclerview is inside NestedScrollView (RV) and it loads all content.Using constant height doesn't work, But I'll update question if I find something better.

  • `I tried to make nested Recyclerview but performance was so bad`. How performance was bad? It's exactly this is done for these cases. – Praveen May 24 '22 at 09:58
  • The performance problem is certainly due to the nested RecycleView. You should think about doing `RecyclerView.setNestedScrollingEnabled(false)` on the child `RecyclerView` in your `ViewHolder` – logancodemaker May 24 '22 at 10:05
  • @Praveen The problem with performance is for when i scroll down. It makes lag on creating second item in parent Recyclerview. –  May 24 '22 at 10:55
  • @logancodemaker The problem with performance is for when i scroll down. It makes lag on creating second item in parent Recyclerview. but I try your suggestion and update question. –  May 24 '22 at 10:56
  • @forootan please share you code for betting support – logancodemaker May 24 '22 at 11:01
  • @logancodemaker i updated question and add video from my app. –  May 24 '22 at 12:54

2 Answers2

0

You can achieve this with ConstraintLayout and Flow.

EDIT: Sorry, I just realised I wrote everything in Kotlin. If you cannot understand something I can try to translate it to Java.

xml:

 <androidx.constraintlayout.widget.ConstraintLayout 
        android:id="@+id/constraintLayout"
        ...>

        <androidx.constraintlayout.helper.widget.Flow
            android:id="@+id/flow"
            app:flow_wrapMode="aligned"
            app:flow_horizontalStyle="spread_inside"
            app:flow_maxElementsWrap="4"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>

Adding of items:

val constraintLayout = itemView.findViewById(R.id.constraintLayout)
val flow = itemView.findViewById(R.id.flow)
val items // items given to the viewHolder to display

val layoutInflater = LayoutInflater.from(context)

items.forEach { item ->
        val view = // create item view, e.g. DataBinding, ...
        view.id = ViewCompat.generateViewId()         
        constraintLayout.addView(root)
        flow.addView(root)
    }
}

// if there are less than 4 items you have to add invisible dummy items. Otherwise, the alignment will look different for these ViewHolders

if(items.size>=4) return

for (i in 0..(4-items.size)) {
        val view = // create dummy view
        view.id = ViewCompat.generateViewId()         
        constraintLayout.addView(root)
        flow.addView(root)
}


Daniel Knauf
  • 559
  • 3
  • 11
  • Hi and thank you for your answer, I am ok with kotlin. But what about Pictures and Videos tab? There are thousand of `CardView` and make all of them and add them take a lot of time and memory. also it has sticky header for `CardView` item that i think is possible only via `RecyclerView`. Am i right? –  May 25 '22 at 05:47
  • Yes, I meant a `ConstraintLayout` instead of the `RecyclerView` inside each `CardView` to display entries (icon, name, size). – Daniel Knauf May 25 '22 at 11:21
  • it's not about inner item layout. But It's about not loading parent `RecyclerView` properly and loading all item at once in inner `RecyclerView`. I updated question. Unfortunately add view manually is not good idea for all files and it makes lags alot –  May 25 '22 at 11:40
0

So far, Using vertical RV inside vertical RV has bug. Because of inner RV make long height and outer RV has no idea of this, So it create just first Item, but all items in inner RV. using all solution on Stack O.F. had no effect!