【问题标题】:How to write the adapter class for the following recycler view?如何为以下回收器视图编写适配器类?
【发布时间】:2020-04-10 12:10:36
【问题描述】:

我正在尝试制作一个 Todo 应用程序,我已经完成了 Room 部分并且能够存储数据现在我想以 Recycler View 的形式显示数据,但我不知道如何编写与其对应的适配器类.我在不同的网站上寻找它,但从未得到任何满意的答案。

**TodoFragViewModel.kt""

class TodofragViewModel(
    val database: TodoDao, applicaltion: Application
): AndroidViewModel(applicaltion) {
    // TODO: Implement the ViewModel
    /**
     * viewModelJob allows us to cancel all coroutines started by this ViewModel.
     */
    private var viewModelJob = Job()

    /**All coroutines can be cancelled by viewmodelJob.cancel() and Dispatcher.main is byDefault choice
     */
    private val uiScope = CoroutineScope(Dispatchers.Main + viewModelJob)

    private val currenctTodo = MutableLiveData<Todo?>()

    private val allTodo = database.getAllTodo()


    init{
        intializeThisTodo()
    }

    private fun intializeThisTodo(){
        uiScope.launch {
            currenctTodo.value=getFromDatabase()
        }
    }

    private suspend fun getFromDatabase(): Todo? {
        return  withContext(Dispatchers.IO){
            val info =database.getCurrentTodo()
            info

        }
    }



    private suspend fun insert(thisTodo: Todo) {

        withContext(Dispatchers.IO) {

            database.insert(thisTodo)
            Log.i("Database","${database.getCurrentTodo()?.description} and ${database.getCurrentTodo()?.time}")
        }


    }


    fun onAdded(time:String,description:String) {

        uiScope.launch {

            val thisTodo = Todo(time,description)

            insert(thisTodo)

            currenctTodo.value=getFromDatabase()


        }

    }


    /**
     * Called when the ViewModel is dismantled.
     * At this point, we want to cancel all coroutines;
     * otherwise we end up with processes that have nowhere to return to
     * using memory and resources.
     */
    override fun onCleared() {
        super.onCleared()
        viewModelJob.cancel()
    }

}

todo_recycler_view


<androidx.cardview.widget.CardView 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"
    android:layout_width="match_parent" android:layout_height="wrap_content">
<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/date_text"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_marginStart="16dp"
        android:layout_marginTop="16dp"
        android:layout_marginEnd="16dp"
        android:text="TextView"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/todo_description"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="16dp"
        android:layout_marginEnd="16dp"
        android:text="TextView"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/date_text" />


</androidx.constraintlayout.widget.ConstraintLayout>

TodoFrag.kt


class todofrag : Fragment() {

    companion object {
        fun newInstance() = todofrag()
    }

    private lateinit var viewModel: TodofragViewModel

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.todofrag_fragment, container, false)
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        val application = requireNotNull(this.activity).application
        val dataSource= TodoDatabase.getInstance(application)?.InformationDatabaseDao

        val viewModelFactory = dataSource?.let { TodoViewModelFactory(it, application) }
        val viewModel=ViewModelProviders.of(this,viewModelFactory).get(TodofragViewModel::class.java)


        add_button.setOnClickListener{
            val currentDate: String = SimpleDateFormat("dd/MM/yyyy", Locale.getDefault()).format(Date())
            val currentTime: String = SimpleDateFormat("HH:mm:ss", Locale.getDefault()).format(Date())

            val time:String="${currentDate} \n ${currentTime}"

            viewModel.onAdded(time,todo_text.text.toString())

        }

    }

}

如果添加了任何其他文件,请告诉我。顺便说一句,我尝试使用卡片视图以使其看起来不错。

【问题讨论】:

    标签: kotlin android-room android-recyclerview


    【解决方案1】:

    developer documentation 解释得很好。

    这可能并不完全适合您的需求,但它应该是一个好的开始。具体来说,我不知道您的 Todo 类的所有字段,因此请确保您考虑了此代码中的这些字段。

    基本上,您需要一个代表您的CardViewViewHolder

    class TodoViewHolder(convertView: View) : RecyclerView.ViewHolder(convertView) {
      val dateText = convertView.findViewById(R.id.date_text)
      val description = convertView.findViewById(R.id.todo_description)
      // whatever else you need access to
    }
    

    您会希望使用DiffUtil 来获得更好的用户体验。当列表中的事物发生变化时,这允许一些动画,例如删除项目、编辑项目或添加项目。

    private class TodoDiffCallback : DiffUtil.ItemCallback<Todo>() {
      override fun areItemsTheSame(oldItem: Todo, newItem: Todo) =
        oldItem.id == newItem.id
    
      override fun areContentsTheSame(oldItem: Todo, newItem: Todo) =
        oldItem.dateText == newItem.dateText && oldItem.description == newItem.description
    
    }
    

    您需要扩展 ListAdapter 并覆盖其方法。 onCreateViewHolder 为看到的每个视图创建TodoViewHolder 的实例,onBindViewHolder 允许您向列表中的每个项目添加行为。值得注意的是,您可以在需要时将参数传递给适配器。

    class MyListAdapter : ListAdapter<Todo, TodoViewHolder>(TodoDiffCallback()) {
      override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = TodoViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.todo_recycler_view, parent, false))
    
      override fun onBindViewHolder(holder: TodoViewHolder, position: Int) {
        val todo = getItem(position)
        holder.dateText = todo.dateText
        holder.description = todo.description
        // add whatever click listener and other stuff you need
      }
    }
    

    在您的片段中,当您访问您的RecyclerView 时,只需添加一个适配器实例(如果它为空)。

    if (recyclerView.adapter == null) {
      recyclerView.adapter = TotoListAdapter()
    }
    

    当您想要将数据(您从 Room 或您的 API 检索到的数据)添加到适配器(在片段/活动中)时,只需执行以下操作:

    (recyclerView.adapter as? TodoListAdapter)?.submitList(data)
    

    附带说明,请确保清理您的样式(您可以使用Code 菜单中的Reformat Code 命令),并且您希望将todo_recycler_view 重命名为todo_view 之类的名称。您需要在片段布局中使用 RecyclerView 布局。

    【讨论】:

    • 我有疑问,这里(recyclerView.adapter as? TodoListAdapter)?.submitList(data)在哪里接收数据,意味着上面的代码在片段文件中,但我们在适配器文件中的哪里接受它。
    • @AshutoshPanda 我不完全确定我理解你的评论。是的,对submitList 的调用在片段中(就像在 LiveData 的 observe 回调中一样,它可能从存储库中获取它,它可能从服务器或 Room 或 Sqlite 获取它)。适配器将负责其余的工作,因此您不需要额外的代码来接收适配器中的数据。我已经更新了答案以反映这一点。
    • 我的意思是函数的主体在哪里** submitList(data) **?
    • 这是适配器的功能。您无需创建或覆盖它。它将使用 DiffUtil 查看列表中的任何内容是否已更改,并对您的视图进行必要的更新。请参阅developer.android.com/reference/kotlin/androidx/recyclerview/… 了解更多信息
    • 如果你想探索函数和类的内部结构,右击函数,点击Go To,然后Declaration and Usages。这将带你到它的源代码。如果您使用的是 Mac,则快捷方式是 command-B。如果您在 PC 上,则必须查找快捷方式。
    猜你喜欢
    • 2016-04-05
    • 1970-01-01
    • 2019-05-03
    • 1970-01-01
    • 2015-11-15
    • 1970-01-01
    • 2017-04-28
    • 1970-01-01
    相关资源
    最近更新 更多