Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sharing Data between ViewModels

I have a complex screen in my project which I'm breaking in more than one fragment. I'm trying to follow the MVVM architecture for these classes, so which fragment has its own ViewModel and Contract class.

The issue is that all the ViewModels needs the same object instance (let's call it Book) to do Room transactions.

Does it have a correct way to share data (or LiveData) between ViewModels? I know the concept of Shared ViewModel but I don't know if I can apply it to this case. I also thought about using MediatorLiveData but didn't get a good approach on it too.

I'm thinking about having a class (let's call BookObservableProvider) with a LiveData<Book> (or Rx Subject<Book>) where each ViewModel injects the same instance and load/update always the same value.

Is it a good approach?

like image 523
Igor Escodro Avatar asked Sep 11 '25 00:09

Igor Escodro


1 Answers

The answer is as usual, it depends. If the reason behind your question is Room access, then it is recmended to have a DataRepository class that handles all Database access and you just pass that repository singleton to each AndroidViewModel.

mRepository = ((MainApp) application).getRepository();

In MainApp:

public DataRepository getRepository() {
    return DataRepository.getInstance(getDatabase(), mAppExecutors);
}

And the Repository:

public class DataRepository {

    private static DataRepository sInstance;
    private MediatorLiveData<String> mObservableString;

    private DataRepository(final AppDatabase database, final AppExecutors executors) {
        mObservableString.addSource(database.myDao().loadString(),
            mString -> {
                if (database.getDatabaseCreated().getValue() != null) {
                    mObservableString.postValue(mString);
                }
            });
    }

    public static DataRepository getInstance(final AppDatabase database, final AppExecutors executors) {
        if (sInstance == null) {
            synchronized (DataRepository.class) {
                if (sInstance == null) {
                    sInstance = new DataRepository(database, executors);
                }
            }
        }
        return sInstance;
    }
    
    // and then your access methods
    
    public LiveData<String> getString() {
        return mObservableString;
    }

In the repository it is recommended to have a MediatorLivedata if you want to change the reference (source). Otherwise a normal LiveData does the job.

Regarding ViewModels:

In theory each fragment gets it's own Viewmodel. And if you get it by using requireActivity() as reference, you can get each ViewModel everywhere and have it therefore shared.

As an example:

    viewModelA = new ViewModelProvider(requireActivity()).get(ViewModelA.class);
    viewModelB = new ViewModelProvider(requireActivity()).get(ViewModelB.class);

This you could call in every Fragment and get the same ViewModel instances. If the DataRepository setup seems overkill to you, make one ViewModel with Room access and load it from every Fragment.

like image 153
Tobi Avatar answered Sep 12 '25 12:09

Tobi