@vladis005
Начинающий веб разработчик

Почему выдает ошибку required value was null при передачи данных между фрагментами?

Всем привет! Пишу таск трекер. Хочу по нажатию на название задачи открывать детали о ней в другом фрагменте. Сразу говорю на всякий случай что юзаю data class вместо view model здесь. Данные передаю через deeplink. Выдает ошибку required value was null. Подозреваю что дело в самом диплинке а именно в curTodo. Если не писать в этом диплинки аргументы, а просто URI для простой навигации app://taskmaster.taskDetailFragment то все гуд, а вот если писать как в исхоном коде, то начинаются проблемы. Что делать не знаю, срочно надо как-то починиться. Буду благодарна за помощь!

TodoAdapter

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
              }

              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)
              }

              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()
              }
        }
    }

    override fun getItemCount(): Int {
          return todos.size
    }

}


TaskDetailFragment
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

    }
}


TaskListFragment
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
            )
        )
    }

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }

    companion object{
        const val TASK_DETAIL_URI = "app://taskmaster.taskDetailFragment"
    }
}


task_graph
<?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}&amp;taskDateBundleKey={taskDateBundleKey}" />
        <argument
            android:name="taskBundleKey"
            app:argType="string" />
        <argument
            android:name="taskDateBundleKey"
            app:argType="string" />
    </fragment>
</navigation>
  • Вопрос задан
  • 101 просмотр
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы