2

我正在使用带有流的 Paging 3 来填充我的 RecyclerView,我单击一个项目并转到详细信息页面并为该项目投票,这会将 1 添加到 ViewHolder 中可见的计数器。

一切都正确填充,当我从详细信息页面返回主屏幕时,我已经刷新,但是当使用数据更新时,该项目和其他一些项目会闪烁。

我的问题是,当我更新时,我赞成的项目会完全闪烁,通常使用 recylerview 适配器我会将稳定的 ID 设置为 true,但是你不能使用 PagingDataAdapter 来做到这一点,我认为这可能是使用 Glide 但整个 ViewHolder 会刷新,我列表中的其他一些也会刷新。

我的 PagingDataAdapter 的 DiffUtil 使用 objects.equals,我在我的条目项中覆盖了它,只有在没有用户输入的情况下不太可能随机更改的字段,所以我认为这不是问题。(虽然,在我看来,其他刷新的项目可能意味着这可能是错误的?

观察者 XML -

<?xml version="1.0" encoding="utf-8"?>
<layout>

    <data>

        <variable
            name="entry"
            type="com.model.Entry" />

    </data>

    <androidx.cardview.widget.CardView 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="wrap_content"
        android:layout_height="wrap_content"
        android:clickable="true"
        android:focusable="true"
        android:foreground="?attr/selectableItemBackgroundBorderless"
        app:cardCornerRadius="@dimen/rounded_corners"
        app:cardUseCompatPadding="true">

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

            <androidx.appcompat.widget.AppCompatImageView
                android:id="@+id/img_entry_item"
                android:layout_width="160dp"
                android:layout_height="180dp"
                android:scaleType="centerCrop"
                app:image_from_url="@{entry.imageUrl}"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent"
                tools:src="@tools:sample/backgrounds/scenic" />

            <androidx.appcompat.widget.AppCompatTextView
                android:id="@+id/text_votes"
                style="@style/Text.RH.Body1.Bold"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:paddingStart="@dimen/padding_medium"
                android:paddingTop="@dimen/padding_medium"
                android:paddingEnd="@dimen/padding_xsmall"
                android:paddingBottom="@dimen/padding_medium"
                android:text="@{String.valueOf(entry.voteCount)}"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@id/img_entry_item"
                tools:text="3000" />

            <androidx.appcompat.widget.AppCompatTextView
                android:id="@+id/text_votes_suffix"
                style="@style/Text.RH.Body1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:paddingStart="@dimen/none"
                android:paddingEnd="@dimen/padding_medium"
                android:text="@string/votes"
                app:layout_constraintBaseline_toBaselineOf="@id/text_votes"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintHorizontal_bias="0.0"
                app:layout_constraintStart_toEndOf="@id/text_votes"
                app:layout_constraintTop_toBottomOf="@id/img_entry_item" />

            <androidx.appcompat.widget.AppCompatTextView
                android:id="@+id/text_index"
                style="@style/Text.RH.Body1.Light"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@color/item_label_background"
                android:padding="@dimen/padding_medium"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent"
                tools:text="1" />

        </androidx.constraintlayout.widget.ConstraintLayout>

    </androidx.cardview.widget.CardView>

</layout>

我的图像加载绑定适配器

@BindingAdapter("image_from_url")
fun AppCompatImageView.loadImageWithGlide(url: String?) {
    try {
        if(this.tag == url) return

        this.tag = url

        when {
            url.isNullOrBlank() -> this.setImageDrawable(null)
            else -> {
                Glide.with(this)
                    .load(url)
                    .diskCacheStrategy(DiskCacheStrategy.ALL)
                    .transition(DrawableTransitionOptions.withCrossFade())
                    .placeholder(CircularProgressDrawable(this.context).apply {
                        strokeWidth = 5f
                        centerRadius = 30f
                        start()
                    })
                    .into(this)
            }
        }
    } catch (ex: Exception) {
        Timber.e(ex, "Unable to load rounded image url: $url")
    }
}

这是使用 PagingDataAdapter 从我的 ViewHolder 填充的

class EntryAdapter(
    private val maxItems: Int? = null,
    private val onEntryClicked: (entry: Entry) -> (Unit),
) : PagingDataAdapter<Entry, EntryAdapter.ViewHolder>(
    DiffItemCallback()
) {

    override fun getItemCount(): Int = maxItems?.let { super.getItemCount().coerceAtMost(maxItems) } ?: super.getItemCount()

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder =
        ViewHolder(
            ItemEntryItemVotesBinding.inflate(
                LayoutInflater.from(parent.context),
                parent,
                false
            )
        )

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.bind(
            entry = getItem(position),
            adapterPosition = position
        )
    }

    inner class ViewHolder(
        private val binding: ItemEntryItemVotesBinding
    ) : RecyclerView.ViewHolder(binding.root) {

        init {
            binding.root.setOnClickListener {
                getItem(absoluteAdapterPosition)?.let(onEntryClicked)
            }
        }

        fun bind(entry: Entry?, adapterPosition: Int) {
            binding.entry = entry
            binding.textIndex.text = (adapterPosition + 1).toString()
        }
    }
}

使用 Flows 从我的片段中填充

...
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        initDataBinding()
        
        initEntriesRecyclerView()
    }
...

    private fun initEntriesRecyclerView() {
        binding.rvEntries.apply {
            adapter = rvAdapter
            setSnapToStart()
        }

        viewModel.competition.observe(
            viewLifecycleOwner
        ) { competition ->
            competition?.let {
                lifecycleScope.launchWhenResumed {
                    viewModel.getEntries(
                        competitionId = competition.id
                    ).collectLatest {
                        if (entryAdapter.itemCount == 0) {
                            binding.rvAdapter.layoutAnimation = AnimationUtils.loadLayoutAnimation(
                            requireContext(),
                            R.anim.layout_animation_from_right
                           )
                        }

                       rvAdapter.submitData(it)
                   }
               }
            }
        }
    }

和我的视图模型

    fun getEntries(competitionId: Long) = entryRepository.getEntries(
        competitionId = competitionId,
        sortBy = EntrySortBy.Votes,
        sortDirection = EntrySortDirection.Desc,
        scope = viewModelScope
    )

然后存储库

    override fun getEntries(
        competitionId: Long,
        sortBy: EntrySortBy,
        sortDirection: EntrySortDirection,
        scope: CoroutineScope
    ) = Pager(
        PagingConfig(pageSize = 20)
    ) {
        EntryDataSource(
            competitionId = competitionId,
            sortBy = sortBy,
            sortDirection = sortDirection,
            entryRepository = this
        )
    }.flow.cachedIn(scope)
4

1 回答 1

1

试试这个 -> 在 DiffUtil.ItemCallback getChangePayload 中覆盖这样的乐趣↓</p>

override fun getChangePayload(oldItem: ChatsModel, newItem: ChatsModel): Any = Any()

在您的情况下, fun 必须返回“Any()”。

于 2021-07-08T12:29:36.473 回答