Yothin Homjan
Yothin Homjan

Reputation: 41

Recyclerview in Recyclerview scrolling first time laggy

I have Recyclerview multiple view types and have Recyclerview in Recyclerview when scroll lag first time I do not know why scroll lag first time

here my layout fragment

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/coordinatorLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".presentation.LottoFragment">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/teal_700"
        android:padding="20dp">

        <LinearLayout
            android:id="@+id/searchLinearLayout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent">

            <com.google.android.material.textfield.TextInputLayout
                android:id="@+id/menuTextInputLayout"
                style="@style/Widget.MaterialComponents.TextInputLayout.FilledBox.ExposedDropdownMenu"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="@string/label">

                <AutoCompleteTextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:inputType="none" />

            </com.google.android.material.textfield.TextInputLayout>

        </LinearLayout>

    </androidx.constraintlayout.widget.ConstraintLayout>

    <LinearLayout
        android:id="@+id/contentLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:behavior_peekHeight="56dp"
        app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/ic_list_header_background"
            android:clickable="true"
            android:elevation="4dp"
            android:orientation="horizontal"
            android:padding="20dp">

            <TextView
                android:id="@+id/lotto_text_view"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:fontFamily="@font/kanit_light"
                android:text="0 items(s)" />

            <ImageView
                android:id="@+id/filterIcon"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="end"
                android:src="@android:drawable/arrow_up_float"
                android:visibility="gone" />

        </LinearLayout>

        <LinearLayout
            android:id="@+id/front_layer_linear_layout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@android:color/white"
            android:orientation="vertical">

            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/lotto_recycler_view"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:clipToPadding="false"
                android:paddingBottom="64dp"
                tools:itemCount="3"
                tools:listitem="@layout/item_lotto_prizes_one" />

        </LinearLayout>
    </LinearLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

here my fragment

 lottoRecyclerView.apply {
            layoutManager = LinearLayoutManager(context)
            adapter = lottoLatestAdapter
        }

here my Adapter:

class LottoLatestAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

    companion object {
        private const val VIEW_TYPE_LOTTO_PRIZE_ONE = 1
        private const val VIEW_TYPE_LOTTO_PRIZE_RUNNING_NUMBER = 2
        private const val VIEW_TYPE_LOTTO_PRIZE_ONE_NEAR = 3
        private const val VIEW_TYPE_LOTTO_PRIZE_OTHER = 4
    }
    var latestList: MutableList<LottoPrizesLatestModel> = mutableListOf()
        set(value) {
            field = value
            notifyDataSetChanged()
        }

    private val viewPool : RecycledViewPool = RecycledViewPool()

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        val inflater = LayoutInflater.from(parent.context)
        return when (viewType) {
            VIEW_TYPE_LOTTO_PRIZE_ONE -> {
                LottoPrizeOneHolder(ItemLottoPrizesOneBinding.inflate(inflater, parent, false))
            }
            VIEW_TYPE_LOTTO_PRIZE_RUNNING_NUMBER -> {
                LottoPrizeRunningNumberHolder(
                    ItemLottoRunningNumbersBinding.inflate(
                        inflater,
                        parent,
                        false
                    )
                )
            }
            VIEW_TYPE_LOTTO_PRIZE_ONE_NEAR -> {
                LottoPrizeOneNearHolder(
                    ItemLottoPrizesOneNearBinding.inflate(
                        inflater,
                        parent,
                        false
                    )
                )
            }
            VIEW_TYPE_LOTTO_PRIZE_OTHER -> {
                LottoPrizeOtherListHolder(
                    ItemLottoPrizesOtherListBinding.inflate(
                        inflater,
                        parent,
                        false
                    ),
                    LottoLatestPrizeOtherAdapter()
                )
            }
            else -> throw NullPointerException("Not have view Type")
        }
    }

    override fun getItemViewType(position: Int): Int {
        return when (latestList[position]) {
            is LottoPrizesLatestModel.LottoLatestPrizeOne -> VIEW_TYPE_LOTTO_PRIZE_ONE
            is LottoPrizesLatestModel.LottoLatestRunningNumbers -> VIEW_TYPE_LOTTO_PRIZE_RUNNING_NUMBER
            is LottoPrizesLatestModel.LottoLatestPrizeFirstNear -> VIEW_TYPE_LOTTO_PRIZE_ONE_NEAR
            is LottoPrizesLatestModel.LottoLatestPrizeOther -> VIEW_TYPE_LOTTO_PRIZE_OTHER
        }
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        when (holder) {
            is LottoPrizeOneHolder -> holder.bind(latestList[position] as LottoPrizesLatestModel.LottoLatestPrizeOne)

            is LottoPrizeRunningNumberHolder -> holder.bind(latestList[position] as LottoPrizesLatestModel.LottoLatestRunningNumbers)

            is LottoPrizeOneNearHolder -> holder.bind(latestList[position] as LottoPrizesLatestModel.LottoLatestPrizeFirstNear)

            is LottoPrizeOtherListHolder -> {
                viewPool.putRecycledView(holder)
                holder.bind(latestList[position] as LottoPrizesLatestModel.LottoLatestPrizeOther, viewPool)
            }

        }
    }

    override fun getItemCount(): Int = latestList.size
}

here my layout holder

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="8dp">

    <TextView
        android:id="@+id/title_prize_other_text_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:fontFamily="@font/kanit_light"
        android:gravity="center"
        android:textSize="26sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/prize_other_recycler_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:clipToPadding="false"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/title_prize_other_text_view"
        tools:itemCount="10"
        tools:listitem="@layout/item_lotto_prizes_other" />

    <GridLayout
        android:id="@+id/prize_other_grip_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:columnCount="2"
        android:orientation="vertical"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/title_prize_other_text_view" />

    <TextView
        android:id="@+id/text_prize_one_near_text_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:fontFamily="@font/kanit_light"
        android:text="@string/lotto_prize_per_baht"
        android:textSize="16sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/prize_other_recycler_view" />

</androidx.constraintlayout.widget.ConstraintLayout>

and here my holder recyclerView in RecyclerView

class LottoPrizeOtherListHolder(
    private val binding: ItemLottoPrizesOtherListBinding,
    private val lottoLatestPrizeOtherAdapter: LottoLatestPrizeOtherAdapter
) :
    RecyclerView.ViewHolder(binding.root) {

    fun bind(
        lottoLatestPrizeOther: LottoPrizesLatestModel.LottoLatestPrizeOther,
        viewPool: RecyclerView.RecycledViewPool
    ) = with(binding) {

        prizeOtherRecyclerView.apply {
            layoutManager = GridLayoutManager(
                context,
                2,
                GridLayoutManager.VERTICAL,
                false
            ).apply {
                initialPrefetchItemCount = lottoLatestPrizeOther.prizeModel.number.size
            }
            this.adapter = lottoLatestPrizeOtherAdapter
            setRecycledViewPool(viewPool)
        }
        lottoLatestPrizeOtherAdapter.numberList =
            lottoLatestPrizeOther.prizeModel.number.toMutableList()
        titlePrizeOtherTextView.text = lottoLatestPrizeOther.prizeModel.name
        textPrizeOneNearTextView.text = itemView.context.getString(
            R.string.lotto_prize_per_baht,
            lottoLatestPrizeOther.prizeModel.reward
        )
    }
}

my problem is : When i scroll recyclerview for first time it is not smooth and logcat show recyclerview Skipped 51 frames! adapter but when I reach end of recyclerView and scroll to up then scroll down it is very smooth and my recyclerview have TextView Only !!! how can I solve this issue?

this my video App https://youtu.be/Li7aKWmEfXQ

Upvotes: 3

Views: 2243

Answers (3)

goemic
goemic

Reputation: 1339

You can reach some performance improvements by applying the following:

recyclerView.setHasFixedSize(true);
recyclerView.setDrawingCacheEnabled(true);

..in combination with lite mode of MapsView:

<com.google.android.gms.maps.MapView
        android:layout_width="match_parent"
        android:layout_height="200dp"
        app:liteMode="true"
        app:mapType="normal" />

For it was not an option to disable nestedScrollingEnabled as mentioned by @Narendra_Nath, which further improves performance.

Upvotes: 0

Narendra_Nath
Narendra_Nath

Reputation: 5185

The main reason Jank occurs the first time because on the first time it is loading the values onto memory dynamically. while once it is down it already has a few elements pre loaded

You can handle it using

mRecyclerView.setHasFixedSize(true); 
mRecyclerview.setNestedScrollingEnabled(false);

in your kotlin code

or add android:nestedScrollingEnabled="false" in your RecyclerView xml

Upvotes: 1

In your fragment add this after applying LayoutManager:

lottoRecyclerView.setDrawingCacheEnabled(true);
lottoRecyclerView.setItemViewCacheSize(myCacheSize);

Upvotes: 1

Related Questions