android - 将 View 模型与recyclerviews一起使用

标签 android kotlin mvvm android-recyclerview

这一切都很复杂,我希望我能很好地解释。因此,我正在使用recyclerview以卡片形式显示用户配置文件列表。每张卡包含2个用于执行不同操作的按钮。现在,这些按钮需要在单击时观察ViewModel内部的LiveData对象(我正在使用MVVM,Android体系结构组件和Kotlin扩展)。一个按钮尤其需要根据某种条件观察不同的实时数据。这就是为什么我创建了一个带有条件并返回合适的OnClickListener的函数的原因。我将其传递给recyclerview适配器。

现在的问题是我在多个片段中使用了相同的RecyclerView。当我在编写函数的同一片段中使用recyclerview时,一切正常。我在其他任何地方都收到如下错误:

java.lang.IllegalStateException: Fragment HomeFragment{1ef5330} (b299012d-c9c2-427f-8387-a7888289701b)} not attached to an activity.
        at androidx.fragment.app.Fragment.requireActivity(Fragment.java:833)
        at 
com.halalrishtey.HomeFragment$$special$$inlined$activityViewModels$2.invoke(FragmentViewModelLazy.kt:80)
        at com.halalrishtey.HomeFragment$$special$$inlined$activityViewModels$2.invoke(Unknown Source:0)
        at androidx.lifecycle.ViewModelLazy.getValue(ViewModelProvider.kt:52)
        at androidx.lifecycle.ViewModelLazy.getValue(ViewModelProvider.kt:41)
        at com.halalrishtey.HomeFragment.getUserVM(Unknown Source:7)
        at com.halalrishtey.HomeFragment.access$getUserVM$p(HomeFragment.kt:25)
        at com.halalrishtey.HomeFragment$genInterestBtnListener$1.onClick(HomeFragment.kt:65)
        at android.view.View.performClick(View.java:7125)
        at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:967)
        at android.view.View.performClickInternal(View.java:7102)
        at android.view.View.access$3500(View.java:801)
        at android.view.View$PerformClick.run(View.java:27336)
        at android.os.Handler.handleCallback(Handler.java:883)
        at android.os.Handler.dispatchMessage(Handler.java:100)
        at android.os.Looper.loop(Looper.java:214)
        at android.app.ActivityThread.main(ActivityThread.java:7356)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)

创建OnClickListener的函数如下所示:
fun genInterestBtnListener(
        condition: Boolean,
        v: View
    ): View.OnClickListener {
        return View.OnClickListener {
            if (!condition) {
                userVM.initInterest().observe(viewLifecycleOwner, Observer { msg ->
                    Toast.makeText(context, msg, Toast.LENGTH_SHORT)
                        .show()
                    //More code here
                })
            } else {
                userVM.removeInterest().observe(viewLifecycleOwner, Observer { msg ->
                    Toast.makeText(context, msg, Toast.LENGTH_SHORT)
                        .show()
                })
            }
        }
    }

我无法观察适配器内部的情况,因此无需重复执行代码的最佳解决方案是什么?

更新:我这样声明userVM:
private val userVM: UserViewModel by activityViewModels()

也是这是我的适配器代码:
class CardDataRVAdapter(private var items: List<ProfileCardData>) :
    RecyclerView.Adapter<CardDataRVAdapter.CardDataViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CardDataViewHolder {
        val inflatedView =
            LayoutInflater.from(parent.context).inflate(R.layout.profile_card, parent, false)
        return CardDataViewHolder(inflatedView)
    }

    override fun onBindViewHolder(holder: CardDataViewHolder, position: Int) {
        val card = items[position]
        holder.bindCard(card)
    }

    override fun getItemCount() = items.size

    class CardDataViewHolder constructor(
        v: View
    ) : RecyclerView.ViewHolder(v), View.OnClickListener {
        private var view: View = v
        private var cardData: ProfileCardData? = null

        init {
            v.setOnClickListener(this)
        }

        override fun onClick(p0: View?) {
            //TODO: Implement a proper onClickListener
            Toast.makeText(
                p0?.context,
                "${p0?.cardTitleTextView?.text} Card was clicked",
                Toast.LENGTH_SHORT
            ).show()
        }


        companion object {
            private val KEY = "CARD"
        }

        fun bindCard(card: ProfileCardData) {
            this.cardData = card

            if (card.isUserShortlisted) {
                view.showInterestBtn.setIconResource(R.drawable.ic_favorite)
            } else {
                view.showInterestBtn.setIconResource(R.drawable.ic_favorite_border)
            }

            if (card.data.photoUrl.length > 5) {
                Picasso.get().load(card.data.photoUrl)
                    .into(view.cardImageView)

                Picasso.get().load(card.data.photoUrl)
                    .into(view.cardAvatarImageView)
            }

            view.cardTitleTextView.text = card.data.displayName
            view.cardSubtitleTextView.text = "${card.data.age} - ${card.data.height}"

            view.showInterestBtn.setOnClickListener(card.showBtnInterestListener)
            view.sendMessageBtn.setOnClickListener(card.messageBtnListener)
        }
    }
}

最佳答案

根据我的理解,应该在创建ViewModel类实例的片段/ Activity 中观察每个LiveData
我认为出现此问题是因为您试图观察LiveData所创建的片段之外的片段。
您可以使用observeForever观察片段/ Activity 之外的LiveData,但还需要调用removeObserver以避免内存泄漏

ii

关于android - 将 View 模型与recyclerviews一起使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60709724/

相关文章:

java - 我正在做条形码扫描仪。但我可以在 TextView 中显示我的 resultCode 。

Kotlin if 条件习语

android - 撰写预览根本不起作用 - 需要编译项目

android - 从 PagerAdapter 调用时 fragment 消失

c# - 是否可以触发 OnPropertyChanged 事件,而无需在 ViewModel 上的属性 setter 中显式调用它?

android - BottomNavigationView 在 View 模型中的数据绑定(bind)

java - 单击 editText 后,转到另一个 edittext 时完成

android - 如何使用 SQLite 从图库中选择图片并另存为背景 ImageView

android - 如何在 Android 的标签栏中居中对齐文本

c# - 在我的项目 Xamarin 中实现 INotifyPropertyChanged