【问题标题】:No Data with RecyclerView, Data Binding and ViewModelRecyclerView、数据绑定和 ViewModel 没有数据
【发布时间】:2018-09-25 16:51:10
【问题描述】:

刚接触 Android 开发并试图围绕最新的架构组件展开思考。使用 Android Studio 3.2、Room、LiveData、ViewModel、Data Binding 和 RecyclerView,我已经与 Data Binding 斗争了好几天。我的活动中有一个片段,应该显示来自我的 ViewModel/Query 的数据的 RecyclerView 部分是空白/空的。 Adapter 的 getItemCount 中的 Log.d 显示零个项目,即使相关的 Room 查询有效并返回项目。

请用线索棒打我,让我知道我错过了什么。我的代码的相关部分:

实体与道

import org.threeten.bp.Instant

data class ActionDetails(val time: Instant,
                     val firstName: String,
                     ... )

@Query("SELECT time, first_name as firstName...")
fun liveStatus(): LiveData<List<ActionDetails>>

片段类

class MainFragment : Fragment() {
...
private lateinit var viewModel: MainViewModel
private lateinit var adapter: ViewAdapter

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                          savedInstanceState: Bundle?): View {
    val binding = MainFragmentBinding.inflate(inflater, container, false)
    val context = context ?: return binding.root

    val factory = Utilities.provideMainViewModelFactory(context)
    viewModel = ViewModelProviders.of(this, factory).get(MainViewModel::class.java)

    adapter = ViewAdapter(listOf())

    binding.apply {
        rvActionDetails.setHasFixedSize(true)
        rvActionDetails.layoutManager = LinearLayoutManager(context)
        rvActionDetails.adapter = adapter
        vm = viewModel
        setLifecycleOwner(this@MainFragment)
    }

    return binding.root
}

视图模型

class MainViewModel(private val repository: DataRepository) : ViewModel() {
    val actions: LiveData<List<ActionDetails>> = repository.liveStatus()
}

适配器

import ...FragmentActionDetailBinding

class ViewAdapter(private val actions: List<ActionDetails>) : RecyclerView.Adapter<ViewAdapter.ViewHolder>() {
private val TAG = this::class.java.simpleName

class ViewHolder(val binding: FragmentActionDetailBinding) : RecyclerView.ViewHolder(binding.root) {
    fun bind(action: ActionDetails) {
            binding.apply {
            vm = action
            executePendingBindings()
            }
    }
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
    val inflater = LayoutInflater.from(parent.context)
    val binding = FragmentActionDetailBinding.inflate(inflater, parent, false)
    return ViewHolder(binding)
}

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
    holder.bind(actions[position])
}

override fun getItemCount(): Int {
    Log.d(TAG, "Adapter has ${actions.size} items!")
    return actions.size
}
}

主要片段

<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<data>
    <variable
        name="vm" type=".MainViewModel" />
</data>

<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainFragment" >
    ...
    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rv_action_details"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        tools:listitem="@layout/fragment_action_detail" />

</androidx.constraintlayout.widget.ConstraintLayout>

片段 XML

<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<data>
    <variable
        name="vm" type=".ActionDetails" />
</data>

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    tools:context=".ActionDetailFragment" >

    <TextView
        android:id="@+id/first_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@{vm.firstName}"
        tools:text="John"/>
    ...
</LinearLayout>

【问题讨论】:

    标签: android android-recyclerview kotlin android-databinding android-viewmodel


    【解决方案1】:

    终于解决了这个问题。不知道到底是什么解决了它——我认为这是由于在片段中的 binding.apply 中配置 RecyclerView 之前移动 ViewModel 并运行 executePendingBindings(),但我不确定——因为我在学习后还做了一些其他更改关于 BindingAdapters。

    如果对其他人有帮助,我的更改如下 - 我也非常感谢任何关于如何改进的 cmets。

    干杯。

    片段类

    class MainFragment : Fragment() {
    ...
    
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View {
    ...
        binding.apply {
            //Need to do this before configuring the RecyclerView
            vm = viewModel
            setLifecycleOwner(this@MainFragment)
            executePendingBindings()
    
            rvActionDetails.setHasFixedSize(true)
            rvActionDetails.layoutManager = LinearLayoutManager(context)
            rvActionDetails.adapter = adapter
        }
    
        return binding.root
    }
    

    适配器

    import ...FragmentActionDetailBinding
    
    class ViewAdapter(private val actions: List<ActionDetails>) : RecyclerView.Adapter<ViewAdapter.ViewHolder>() {
    ...
        override fun setData(data: List<ActionDetails>) {
            actions = data
            notifyDataSetChanged()
    }
    

    绑定适配器

    @BindingAdapter("listData")
    fun <T> setRecyclerViewList (recyclerView: RecyclerView, data: T) {
        if (recyclerView.adapter is BindableListAdapter<*>) {
            (recyclerView.adapter as BindableListAdapter<T>).setData(data)
        }
    }
    
    interface BindableListAdapter<T> {
        fun setData(data: T)
    }
    

    主要片段

    <layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    
    <data>
        <variable
            name="vm" type=".MainViewModel" />
    </data>
    
    <androidx.constraintlayout.widget.ConstraintLayout
        ...
        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/rv_action_details"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
            app:listData="@{vm.actions}"
            tools:listitem="@layout/fragment_action_detail" />
    
    </androidx.constraintlayout.widget.ConstraintLayout>
    

    片段 XML

    <layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    
    <data>
        <variable
            name="vm" type=".ActionDetails" />
    </data>
    
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        tools:context=".ActionDetailFragment" >
    
        <TextView
            android:id="@+id/first_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{vm.firstName}"
            tools:text="John"/>
        ...
    </LinearLayout>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-21
      • 2021-05-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-07
      相关资源
      最近更新 更多