DiffUtil重绘ListAdapter Kotline中的所有项目 [英] DiffUtil redraw all items in ListAdapter Kotlin

查看:245
本文介绍了DiffUtil重绘ListAdapter Kotline中的所有项目的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在Android Kotlin中使用DiffUtil和ListAdapter。我在onResume方法中从服务器调用数据。当onResume调用每一项时,整个数据都在重新绘制视图。如果服务器端有任何数据更改,我希望更新视图,以便它将反映在应用程序中。

ListActivity.kt

class ListActivity : BaseActivity() {

    lateinit var binding: ListActivityLayoutBinding
    private val viewModel: ListViewModel by inject()
    private var listAdapter: listAdapter? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setupViewModel()
        binding = ListActivityLayoutBinding.inflate(layoutInflater)
        setContentView(binding.root)
    }

    private fun setupViewModel() {
        viewModel.liveData.observe(this, { list ->
            setupAdapter(list)
        })
    }

    private fun setupAdapter(list: List<XYZ>) {
        initializeAdapter()
        listAdapter?.submitList(list)
        binding.recyclerView.adapter = listAdapter
    }

    private fun initializeAdapter() {
        viewModel.abc?.let { abc ->
            listAdapter = ListAdapter(abc, object : Listener<XYZ> {
                override fun selectedItem(item: XYZ) {
                    // calling 
                    }
                }
            })
        } ?: run {
            Log.e("Error", "Error for fetching data")
        }
    }

    override fun onResume() {
        super.onResume()
        viewModel.fetchData()
    }
}

XYZ.kt

data class XYZ(
    val id: String? = null,
    val title: String? = null,
    val count: Int? = null,
    val status: String? = null,
    val item: Qqq? = null
)

QQQ.kt

data class Qqq(
    val id: String? = null,
    val rr: Rr? = null
)

Rr.kt

data class Rr(
    val firstName: String? = null,
    val lastName: String? = null,
)

ListAdapter.kt

class ListAdapter(
    private val abc: Abc,
    private val listener: Listener <XYZ>
) : ListAdapter<XYZ, ListViewHolder>(LIST_COMPARATOR) {

    companion object {
        private val LIST_COMPARATOR = object : DiffUtil.ItemCallback<XYZ>() {
            override fun areItemsTheSame(oldItem: XYZ, newItem: XYZ): Boolean {
                return oldItem.id == newItem.id
            }

            override fun areContentsTheSame(oldItem: XYZ, newItem: XYZ): Boolean {
                return ((oldItem.title == newItem.title) && (oldItem.status == newItem.status)
                        && (oldItem.count == newItem.count)
                        && (oldItem.item == newItem.item))
            }
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ListViewHolder {
        return ListViewHolder.bindView(parent, abc)
    }

    override fun onBindViewHolder(holder: ListViewHolder, position: Int) {
        holder.bindItem(getItem(position), listener)
    }
}

ListViewModel.Kt

class ListViewModel : BaseViewModel() {

    var abc: Abc? = null
    private var xyz: List<XYZ>? = null
    var liveData: MutableLiveData<List<XYZ>> = MutableLiveData()

    fun fetchData() {
        viewModelScope.launch {
          
            val firstAsync = async {
                if (abc == null) {
                    abc = getAbc() // First retrofit call
                }
            }
            val secondAsync = async {
                xyz = getXYZ() // Second retrofit call
            }
            firstAsync.await()
            secondAsync.await()
            liveData.postValue(xyz)
        }
    }
}

注意:我要检查abc在每次调用中都不是空的。

1.我的DiffUitll回调正确吗?

2.第一次调用我想要重画每一项,但是,如果我在onResume中调用viewModel.fetchData(),如果我需要做任何更改,否则我不想重画我的整个列表。有什么建议吗?

推荐答案

屏幕上闪烁的内容是因为您每次恢复时都会创建一个新的适配器实例,并且会重新触发您的viewModel订阅。

不要将适配器设置为后期初始化,这没有什么好处。

class ListActivity : BaseActivity() {

    lateinit var binding: ListActivityLayoutBinding
    private val viewModel: ListViewModel by inject()

    private val adapterListener = object : Listener<XYZ> {
                override fun selectedItem(item: XYZ) { // TODO  }
            }
           

    private var listAdapter = ListAdapter(adapterListener)

然后在可以的时候设置:

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setupViewModel()
        binding = ListActivityLayoutBinding.inflate(layoutInflater)
        setContentView(binding.root)

        binding.yourRecyclerView.adapter = listAdapter
    }

然后,一旦观察到数据并获得它,就调用listAdapter.submitList(xxx)。除非您确实需要一个完整的新适配器(为什么?),否则无需重新创建适配器。

    private fun setupViewModel() {
        viewModel.liveData.observe(this, { list ->
            listAdapter.submitList(list.toMutableList())
        })
    }

关于您的abc的检查(&Q)

每次都需要调用一件事InitializeAdapter()函数,因为每次视图模型.abc都会检查该值不为空。

这就是ViewModel的问题。如果没有满足要求,你就不应该推一个新的清单。如果viewmodel.abc为空,则您在setupViewModel通过viewmodel.liveData.observe中提供的list不应存在,则您不应推送livedata或应推送其他状态。

片段应该对它接收到的数据做出反应,但是这些数据和逻辑的处理属于其他地方(视图模型和更深入的用例/报告)。

您的代码片段所做的一切就是构造框架的东西(一个循环视图及其附件,如Adapter、LayoutManager,如果需要,等等)。并订阅一个liveData流,该流将提供与框架内容连接所需的数据。它不会思考,也不应该这样做。

更新

Here is a Pull Request在我几分钟内抛出的样例项目中。当我运行该命令时,我在RecclerView的屏幕上看到两个模拟的项目。

这篇关于DiffUtil重绘ListAdapter Kotline中的所有项目的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆