RecyclerView 嵌套 RecyclerView,第一次滚动卡顿。

3

我有一个 Recyclerview,其中包含多个视图类型,并且在 Recyclerview 中有另一个 Recyclerview。当第一次滚动时出现滞后,我不知道为什么会出现滚动滞后。

这是我的片段布局:

<?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>

这是我的片段

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

这是我的适配器:

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
}

这是我的布局容器。
<?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>

这是我的RecyclerView中的holder recyclerView

(将html标签保留)
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
        )
    }
}

我的问题是:当我第一次滚动RecyclerView时,它不够流畅,并且logcat显示RecyclerView跳过了51帧!适配器。但当我到达RecyclerView的末尾并向上滚动,然后向下滚动时,它非常流畅,而我的RecyclerView只有TextView !!! 我该如何解决这个问题?

这是我的视频应用程序:https://youtu.be/Li7aKWmEfXQ

3个回答

1
在应用LayoutManager后,在您的片段中添加以下内容:
lottoRecyclerView.setDrawingCacheEnabled(true);
lottoRecyclerView.setItemViewCacheSize(myCacheSize);

谢谢,我尽力了,但我的情况还没有解决。 - Yothin Homjan

1
主要原因是Jank在第一次加载内存动态值时发生,而一旦它下降了,它已经预先加载了一些元素。您可以使用以下方式处理它:
mRecyclerView.setHasFixedSize(true); 
mRecyclerview.setNestedScrollingEnabled(false);

在你的 Kotlin 代码中,或者在你的 RecyclerView 的 xml 中添加 android:nestedScrollingEnabled="false"

0

您可以通过以下方式实现一些性能改进:

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

..与地图视图的精简模式结合使用:

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

因为禁用nestedScrollingEnabled并不是一个选项,正如@Narendra_Nath所提到的那样,这进一步提高了性能。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接