Muhammad Ahmed AbuTalib
Muhammad Ahmed AbuTalib

Reputation: 4292

sharing data between fragments via viewmodels

According to the section "Share data between fragments" at https://developer.android.com/topic/libraries/architecture/viewmodel we are told that creating a ViewModel in the activity scope and sharing that amongst the fragments is the way to go.

This is the Fragment which sets the value in the ViewModel

class MasterFragment : Fragment() {

    private lateinit var itemSelector: Selector

    private lateinit var model: SharedViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        model = activity?.run {
            ViewModelProviders.of(this).get(SharedViewModel::class.java)
        } ?: throw Exception("Invalid Activity")
        itemSelector.setOnClickListener { item ->
            // Update the UI
        }
    }
}

This is the detail fragment which uses the property set

class DetailFragment : Fragment() {

    private lateinit var model: SharedViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        model = activity?.run {
            ViewModelProviders.of(this).get(SharedViewModel::class.java)
        } ?: throw Exception("Invalid Activity")
        model.selected.observe(this, Observer<Item> { item ->
            // Update the UI
        })
    }
}

This is the ViewModel

class SharedViewModel : ViewModel() {
    val selected = MutableLiveData<Item>()

    fun select(item: Item) {
        selected.value = item
    }
}

My question is simple. Assuming the MasterFragment set a value in the ViewModel on a button click, how would we recover that value when accessing it AFTER THE SYSTEM HAS KILLED OUR APPLICATION AND RESTARTED IT ?.

Our DetailFragment will not be seeing the value since we were setting it on the button click in the MasterFragment. To understand the question better, consider we have Fragment A, B, C, and D and they share a ViewModel which has a value Fragment A B and C together computed and placed it in ViewModel for Fragment D to access.

Now when the system kills and recreates our application Fragment D won't have that value available.

OnSaveInstance also won't be able to help out much without resorting to dirty code. For simple situations, yes , but like the one in which FragmentA B and C together are making a value, in that situation, OnSaveInstance would be problematic.

OnSaveInstance should have been inside the ViewModel but alas I don't think that's the case. Any ideas?

Upvotes: 0

Views: 6615

Answers (3)

Pedro Henrique
Pedro Henrique

Reputation: 141

For those using Kotlin out there try the following approach:

  • Add the androidx ViewModel and LiveData libraries to your gradle file

  • Call your viewmodel inside the fragment like this:

     class MainFragment : Fragment() {
    
       private lateinit var viewModel: ViewModel
    
       override fun onActivityCreated(savedInstanceState: Bundle?) {
           super.onActivityCreated(savedInstanceState)
    
           // kotlin does not have a getActivity() built in method instead we use activity, which is null-safe
           activity?.let {
               viemModel = ViewModelProvider(it).get(SharedViewModel::class.java)
           }
       }
    }
    

Upvotes: 0

Viraj Patel
Viraj Patel

Reputation: 2393

ViewModel objects are scoped to the Lifecycle passed to the ViewModelProvider when getting the ViewModel. The ViewModel remains in memory until the Lifecycle it's scoped to goes away permanently: in the case of an activity, when it finishes, while in the case of a fragment, when it's detached.

You can check it here

My question is simple. Assuming the MasterFragment set a value in the ViewModel on a buttonClick , how would we recover that value when accessing it AFTER THE SYSTEM HAS KILLED OUR APPLICATION AND RESTARTED IT ?.

You can't recover the value if the application is killed by the user or system or restarted.

To solve your purpose of accumulating data from Activity A, B and C and display it in Activity D even though the application is killed or restarted, you can choose any 1 method from the following:
1. SharedPreference
2. Local Database Room or SQLite
3. Store data in a file

I recommend you to use SharedPreference for small data and Room for Large and Complex data.

In a nutshell, ViewModel stores data temporary to survive orientation change(no need to write code of onSaveInstanceState and onRestoreInstanceState) and share data between Activities and Fragments. Data will be lost if the activity is destroyed or fragment is detached.

Upvotes: 7

Antonis Radz
Antonis Radz

Reputation: 3097

If you still want to get stored value after app reset or killed you need to save data to SharedPreferences or internal SqLite database and restore it after app start.

Upvotes: 1

Related Questions