Ошибка lateinit property binding has not been initialized

Хочу перенести приложение для заметок из Activity в Fragment. В Activity все работало без ошибок, но как перенес начались проблемы. При запуске и выборе фрагмента приложение вылетает и выдает lateinit property binding has not been initialized, как это исправить?

class PlannedEvFragment : Fragment(R.layout.fragment_planned_ev){
    private lateinit var binding: FragmentPlannedEvBinding
    private lateinit var noteViewModel: NoteViewModel
    private lateinit var adapter: NoteRecyclerViewAdapter

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val dao = NoteDatabase.getInstance(activity!!.application).noteDAO
        val repository = NoteRepository(dao)
        val factory = NoteViewModelFactory(repository)
        noteViewModel = ViewModelProvider(this, factory).get(NoteViewModel::class.java)

        binding.noteViewModel = noteViewModel    <-- на этой строчке выдает ошибку

        binding.lifecycleOwner = this
        displayNoteList()
        initRecyclerView()

        nnoteViewModel.message.observe(this, Observer {
            it.getContentIfNotHandled()?.let {
                Toast.makeText(activity!!.application, it, Toast.LENGTH_SHORT).show()
            }
        })
    }

    private fun initRecyclerView(){
        adapter = NoteRecyclerViewAdapter({ selectedItem: Note -> listItemClicked(selectedItem) })
        binding.noteRecyclerView.layoutManager = LinearLayoutManager(context)
        binding.noteRecyclerView.adapter = adapter
        displayNoteList()
    }

    private fun displayNoteList(){
        noteViewModel.notes.observe(this, Observer {
            Log.i("MYTAG", it.toString())
            adapter.setList(it)
            adapter.notifyDataSetChanged()
        })
    }
    private fun listItemClicked(note: Note){
        noteViewModel.initUpdateAndDelete(note)
    }
}

Фрагмент:

<?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="noteViewModel"
            type="com.example.taskmanager.view.NoteViewModel" />

    </data>

Ответы (2 шт):

Автор решения: Sergei Buvaka

Я не очень хорошо знаком с Data Binding, но, думаю я знаю где ваша проблема.

Ошибка lateinit property binding has not been initialized говорит о том, что есть некоторое поле (в вашем случае binding которое не инициализированно, т.е. null).

Тут есть 2 варианта:

  • Либо вы в принципе не вызвали методы инициализации binding в коде. Я их не вижу, поэтому вполне вероятно, что ваша проблема лежит здесь.

  • Но тут может быть такое, что система делает это под капотом (это к тому, что я не знаю как правильно должны инициализироваться биндинги в Data Bindnig). Если вы говорите, что данный код работал в Activity успешно, то скорее всего вам нужно перенести всю инициализацию (в частности любые вызовы binding) любой колбек жизненного цикла фрагмента начиная с onViewCreated() или более поздний.

    Связано это с тем, что в Activity ваша View вам доступна уже в методе onCreate() после вызова setContentView() и там ваш биндинг мог обратиться ко View. Во фрагменте в методе onCreate() никакой View еще не существует, макет раздувается в методе onCreateView() и готов к использованию уже в onViewCreated()

→ Ссылка
Автор решения: AVRamones
  1. Необходимо добавить метод onCreateView(). В нем инициализировать binding :

     override fun onCreateView(
         inflater: LayoutInflater,
         container: ViewGroup?,
         savedInstanceState: Bundle?
     ): View? {
    
     binding = DataBindingUtil.inflate(inflater, layoutId, container, false)
    
     return binding.root
     }
    
  2. Необходимо вынести логику из метода onCreate в метод onViewCreated()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
     super.onViewCreated(view, savedInstanceState)
    
     val dao = NoteDatabase.getInstance(activity!!.application).noteDAO
     val repository = NoteRepository(dao)
     val factory = NoteViewModelFactory(repository)
     noteViewModel = ViewModelProvider(this, factory).get(NoteViewModel::class.java)
    
     binding.noteViewModel = noteViewModel
    
     binding.lifecycleOwner = this
     displayNoteList()
     initRecyclerView()
    
     nnoteViewModel.message.observe(this, Observer {
         it.getContentIfNotHandled()?.let {
             Toast.makeText(activity!!.application, it, Toast.LENGTH_SHORT).show()
         }
     })
    
    }
    
→ Ссылка