Why is my ViewModel null in Fragment but not Fragment’s bound layout?

  android, fragment, kotlin, layout, viewmodel

I have a FooActivity: AppCompatActivity() that uses a FooViewModel to look up a Foo from a database and then present information about it in a few Fragments. Here’s how I set it up:

private lateinit var viewModel: FooViewModel

override fun onCreate(savedInstanceState: Bundle?) {

    super.onCreate(savedInstanceState)
    // Get the Intent that started this activity and extract the FOO_ID
    val id = intent.getLongExtra(FOO_ID, 1L)
    val viewModelFactory = FooViewModelFactory(
        id,
        FooDatabase.getInstance(application).fooDao,
        application)
    viewModel = ViewModelProviders.of(
        this, viewModelFactory).get(FooViewModel::class.java)

    // FooViewModel is bound to Activity's Fragments, so must
    // create FooViewModelFactory before trying to bind/inflate layout
    binding = DataBindingUtil.setContentView(this, R.layout.activity_foo)
    binding.lifecycleOwner = this
    binding.viewModel = viewModel
}

And in the FooInfoFragment class:

private val viewModel: FooViewModel by activityViewModels()

override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    super.onCreateView(inflater, container, savedInstanceState)
    val binding = FragmentFooInfoBinding.inflate(inflater)
    binding.setLifecycleOwner(this)
    binding.viewModel = viewModel
    // normally viewModel.foo shouldn't be null here, right?
    return binding.root
}

So far so good. My layout shows the various info of the Foo, eg @{viewModel.foo.name}.

The issue is that in my FooInfoFragment.onCreateView when I attempt to access viewModel.foo.value?.name after binding it’s null.

    binding.viewModel = viewModel
    Log.wtf(TAG, "${viewModel.foo.value?.name} shouldn't be null!")
    return binding.root

I don’t understand why it’s null in my Fragment but not in my layout. Help?

Source: Android Questions

LEAVE A COMMENT