代码之家  ›  专栏  ›  技术社区  ›  Amol Borkar

使用带有recycleview的视图模型

  •  0
  • Amol Borkar  · 技术社区  · 4 年前

    这一切都很复杂,我希望我能解释清楚。所以,我使用recycleview以卡片的形式显示用户配置文件列表。每张卡包含2个按钮,用于不同的操作。现在,当点击这些按钮时,需要观察ViewModel中的LiveData对象(我使用的是MVVM、Android架构组件和Kotlin扩展)。一个按钮特别需要根据某些条件观察不同的实时数据。这就是为什么我创建了一个函数,它接受条件并返回合适的结果 OnClickListener 。我把这个交给回收视图适配器。

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

    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)
            }
        }
    }
    
    0 回复  |  直到 4 年前
        1
  •  0
  •   Max Mark B    4 年前

    据我了解,每 LiveData 应该在创建ViewModel类实例的片段/活动中观察到。 我认为问题的发生是因为您试图在创建LiveData的片段之外观察LiveData。 您可以通过以下方式观察片段/活动外的LiveData observeForever ,但你也需要打电话 removeObserver 避免内存泄漏

    cmiiw

        2
  •  0
  •   Biscuit Samir    4 年前

    我认为你的问题是因为你在使用 view. 在你的 bindCard() 功能。

    你班上有《听众》节目吗?你可以把它移到你的 Adapter 因为这样更合适 适配器 了解Listener而不是 data class

    你能试着换一下你的 适配器 像这样的:

    您在类中声明要与之交互的对象,然后在绑定中调用它们。

    class CardDataViewHolder constructor(
            v: View
        ) : RecyclerView.ViewHolder(v), View.OnClickListener {
            private var view: View = v
            private var cardData: ProfileCardData? = null
    
            val showInterestBtn = view.findViewById(R.id.show_interest)
            val sendMessageBtn = view.findViewById(R.id.message_btn)
            val title = view.findViewById(R.id.card_title)
            val subtitle = view.findViewById(R.id.card_subtitle)
    
            companion object {
                private val KEY = "CARD"
            }
    
            fun bindCard(card: ProfileCardData) {
                this.cardData = card
    
                if (card.isUserShortlisted) {
                    showInterestBtn.setIconResource(R.drawable.ic_favorite)
                } else {
                    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)
                }
    
                title.text = card.data.displayName
                subtitle.text = "${card.data.age} - ${card.data.height}"
    
                showInterestBtn.setOnClickListener(card.showBtnInterestListener)
                sendMessageBtn.setOnClickListener(card.messageBtnListener)
            }
        }