【问题标题】:Correct Place to Update RecyclerView with Observed Data使用观察到的数据更新 RecyclerView 的正确位置
【发布时间】:2020-05-11 17:51:33
【问题描述】:

我希望我做对了,但我希望澄清以下代码被视为良好做法。

这是我的片段(请注意我放置setupObservers()initRecyclerView 的位置)。

private const val TAG = "DAS.SitesFragment"

class SitesFragment : Fragment() {

    private lateinit var businessViewModel: BusinessViewModel
    private var sitesList = ArrayList<SiteObject>()

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?): View? {
        // Inflate the layout for this fragment
        val binding: SitesFragmentBinding = DataBindingUtil.inflate(
            inflater, R.layout.sites_fragment, container, false
        )

        binding.apply {
            sitesFloatingActionButtonAdd.setOnClickListener{
                findNavController().navigate(R.id.action_sitesFragment_to_siteAddEditFragment)
                Log.d(TAG,"sitesFloatingActionButtonAdd clicked, navigating to siteAddEditFragment")
            }

            sitesClearIconImageView.setOnClickListener{
                findNavController().navigate(R.id.action_sitesFragment_to_siteFragment)
                Log.d(TAG,"sitesClearIconImageView clicked, navigating to siteFragment")
            }
        }

        return binding.root
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)

            activity?.let {
                businessViewModel = ViewModelProvider(it).get(BusinessViewModel::class.java)
                Log.d(TAG, "businessViewModel = ${businessViewModel.toString()}")
        }
        setupObservers()
    }

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


    private fun initRecyclerView() {
        Log.d(TAG, "initRecyclerView()")
        sitesRecyclerView.apply {
            adapter = SitesRecyclerViewAdapter(sitesList)
            layoutManager = LinearLayoutManager(activity)
            setHasFixedSize(true)  
        }

    }

    private fun setupObservers() {
        Log.d(TAG, "setupObservers()")
        businessViewModel.listenToSites().observe(viewLifecycleOwner, Observer { allSites ->
            sitesList = allSites
            sitesRecyclerView.adapter = SitesRecyclerViewAdapter(sitesList)
//            sitesRecyclerView.adapter?.notifyDataSetChanged() - don't think I even need this..
            Log.d(TAG,"siteAdapter updated, sitesList size = ${sitesList.size}")
        })
    }

}

这是我的适配器

private const val TAG = "DAS.SitesRViewAdapter"


class SitesRecyclerViewAdapter(private val sitesList: ArrayList<SiteObject>): RecyclerView.Adapter<SitesRecyclerViewAdapter.SiteViewHolder> (){

    class SiteViewHolder (itemView: View): RecyclerView.ViewHolder (itemView) {

        val siteItemTitle: TextView = itemView.sitesItemTitleText
        val siteItemProjectText: TextView = itemView.sitesItemProjectsText

        val siteItemMapImage: ImageView = itemView.sitesItemMapImageView
        val siteItemPriorityImage: ImageView = itemView.sitesItemPriorityImageView
        val siteItemRating1Image: ImageView = itemView.sitesItemRating1ImageView
        val siteItemRating2Image: ImageView = itemView.sitesItemRating2ImageView
        val siteItemRating3Image: ImageView = itemView.sitesItemRating3ImageView

    }


    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SiteViewHolder {
        Log.d(TAG, "onCreateViewHolder()")
        val itemView = LayoutInflater.from(parent.context).inflate(R.layout.sites_list_item, parent, false)
        return SiteViewHolder(itemView)
    }

    override fun onBindViewHolder(holder: SiteViewHolder, position: Int) {

        val currentItem = sitesList[position]

        Log.d(TAG, "onBindViewHolder(), currentItem = ${currentItem.siteReference}")

        holder.siteItemTitle.text = currentItem.siteReference
        holder.siteItemProjectText.text = currentItem.recentProjectsText

        // Reset visibility
        holder.siteItemPriorityImage.visibility = View.INVISIBLE
        holder.siteItemMapImage.visibility = View.INVISIBLE
        holder.siteItemRating1Image.visibility = View.INVISIBLE
        holder.siteItemRating2Image.visibility = View.INVISIBLE
        holder.siteItemRating3Image.visibility = View.INVISIBLE

        // Make relevant icons visible
        if (currentItem.plusCode.isNotEmpty()) holder.siteItemMapImage.visibility = View.VISIBLE
        if (currentItem.sitePriority) holder.siteItemPriorityImage.visibility = View.VISIBLE
        when (currentItem.siteRating) {
            1 -> holder.siteItemRating1Image.visibility = View.VISIBLE
            2 -> holder.siteItemRating2Image.visibility = View.VISIBLE
            3 -> holder.siteItemRating3Image.visibility = View.VISIBLE
        }
    }

    override fun getItemCount(): Int {
        return sitesList.size
    }
}

我在 logcat 中看到的内容如下:

2020-05-11 18:09:02.221 30982-30982/com.xxx.acorn D/DAS.SplashActivity: firebaseAuth = com.google.firebase.auth.internal.zzl@cb43e66, firebaseUser = com.google.firebase.auth.internal.zzn@ca5d5a7
2020-05-11 18:09:02.737 30982-30982/com.xxx.acorn D/DAS.SitesFragment: initRecyclerView()
2020-05-11 18:09:02.785 30982-30982/com.xxx.acorn D/DAS.SitesFragment: businessViewModel = com.locators.acorn.business.BusinessViewModel@f994bce
2020-05-11 18:09:02.785 30982-30982/com.xxx.acorn D/DAS.SitesFragment: setupObservers()
2020-05-11 18:09:02.785 30982-30982/com.xxx.acorn D/DAS.BusinessViewModel: listenToSites()
2020-05-11 18:09:03.414 30982-30982/com.xxx.acorn D/DAS.SitesFragment: siteAdapter updated, sitesList size = 12
2020-05-11 18:09:03.418 30982-30982/com.xxx.acorn D/DAS.SitesRViewAdapter: onCreateViewHolder()
2020-05-11 18:09:03.440 30982-30982/com.xxx.acorn D/DAS.SitesRViewAdapter: onBindViewHolder(), currentItem = Company 88383
2020-05-11 18:09:03.454 30982-30982/com.xxx.acorn D/DAS.SitesRViewAdapter: onCreateViewHolder()
2020-05-11 18:09:03.464 30982-30982/com.xxx.acorn D/DAS.SitesRViewAdapter: onBindViewHolder(), currentItem = Company HEY1
2020-05-11 18:09:03.476 30982-30982/com.xxx.acorn D/DAS.SitesRViewAdapter: onCreateViewHolder()
2020-05-11 18:09:03.484 30982-30982/com.xxx.acorn D/DAS.SitesRViewAdapter: onBindViewHolder(), currentItem = Company 9677
2020-05-11 18:09:03.490 30982-30982/com.xxx.acorn D/DAS.SitesRViewAdapter: onCreateViewHolder()
2020-05-11 18:09:03.501 30982-30982/com.xxx.acorn D/DAS.SitesRViewAdapter: onBindViewHolder(), currentItem = Company 313
2020-05-11 18:09:03.513 30982-30982/com.xxx.acorn D/DAS.SitesRViewAdapter: onCreateViewHolder()
2020-05-11 18:09:03.522 30982-30982/com.xxx.acorn D/DAS.SitesRViewAdapter: onBindViewHolder(), currentItem = Company 123
2020-05-11 18:09:03.528 30982-30982/com.xxx.acorn D/DAS.SitesRViewAdapter: onCreateViewHolder()
2020-05-11 18:09:03.537 30982-30982/com.xxx.acorn D/DAS.SitesRViewAdapter: onBindViewHolder(), currentItem = Company UTY
2020-05-11 18:09:03.546 30982-30982/com.xxx.acorn D/DAS.SitesRViewAdapter: onCreateViewHolder()
2020-05-11 18:09:03.566 30982-30982/com.xxx.acorn D/DAS.SitesRViewAdapter: onBindViewHolder(), currentItem = Company TJJF
2020-05-11 18:19:22.769 30982-30982/com.xxx.acorn D/DAS.SitesRViewAdapter: onCreateViewHolder()
2020-05-11 18:19:22.775 30982-30982/com.xxx.acorn D/DAS.SitesRViewAdapter: onBindViewHolder(), currentItem = Company ZHHPE
2020-05-11 18:19:22.852 30982-30982/com.xxx.acorn D/DAS.SitesRViewAdapter: onCreateViewHolder()
2020-05-11 18:19:22.861 30982-30982/com.xxx.acorn D/DAS.SitesRViewAdapter: onBindViewHolder(), currentItem = Company ZZZZ
2020-05-11 18:19:23.963 30982-30982/com.xxx.acorn D/DAS.SitesRViewAdapter: onCreateViewHolder()
2020-05-11 18:19:23.970 30982-30982/com.xxx.acorn D/DAS.SitesRViewAdapter: onBindViewHolder(), currentItem = Company XYZ
2020-05-11 18:19:24.047 30982-30982/com.xxx.acorn D/DAS.SitesRViewAdapter: onBindViewHolder(), currentItem = Company ABC
2020-05-11 18:19:25.096 30982-30982/com.xxx.acorn D/DAS.SitesRViewAdapter: onBindViewHolder(), currentItem = Company ABCCC

所以它似乎正确触发,后面的条目仅在您向下滚动时显示(重要的是 OnCreateViewHolder 在回收 ViewHolder 时停止触发,但我担心这是不正确的,因为我正在使用空列表创建 RecyclerView ,然后在设置观察者后填充它..

有趣的是,我注意到的一件事是,当我添加一个新站点时,观察者会触发两次,所以我在 logcat 中得到如下内容:

2020-05-11 18:09:03.414 30982-30982/com.xxx.acorn D/DAS.SitesFragment: siteAdapter updated, sitesList size = 13
2020-05-11 18:09:03.414 30982-30982/com.xxx.acorn D/DAS.SitesFragment: siteAdapter updated, sitesList size = 13

它似乎也填充了 RecyclerView 两次(包括复制上述内容),但我认为这是观察者的怪癖,超出了这个问题的范围。..

【问题讨论】:

    标签: android kotlin android-recyclerview


    【解决方案1】:

    请在onViewCreated回调中进行所有操作

    【讨论】:

    • 不,您不能在 onViewCreated 中设置观察者,因为 ViewModel 在 onActivityCreated 之前不会被初始化(因此它会因致命异常而失败..)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-14
    • 2019-04-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多