我想通过单击任务标题来打开包含任务详细信息的屏幕。所以我想将数据(标题和日期以及说明)发送到此屏幕。但我有一个错误,要求值为空。我不使用视图模型。我使用数据类。我想我就是因为这个才遇到这个问题的。无论如何,我想找到一个不使用视图模型的解决方案。
Todo适配器
package com.bignerdranch.android.taskmaster
import android.graphics.Paint.STRIKE_THRU_TEXT_FLAG
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.CheckBox
import android.widget.TextView
import androidx.core.net.toUri
import androidx.navigation.NavDeepLinkRequest
import androidx.navigation.findNavController
import androidx.navigation.fragment.NavHostFragment
import androidx.recyclerview.widget.RecyclerView
import com.bignerdranch.android.taskmaster.Constants.TASK_BUNDLE_KEY
import com.bignerdranch.android.taskmaster.Constants.TASK_DATE_BUNDLE_KEY
import com.bignerdranch.android.taskmaster.TaskListFragment.Companion.TASK_DETAIL_URI
import com.bignerdranch.android.taskmaster.databinding.ItemTodoBinding
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
class TodoAdapter(
private var todos: MutableList<Todo>, private val todoDao: TodoDao
):RecyclerView.Adapter<TodoAdapter.TodoViewHolder>() {
class TodoViewHolder( ItemTodoBinding: ItemTodoBinding): RecyclerView.ViewHolder(ItemTodoBinding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TodoViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val ItemTodoBinding = ItemTodoBinding.inflate(layoutInflater, parent, false)
return TodoViewHolder(
return TodoViewHolder(ItemTodoBinding)
)
}
private fun toggleStrikeThrough(tvTodoTitle: TextView, isChecked:Boolean){
if(isChecked){
tvTodoTitle.paintFlags = tvTodoTitle.paintFlags or STRIKE_THRU_TEXT_FLAG
}else{
tvTodoTitle.paintFlags = tvTodoTitle.paintFlags and STRIKE_THRU_TEXT_FLAG.inv()
}
}
override fun onBindViewHolder(holder: TodoViewHolder, position: Int) {
val curTodo = todos[position]
holder.itemView.apply{
val tvTodoTitle = findViewById(R.id.tvTodoTitle) as TextView
tvTodoTitle.text = curTodo.title
val cbDone = findViewById(R.id.cbDone) as CheckBox
val deleteBtn = findViewById(R.id.deleteBtn) as Button
cbDone.isChecked = curTodo.isChecked
toggleStrikeThrough(tvTodoTitle, curTodo.isChecked)
cbDone.setOnCheckedChangeListener { _, isChecked ->
toggleStrikeThrough(tvTodoTitle, isChecked)
curTodo.isChecked = !curTodo.isChecked
}
cbDone.setOnClickListener(View.OnClickListener{
GlobalScope.launch {
todoDao.update(curTodo)
todoDao.delete(curTodo)
}
todos.removeAll { todo ->
todo.isChecked
}
notifyDataSetChanged()
})
deleteBtn.setOnClickListener{
GlobalScope.launch {
todoDao.delete(curTodo)
}
notifyDataSetChanged()
}
tvTodoTitle.setOnClickListener {
val request = NavDeepLinkRequest.Builder
.fromUri("${TASK_DETAIL_URI}?${TASK_BUNDLE_KEY}=${curTodo.title}&${TASK_DATE_BUNDLE_KEY}=${curTodo.date}&${TASK_DESCR_BUNDLE_KEY}=${curTodo.description}".toUri())
.build()
findNavController().navigate(request)
}
}
}
override fun getItemCount(): Int {
return todos.size
}
}
任务列表片段
class TaskListFragment : Fragment(R.layout.fragment_task_list) {
private lateinit var todoAdapter: TodoAdapter
private var _binding: FragmentTaskListBinding? = null
private lateinit var todoDao: TodoDao
private val binding: FragmentTaskListBinding
get() = checkNotNull(_binding)
private var todos: MutableList<Todo> = mutableListOf()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val appDatabase = AppDatabase.getInstance(this.requireActivity())
todoDao = appDatabase.todoDao()
todoDao.getAllTasks().observe(this, Observer { todoList ->
todos.clear()
todos.addAll(todoList)
todoAdapter.notifyDataSetChanged()
})
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentTaskListBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
todoAdapter = TodoAdapter(todos, todoDao)
binding.rvTodoItems.adapter = todoAdapter
binding.rvTodoItems.layoutManager = LinearLayoutManager(this.activity)
binding.btnAddTodo.setOnClickListener {
NewTaskSheet().show(requireActivity().supportFragmentManager, "NewTaskTag")
}
requireActivity().supportFragmentManager.setFragmentResultListener(
"requestKey",
this
) { requestKey, bundle ->
val newTodo = bundle.getSerializable("bundleKey") as Todo
GlobalScope.launch {
todoDao.insert(newTodo)
}
todoAdapter.notifyDataSetChanged()
}
binding.rvTodoItems.addItemDecoration(
DividerItemDecoration(
binding.rvTodoItems.getContext(),
DividerItemDecoration.VERTICAL
)
)
}
任务详细信息片段
class TaskDetailFragment : Fragment() {
private var _binding: FragmentTaskDetailBinding? = null
private val binding: FragmentTaskDetailBinding
get() = checkNotNull(_binding)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val title = arguments?.getString(TASK_BUNDLE_KEY)
val date = arguments?.getString(TASK_DATE_BUNDLE_KEY)
val descr = arguments?.getString(TASK_DESCR_BUNDLE_KEY)
binding.taskTitle.setText(title.toString())
binding.selectedDate.setText(date.toString())
binding.selectedDescription.setText(descr.toString())
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentTaskDetailBinding.inflate(inflater, container, false)
return binding.root
}
}
常数
object Constants {
const val TASK_BUNDLE_KEY = "taskBundleKey"
const val TASK_DATE_BUNDLE_KEY = "taskDateBundleKey"
const val TASK_DESCR_BUNDLE_KEY = "taskDescrBundleKey"
}
任务图
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/task_graph"
app:startDestination="@id/taskListFragment">
<fragment
android:id="@+id/taskListFragment"
android:name="com.bignerdranch.android.taskmaster.TaskListFragment"
android:label="TaskListFragment" />
<fragment
android:id="@+id/taskDetailFragment"
android:name="com.bignerdranch.android.taskmaster.TaskDetailFragment"
android:label="TaskDetailFragment">
<deepLink
android:id="@+id/deepLink"
app:uri="app://taskmaster.taskDetailFragment?taskBundleKey={taskBundleKey}&taskDateBundleKey={taskDateBundleKey}" />
<argument
android:name="taskBundleKey"
app:argType="string" />
<argument
android:name="taskDateBundleKey"
app:argType="string" />
</fragment>
<deepLink
android:id="@+id/deepLink2"
app:uri="app://taskmaster.taskDetailFragment" />
</navigation>
这段代码应该在onViewCreated中:
val title = arguments?.getString(TASK_BUNDLE_KEY)
val date = arguments?.getString(TASK_DATE_BUNDLE_KEY)
val descr = arguments?.getString(TASK_DESCR_BUNDLE_KEY)
binding.taskTitle.setText(title.toString())
binding.selectedDate.setText(date.toString())
binding.selectedDescription.setText.(descr.toString())