MVVM-包含布局内的 Recyclerview 从未初始化
MVVM- Recyclerview inside included layout is never initialized
我有一个通用列表,需要在我的应用中的大部分 activities/fragments 上显示。为此,我创建了一个布局并在其中添加了回收器,如下面的代码所示。然后在需要时将此布局包含在 activities/fragment 中。我正在使用 MVVM,android bindings.My 这里的问题是 recyclerview 的 onCreateViewHolder 甚至 getItemCount 从未被调用。我的 updateList 函数从视图模型成功调用,列表中有 2 个项目,但 notifydatasetchanged 没有任何效果。我做错了什么?这是我的代码。
适配器 Class
class FaqsAdapter : RecyclerView.Adapter<FaqsAdapter.MyViewHolder>() {
lateinit var binding: FaqItemBinding
lateinit var listFaqs: List<ModelFaqs>
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val inflater = LayoutInflater.from(parent.context)
binding = DataBindingUtil.inflate(inflater, R.layout.faq_item, parent, false)
return MyViewHolder(binding)
}
override fun getItemCount(): Int {
return if (::listFaqs.isInitialized) listFaqs.size else 0
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.bind(listFaqs[position])
}
fun updateList(faqs: List<ModelFaqs>) {
this.listFaqs = faqs //this line executes
notifyDataSetChanged() // line also executes but does nothing.
}
class MyViewHolder(binding: FaqItemBinding) : RecyclerView.ViewHolder(binding.root) {
private val mBinding = binding
fun bind(modelFaqs: ModelFaqs) {
val viewModel = FaqItemViewModel()
viewModel.bind(modelFaqs)
mBinding.mViewModel = viewModel
}
}
}
片段
class FragLoan : Fragment() {
//other code
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
binding.viewFaqs.rcFaqs.layoutManager = LinearLayoutManager(context)
viewModel = ViewModelProviders.of(this).get(FragLoanViewModel::class.java)
}
}
视图模型class
class FragLoanViewModel : BaseViewModel() {
//other code
private fun onLoanSuccess(response: AdvanceLoanDetails?) {
Log.d(TAG, "LoanViewModel--On Success")
val modelFaqs: MutableList<ModelFaqs> = mutableListOf()
if (response?.result == true) {
if (response.resultContent?.faqs != null) {
for (faqs in response.resultContent.faqs) {
val model = ModelFaqs(faqs?.question, faqs?.answer)
modelFaqs.add(model)
}
updateFaq(modelFaqs)
}
}
}
//other code.
}
基础视图模型
这是我的 baseviewModel
abstract class BaseViewModel : ViewModel() {
val faqsAdapter = FaqsAdapter()
private val injector: ViewModelInjector = DaggerViewModelInjector
.builder()
.networkModule(NetworkModule)
.build()
init {
inject()
}
private fun inject() {
when (this) {
//code here
}
}
fun updateFaq(listFaqs: List<ModelFaqs>) {
faqsAdapter.updateList(listFaqs)
}
}
片段布局
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<data>
<variable
name="viewModel"
type="com.mypackage.viewmodel.FragLoanViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorViewBackgroundGrey"
tools:context="com.mypackage.myfragments.FragLoan">
<ImageView
android:id="@+id/ivLoanBanner"
android:layout_width="0dp"
android:layout_height="@dimen/_60sdp"
android:layout_marginTop="16dp"
android:contentDescription="@null"
android:scaleType="fitXY"
app:imageurl="@{viewModel.banner}"
app:layout_constraintLeft_toLeftOf="@id/guideLeft"
app:layout_constraintRight_toRightOf="@id/guideRight"
app:layout_constraintTop_toTopOf="parent" />
<androidx.cardview.widget.CardView
android:id="@+id/cvLoanDetails"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:background="@color/colorWhite"
app:cardCornerRadius="@dimen/card_content_radius"
app:layout_constraintEnd_toEndOf="@id/guideRight"
app:layout_constraintStart_toStartOf="@id/guideLeft"
app:layout_constraintTop_toBottomOf="@id/ivLoanBanner">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="@dimen/_16sdp">
<TextView
android:id="@+id/tvAdvanceLoadTitle"
mutableText="@{viewModel.title}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/_6sdp"
android:textColor="@color/colorBlack"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tvAdvanceLoanValidity"
mutableText="@{viewModel.validity}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:textColor="@color/lightGrey"
app:layout_constraintStart_toStartOf="@+id/tvAdvanceLoadTitle"
app:layout_constraintTop_toBottomOf="@+id/tvAdvanceLoadTitle" />
<TextView
android:id="@+id/tvAdvanceLoanPrice"
mutableText="@{viewModel.amount}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/colorPrimary"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/tvAdvanceLoadTitle" />
<TextView
android:id="@+id/tvAdvanceLoanTax"
mutableText="@{viewModel.inclusiveTax}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:textColor="@color/lightGrey"
app:layout_constraintEnd_toEndOf="@+id/tvAdvanceLoanPrice"
app:layout_constraintTop_toBottomOf="@+id/tvAdvanceLoanPrice" />
<TextView
android:id="@+id/tvAdvanceLoanDetail"
mutableText="@{viewModel.description}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/_8sdp"
android:background="@drawable/edit_text_history"
android:gravity="center"
android:minHeight="@dimen/_50sdp"
android:padding="@dimen/_6sdp"
android:textColor="@color/lightGrey"
android:textSize="12sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tvAdvanceLoanValidity" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="left"
app:constraint_referenced_ids="tvAdvanceLoanTax,tvAdvanceLoanPrice"
tools:layout_editor_absoluteX="369dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideLeft"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_begin="16dp" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideRight"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_end="16dp" />
<!-- <androidx.recyclerview.widget.RecyclerView-->
<!-- android:id="@+id/rcFaqs"-->
<!-- app:layout_constraintEnd_toEndOf="@id/guideRight"-->
<!-- app:layout_constraintStart_toStartOf="@id/guideLeft"-->
<!-- app:layout_constraintTop_toBottomOf="@+id/cvLoanDetails"-->
<!-- android:layout_width="0dp"-->
<!-- android:layout_height="wrap_content"-->
<!-- app:adapter="@{viewModel.faqsAdapter}" />-->
<include
android:id="@+id/viewFaqs"
layout="@layout/view_faq"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
app:layout_constraintEnd_toEndOf="@id/guideRight"
app:layout_constraintStart_toStartOf="@id/guideLeft"
app:layout_constraintTop_toBottomOf="@+id/cvLoanDetails" />
<include
android:id="@+id/viewTerms"
layout="@layout/view_terms_conditions"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
app:layout_constraintEnd_toEndOf="@id/guideRight"
app:layout_constraintStart_toStartOf="@id/guideLeft"
app:layout_constraintTop_toBottomOf="@+id/viewFaqs" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btnGetLoan"
android:layout_width="0dp"
android:layout_height="@dimen/button_height"
android:layout_marginBottom="8dp"
android:text="@string/get_loan"
android:textAllCaps="false"
app:cornerRadius="@dimen/button_corner_radius"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@id/guideRight"
app:layout_constraintStart_toStartOf="@id/guideLeft" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
我的 FaqItemViewModel
class FaqItemViewModel : BaseViewModel() {
private val sequenceNumber = MutableLiveData<String>()
private val question = MutableLiveData<String>()
private val answer = MutableLiveData<String>()
private var sqNo = 0
fun bind(faqs: ModelFaqs) {
sqNo += 1
sequenceNumber.value = sqNo.toString()
question.value = faqs.question
answer.value = faqs.answer
}
fun getSequenceNumber(): MutableLiveData<String> {
return sequenceNumber
}
fun getQuestion(): MutableLiveData<String> {
return question
}
fun getAnswer(): MutableLiveData<String> {
return answer
}
}
和项目 XML
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="mViewModel"
type="com.mypackage.viewmodel.FaqItemViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/tvSerialNumber"
mutableText="@{mViewModel.sequenceNumber}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/colorAccent"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tvQuestion"
mutableText="@{mViewModel.question}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:paddingLeft="6dp"
android:paddingRight="6dp"
android:textColor="@color/colorAccent"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/tvSerialNumber"
app:layout_constraintTop_toTopOf="@+id/tvSerialNumber" />
<TextView
android:id="@+id/tvAnswer"
mutableText="@{mViewModel.answer}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:paddingLeft="6dp"
android:paddingRight="6dp"
android:textColor="@color/lightGrey"
android:textSize="12sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/tvQuestion"
app:layout_constraintTop_toBottomOf="@+id/tvQuestion" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
您没有将 viewmodel
绑定到您的布局。
在你片段的 onActivityCreated
你是
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
binding.viewFaqs.rcFaqs.layoutManager = LinearLayoutManager(context)
viewModel = ViewModelProviders.of(this).get(FragLoanViewModel::class.java)
binding.viewModel = viewModel //this line will fix
//Additionally, bind it to lifecycleOwner
binding.lifecycleOwner = this
}
接下来在你的适配器中,你不应该有参数 binding
因为它是每个项目的。你应该在 onBindViewHolder
中传递 binding
class FaqsAdapter : RecyclerView.Adapter<FaqsAdapter.MyViewHolder>() {
private val listFaqs = mutableListOf<ModelFaqs>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val inflater = LayoutInflater.from(parent.context)
val binding = DataBindingUtil.inflate(inflater, R.layout.faq_item, parent, false)
return MyViewHolder(binding)
}
override fun getItemCount() = listFaqs.size
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.bind(listFaqs[position])
}
fun updateList(faqs: List<ModelFaqs>) {
this.listFaqs.clear()
this.listFaqs.addAll(faqs)
notifyDataSetChanged() // line also executes but does nothing.
}
class MyViewHolder(private val binding: FaqItemBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(modelFaqs: ModelFaqs) {
val viewModel = FaqItemViewModel()
viewModel.bind(modelFaqs)
binding.mViewModel = viewModel
}
}
好吧,你好像忘记了一件事。在主布局中的 include
布局期间,您需要确保将 ViewModel
and/or 其他数据转发到内部布局。最终,如果不在一个布局中绑定转发您的数据,它就不会被包含在内。
1) 请确保您将 ViewModel
and/or 数据传递给包含的布局进行交互。您需要确保您的 ViewModel
Adapter
绑定到包含的布局。只是为了前任。类似下一个。
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:bind="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".view.DetailActivity">
<data>
<variable
name="viewModel"
type="sample.settings.gensagames.samplejetpackmvvm.viewmodel.DetailViewModel" />
</data>
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/app_bar"
android:layout_width="match_parent">
<!-- Other code -->
</com.google.android.material.appbar.AppBarLayout>
<include
android:id="@+id/detail_content"
layout="@layout/detail_content"
bind:viewModel="@{viewModel}" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</layout>
然后在您包含的布局中使用参数。就像是。这不是你的例子,但你应该明白这一点。 您需要将您的 ViewModel
and/or 参数转发到包含的布局。这一切只是为了设置Adapter
。
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:bind="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".view.DetailActivity">
<data>
<variable
name="viewModel"
type="sample.settings.gensagames.samplejetpackmvvm.viewmodel.DetailViewModel" />
</data>
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:showIn="@layout/detail_fragment">
<TextView
android:id="@+id/textViewContent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/text_margin"
app:mutableText="@{viewModel.getTextContent()}"
tools:text="Sample Text Content" />
</androidx.core.widget.NestedScrollView>
</layout>
问题现已解决。我在 Internet 上搜索示例并找到 google 示例应用程序 sunflowerAlpha。看完这段代码后,我对我的代码做了一些改动。像
首先,我从 BaseView 模型中删除了这些行
val faqsAdapter = FaqsAdapter()
fun updateFaq(listFaqs: List<ModelFaqs>) {
faqsAdapter.updateList(listFaqs)
}
然后我从 xml 文件中删除适配器绑定 "app:adapter="@{theviewmodel.myAdapter}" 并像这样从我的片段中绑定适配器。
binding.viewFaqs.rcFaqs.layoutManager = LinearLayoutManager(context)
binding.viewFaqs.rcFaqs.isNestedScrollingEnabled = false
binding.viewFaqs.rcFaqs.adapter = faqsAdapter
val faqs = createFaqs(loanDetails)
faqsAdapter.updateList(faqs)
现在 recyclerview 已成功填充。
我有一个通用列表,需要在我的应用中的大部分 activities/fragments 上显示。为此,我创建了一个布局并在其中添加了回收器,如下面的代码所示。然后在需要时将此布局包含在 activities/fragment 中。我正在使用 MVVM,android bindings.My 这里的问题是 recyclerview 的 onCreateViewHolder 甚至 getItemCount 从未被调用。我的 updateList 函数从视图模型成功调用,列表中有 2 个项目,但 notifydatasetchanged 没有任何效果。我做错了什么?这是我的代码。 适配器 Class
class FaqsAdapter : RecyclerView.Adapter<FaqsAdapter.MyViewHolder>() {
lateinit var binding: FaqItemBinding
lateinit var listFaqs: List<ModelFaqs>
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val inflater = LayoutInflater.from(parent.context)
binding = DataBindingUtil.inflate(inflater, R.layout.faq_item, parent, false)
return MyViewHolder(binding)
}
override fun getItemCount(): Int {
return if (::listFaqs.isInitialized) listFaqs.size else 0
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.bind(listFaqs[position])
}
fun updateList(faqs: List<ModelFaqs>) {
this.listFaqs = faqs //this line executes
notifyDataSetChanged() // line also executes but does nothing.
}
class MyViewHolder(binding: FaqItemBinding) : RecyclerView.ViewHolder(binding.root) {
private val mBinding = binding
fun bind(modelFaqs: ModelFaqs) {
val viewModel = FaqItemViewModel()
viewModel.bind(modelFaqs)
mBinding.mViewModel = viewModel
}
}
}
片段
class FragLoan : Fragment() {
//other code
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
binding.viewFaqs.rcFaqs.layoutManager = LinearLayoutManager(context)
viewModel = ViewModelProviders.of(this).get(FragLoanViewModel::class.java)
}
}
视图模型class
class FragLoanViewModel : BaseViewModel() {
//other code
private fun onLoanSuccess(response: AdvanceLoanDetails?) {
Log.d(TAG, "LoanViewModel--On Success")
val modelFaqs: MutableList<ModelFaqs> = mutableListOf()
if (response?.result == true) {
if (response.resultContent?.faqs != null) {
for (faqs in response.resultContent.faqs) {
val model = ModelFaqs(faqs?.question, faqs?.answer)
modelFaqs.add(model)
}
updateFaq(modelFaqs)
}
}
}
//other code.
}
基础视图模型 这是我的 baseviewModel
abstract class BaseViewModel : ViewModel() {
val faqsAdapter = FaqsAdapter()
private val injector: ViewModelInjector = DaggerViewModelInjector
.builder()
.networkModule(NetworkModule)
.build()
init {
inject()
}
private fun inject() {
when (this) {
//code here
}
}
fun updateFaq(listFaqs: List<ModelFaqs>) {
faqsAdapter.updateList(listFaqs)
}
}
片段布局
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<data>
<variable
name="viewModel"
type="com.mypackage.viewmodel.FragLoanViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorViewBackgroundGrey"
tools:context="com.mypackage.myfragments.FragLoan">
<ImageView
android:id="@+id/ivLoanBanner"
android:layout_width="0dp"
android:layout_height="@dimen/_60sdp"
android:layout_marginTop="16dp"
android:contentDescription="@null"
android:scaleType="fitXY"
app:imageurl="@{viewModel.banner}"
app:layout_constraintLeft_toLeftOf="@id/guideLeft"
app:layout_constraintRight_toRightOf="@id/guideRight"
app:layout_constraintTop_toTopOf="parent" />
<androidx.cardview.widget.CardView
android:id="@+id/cvLoanDetails"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:background="@color/colorWhite"
app:cardCornerRadius="@dimen/card_content_radius"
app:layout_constraintEnd_toEndOf="@id/guideRight"
app:layout_constraintStart_toStartOf="@id/guideLeft"
app:layout_constraintTop_toBottomOf="@id/ivLoanBanner">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="@dimen/_16sdp">
<TextView
android:id="@+id/tvAdvanceLoadTitle"
mutableText="@{viewModel.title}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/_6sdp"
android:textColor="@color/colorBlack"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tvAdvanceLoanValidity"
mutableText="@{viewModel.validity}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:textColor="@color/lightGrey"
app:layout_constraintStart_toStartOf="@+id/tvAdvanceLoadTitle"
app:layout_constraintTop_toBottomOf="@+id/tvAdvanceLoadTitle" />
<TextView
android:id="@+id/tvAdvanceLoanPrice"
mutableText="@{viewModel.amount}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/colorPrimary"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/tvAdvanceLoadTitle" />
<TextView
android:id="@+id/tvAdvanceLoanTax"
mutableText="@{viewModel.inclusiveTax}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:textColor="@color/lightGrey"
app:layout_constraintEnd_toEndOf="@+id/tvAdvanceLoanPrice"
app:layout_constraintTop_toBottomOf="@+id/tvAdvanceLoanPrice" />
<TextView
android:id="@+id/tvAdvanceLoanDetail"
mutableText="@{viewModel.description}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/_8sdp"
android:background="@drawable/edit_text_history"
android:gravity="center"
android:minHeight="@dimen/_50sdp"
android:padding="@dimen/_6sdp"
android:textColor="@color/lightGrey"
android:textSize="12sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tvAdvanceLoanValidity" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="left"
app:constraint_referenced_ids="tvAdvanceLoanTax,tvAdvanceLoanPrice"
tools:layout_editor_absoluteX="369dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideLeft"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_begin="16dp" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideRight"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_end="16dp" />
<!-- <androidx.recyclerview.widget.RecyclerView-->
<!-- android:id="@+id/rcFaqs"-->
<!-- app:layout_constraintEnd_toEndOf="@id/guideRight"-->
<!-- app:layout_constraintStart_toStartOf="@id/guideLeft"-->
<!-- app:layout_constraintTop_toBottomOf="@+id/cvLoanDetails"-->
<!-- android:layout_width="0dp"-->
<!-- android:layout_height="wrap_content"-->
<!-- app:adapter="@{viewModel.faqsAdapter}" />-->
<include
android:id="@+id/viewFaqs"
layout="@layout/view_faq"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
app:layout_constraintEnd_toEndOf="@id/guideRight"
app:layout_constraintStart_toStartOf="@id/guideLeft"
app:layout_constraintTop_toBottomOf="@+id/cvLoanDetails" />
<include
android:id="@+id/viewTerms"
layout="@layout/view_terms_conditions"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
app:layout_constraintEnd_toEndOf="@id/guideRight"
app:layout_constraintStart_toStartOf="@id/guideLeft"
app:layout_constraintTop_toBottomOf="@+id/viewFaqs" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btnGetLoan"
android:layout_width="0dp"
android:layout_height="@dimen/button_height"
android:layout_marginBottom="8dp"
android:text="@string/get_loan"
android:textAllCaps="false"
app:cornerRadius="@dimen/button_corner_radius"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@id/guideRight"
app:layout_constraintStart_toStartOf="@id/guideLeft" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
我的 FaqItemViewModel
class FaqItemViewModel : BaseViewModel() {
private val sequenceNumber = MutableLiveData<String>()
private val question = MutableLiveData<String>()
private val answer = MutableLiveData<String>()
private var sqNo = 0
fun bind(faqs: ModelFaqs) {
sqNo += 1
sequenceNumber.value = sqNo.toString()
question.value = faqs.question
answer.value = faqs.answer
}
fun getSequenceNumber(): MutableLiveData<String> {
return sequenceNumber
}
fun getQuestion(): MutableLiveData<String> {
return question
}
fun getAnswer(): MutableLiveData<String> {
return answer
}
}
和项目 XML
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="mViewModel"
type="com.mypackage.viewmodel.FaqItemViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/tvSerialNumber"
mutableText="@{mViewModel.sequenceNumber}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/colorAccent"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tvQuestion"
mutableText="@{mViewModel.question}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:paddingLeft="6dp"
android:paddingRight="6dp"
android:textColor="@color/colorAccent"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/tvSerialNumber"
app:layout_constraintTop_toTopOf="@+id/tvSerialNumber" />
<TextView
android:id="@+id/tvAnswer"
mutableText="@{mViewModel.answer}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:paddingLeft="6dp"
android:paddingRight="6dp"
android:textColor="@color/lightGrey"
android:textSize="12sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/tvQuestion"
app:layout_constraintTop_toBottomOf="@+id/tvQuestion" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
您没有将 viewmodel
绑定到您的布局。
在你片段的 onActivityCreated
你是
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
binding.viewFaqs.rcFaqs.layoutManager = LinearLayoutManager(context)
viewModel = ViewModelProviders.of(this).get(FragLoanViewModel::class.java)
binding.viewModel = viewModel //this line will fix
//Additionally, bind it to lifecycleOwner
binding.lifecycleOwner = this
}
接下来在你的适配器中,你不应该有参数 binding
因为它是每个项目的。你应该在 onBindViewHolder
binding
class FaqsAdapter : RecyclerView.Adapter<FaqsAdapter.MyViewHolder>() {
private val listFaqs = mutableListOf<ModelFaqs>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val inflater = LayoutInflater.from(parent.context)
val binding = DataBindingUtil.inflate(inflater, R.layout.faq_item, parent, false)
return MyViewHolder(binding)
}
override fun getItemCount() = listFaqs.size
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.bind(listFaqs[position])
}
fun updateList(faqs: List<ModelFaqs>) {
this.listFaqs.clear()
this.listFaqs.addAll(faqs)
notifyDataSetChanged() // line also executes but does nothing.
}
class MyViewHolder(private val binding: FaqItemBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(modelFaqs: ModelFaqs) {
val viewModel = FaqItemViewModel()
viewModel.bind(modelFaqs)
binding.mViewModel = viewModel
}
}
好吧,你好像忘记了一件事。在主布局中的 include
布局期间,您需要确保将 ViewModel
and/or 其他数据转发到内部布局。最终,如果不在一个布局中绑定转发您的数据,它就不会被包含在内。
1) 请确保您将 ViewModel
and/or 数据传递给包含的布局进行交互。您需要确保您的 ViewModel
Adapter
绑定到包含的布局。只是为了前任。类似下一个。
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:bind="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".view.DetailActivity">
<data>
<variable
name="viewModel"
type="sample.settings.gensagames.samplejetpackmvvm.viewmodel.DetailViewModel" />
</data>
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/app_bar"
android:layout_width="match_parent">
<!-- Other code -->
</com.google.android.material.appbar.AppBarLayout>
<include
android:id="@+id/detail_content"
layout="@layout/detail_content"
bind:viewModel="@{viewModel}" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</layout>
然后在您包含的布局中使用参数。就像是。这不是你的例子,但你应该明白这一点。 您需要将您的 ViewModel
and/or 参数转发到包含的布局。这一切只是为了设置Adapter
。
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:bind="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".view.DetailActivity">
<data>
<variable
name="viewModel"
type="sample.settings.gensagames.samplejetpackmvvm.viewmodel.DetailViewModel" />
</data>
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:showIn="@layout/detail_fragment">
<TextView
android:id="@+id/textViewContent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/text_margin"
app:mutableText="@{viewModel.getTextContent()}"
tools:text="Sample Text Content" />
</androidx.core.widget.NestedScrollView>
</layout>
问题现已解决。我在 Internet 上搜索示例并找到 google 示例应用程序 sunflowerAlpha。看完这段代码后,我对我的代码做了一些改动。像 首先,我从 BaseView 模型中删除了这些行
val faqsAdapter = FaqsAdapter()
fun updateFaq(listFaqs: List<ModelFaqs>) {
faqsAdapter.updateList(listFaqs)
}
然后我从 xml 文件中删除适配器绑定 "app:adapter="@{theviewmodel.myAdapter}" 并像这样从我的片段中绑定适配器。
binding.viewFaqs.rcFaqs.layoutManager = LinearLayoutManager(context)
binding.viewFaqs.rcFaqs.isNestedScrollingEnabled = false
binding.viewFaqs.rcFaqs.adapter = faqsAdapter
val faqs = createFaqs(loanDetails)
faqsAdapter.updateList(faqs)
现在 recyclerview 已成功填充。