Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ViewModelProviders is not working inside my Fragment

This is what I'm trying to do.

  • Set an ArrayList of object inside a Fragment
  • Get that array from an observer within the FragmentActivity container (the activity that hosts all the fragments)

So, What I have done is the following.

First I created the SharedViewModel from where I will set and get the data from :

SharedViewModel.kt

class SharedViewModel: ViewModel() {

    var personArrayObj:MutableLiveData<ArrayList<Person>> = MutableLiveData()

    fun setPersonArray(personArray:ArrayList<Person>){
        personArrayObj.value = personArray
    }

    val getPersonArray:LiveData<ArrayList<Person>>
    get() = personArrayObj

}

Now , I instantiate this ViewModel inside the MainActivity that hosts all the fragments creation, so , I can get the ArrayData from wherever Fragment its set :

MainActivity.kt

class MainActivity: FragmentActivity(){

private lateinit var viewModel:SharedViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        viewModel = ViewModelProviders.of(this).get(SharedViewModel::class.java)
        viewModel.getPersonArray.observe(this, Observer { it:ArrayList<Person>
            Log.d("Array:",""+it)
        })
    }

}

Then the last thing I need to do is to set the value of that Array from whatever Fragment I want, and then the host Activity will be triggered if the value has changed, so, to do this, I simple do a viewModel.setValue(personArray) at my desired Fragment .

The Problem

When I try to instantiate the SharedViewModel inside any fragment I get this problem :

enter image description here

I tried to assert !! for the null, use let too, but is not working and I wonder from where it comes that FragmentActivity required

If I use viewLifecycleOwner instead of activity it says to me that it cant be called either with Fragment or FragmentActivity ?

Any clues?

Thanks .

like image 709
SNM Avatar asked Jun 28 '19 17:06

SNM


People also ask

How do you use ViewModelProvider in Kotlin?

Use the 'by viewModels()' Kotlin property delegate or ViewModelProvider , passing in the fragment. This function is deprecated. Use the 'by viewModels()' Kotlin property delegate or ViewModelProvider , passing in the activity. of (fragment: Fragment, factory: ViewModelProvider.

How do I set a ViewModel in activity?

There are three steps to setting up and using a ViewModel: Separate out your data from your UI controller by creating a class that extends ViewModel. Set up communications between your ViewModel and your UI controller. Use your ViewModel in your UI controller.

What is ViewModelStoreOwner?

A ViewModelStoreOwner is merely an interface. Any class that implements the getViewModelStore() defined by this interface becomes the owner of ViewModelStore . This class then maintains the ViewModelStore and should be responsible to appropriately restoring it when needed.


3 Answers

Fragments offer a helper method for retrieving a non-null Activity - requireActivity(). Use that instead of activity:

viewModel = ViewModelProviders.of(requireActivity()).get(SharedViewModel::class.java)

As an alternative, you can include the fragment-ktx dependency in your app and use the by activityViewModels() Kotlin property extension instead of using ViewModelProviders.of() at all:

val viewModel: SharedViewModel by activityViewModels()
like image 105
ianhanniballake Avatar answered Oct 20 '22 01:10

ianhanniballake


ViewModelProviders.of() is deprecated.So,we can initialize viewmodel like below.

 viewModel = ViewModelProvider(requireActivity()).get(SampleViewModel::class.java)
like image 29
Tarun A Avatar answered Oct 20 '22 03:10

Tarun A


Ok, I was not seeing it

I was making an instance of the viewModel inside my Fragment, and another one, inside my MainActivity, so doing this, we prevent the observer to work.

To solve this, I just made a simple method that returns the instance that I made inside my MainActivity

 fun getViewModelInstance():SharedViewModel = viewModel

Then I just call that instance from any Fragment to work with it

(activity as MainActivity).getViewModelInstance().setPersonArray(personArray)
like image 41
SNM Avatar answered Oct 20 '22 02:10

SNM