android ошибка инициализации модели просмотра фрагмента - PullRequest
1 голос
/ 03 августа 2020

Я пытаюсь реализовать привязку данных в android с помощью kotlin:

override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        mBinding = DataBindingUtil.inflate<ViewDataBinding>(
            inflater, R.layout.fragment_login, container, false
        ) as FragmentLoginBinding
        val view: View = mBinding.root
        mBinding.login?.invoke(viewModel)
        return view
    }

Но он говорит, что lateinit свойство viewModel не было инициализировано во время выполнения. Как я могу это решить?

  • Инициализация во фрагменте будет работать
  • Будет лучше, если вы, ребята, предоставите мне модель просмотра, инициализированную от родителя, родитель - это действие

Ответы [ 3 ]

2 голосов
/ 03 августа 2020

Если вы хотите запустить viewModel в Activity и использовать его во фрагменте, вы можете сделать это следующим образом:

MainActvity.kt:

private lateinit var viewModel: MainActivityVM

override fun onCreate(savedInstanceState: Bundle?)
{
    viewModel = ViewModelProvider(this).get(MainActivityVM::class.java)

    super.onCreate(savedInstanceState)
}

YourFragment.kt:

private lateinit var binding: YourFragmentBinding
private lateinit var viewModel: MainActivityVM

override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View?
{
    binding = DataBindingUtil.inflate(
        inflater,
        R.layout.fragment_your, container, false
    )

    binding.lifecycleOwner = this

    viewModel = ViewModelProvider(requireActivity()).get(MainActivityVM::class.java)

    //here You can use Your viewModel

    return binding.root
}
1 голос
/ 03 августа 2020

lateinit свойства требуют инициализации их перед первым использованием. Ошибка возникает только в том случае, если она не была инициализирована. Вы можете проверить, инициализирован ли lateinit, используя свойство isInitialized интерфейса KProperty0.

val isReadyForUse = ::viewModel.isInitialized

Внутри Fragment вы можете инициализировать ViewModel, используя функция расширения viewModels():

import androidx.fragment.app.viewModels

class YourFragment: Fragment {
    private val viewModel: YourViewModel by viewModels()
}

Он загружается лениво, что означает, что как только вы попытаетесь получить доступ к viewModel, он будет инициализирован и возвращен. В следующий раз инициализация не произойдет.

Если вы хотите, чтобы ваш класс ViewModel сначала загружался в Activity, а затем в Fragment, используйте activityViewModels().

Примечание: после первой инициализации ViewModel с помощью activityViewModels() он будет сохранен в ViewModelStore, принадлежащем Activity. Чтобы создать новый экземпляр YourViewModel с помощью activityViewModels(), вам нужно будет завершить sh свой Activity или очистить хранилище модели представления requireActivity().viewModelStore.clear().

Для инициализации в Activity и используйте фрагмент, сделайте следующее:

class YourActivity {
    override fun onCreate(savedInstanceState: Bundle?) {
        val viewModelInit = ViewModelProvider(this).get(YourViewModel.javaClass)
    }
}

И в Fragment:

import androidx.fragment.app.activityViewModels

class YourFragment: Fragment {
    private val viewModel: YourViewModel by activityViewModels()
}
0 голосов
/ 06 августа 2020

Вот что у меня сработало:

mBinding = DataBindingUtil.inflate<ViewDataBinding>(
            inflater, R.layout.fragment_login, container, false
        ) as FragmentLoginBinding
        val view: View = mBinding.root
        viewModel = ViewModelProvider(requireActivity()).get(AuthViewModel::class.java)
        mBinding.login = viewModel
        return view

В XML:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <data>

        <variable
            name="login"
            type="com........." />
    </data>
    ....
...