Architecture-components-samples: GithubBrowserSample: demonstrate a way to communicate among ViewModels

Created on 26 Jul 2017  路  5Comments  路  Source: android/architecture-components-samples

Hi!

I was looking at a way for one ViewModel to access another ViewModel and see if there any good practice to do so.
Unfortunately (unless I just didn't find it) this sample doesn't demonstrate a way to do this.

The ViewModel guide talks about how you can "Share Data Between Fragments" with a "shared ViewModel" but with no sample of how to share data between ViewModels.

Most helpful comment

I'm not sure why you're saying this is not the purpose of ViewModel. They allow to separate UI logic from other kinds of logic. In that sense, you could have one piece in one ViewModel that depends on something that is in another one.

For instance: let's say you have a "search query" fragment where the user can fill some criteria. Then you have a results fragment. But you also want a "search summary" fragment, that shows some info about the search, including the query that comes from the "search query" fragment.
To do that, the "search summary" ViewModel needs to observe some objects that are managed by the "search query" ViewModel.

All 5 comments

As I understand That's not the purpose of ViewModel. But in the end you could benfit from using ViewModel and LiveData together. Hence, you can use Transformations which let you take action based on on change in other LiveData; The sample provide some examples.

And here in Docs, explains how to share ViewModels between fragments.

I'm not sure why you're saying this is not the purpose of ViewModel. They allow to separate UI logic from other kinds of logic. In that sense, you could have one piece in one ViewModel that depends on something that is in another one.

For instance: let's say you have a "search query" fragment where the user can fill some criteria. Then you have a results fragment. But you also want a "search summary" fragment, that shows some info about the search, including the query that comes from the "search query" fragment.
To do that, the "search summary" ViewModel needs to observe some objects that are managed by the "search query" ViewModel.

I assume in this case your LifecycleOwner will be the host Activity for those Fragments so the ViewModel the Activity creates will be accessible to all of its Fragments.

I think the question has been answered, closing for now!

[Question] is below:

but with no sample of how to share data between ViewModels.

Nobody has been answer.... ((鞙犫垁鞙爘||))聽

@BoD

Share data between ViewModels is hard! Not only conside share data but also have to manage the viewmodels's lifecycle!

My way to share data between ViewModels that in the same activity or fragment:

class GroupViewModels extends ViewModel {
   private A_ViewModel aVM;
   private B_ViewModel bVM;

   priavte BehSubject<Boolean> killSwitcher;

  public GroupViewModels (...) {
    aVM = new A_ViewModel(...);
    bVM = new B_ViewModel(...);

   killSwitcher= BehaviorSubject.create();
 }

public void onClear() {
    killSwitcher.onNext(Boolean.TRUE);
    aVM.onClear();
    bVM.onClear();
}

 public Observable<Event> OnNextEvent () {
  return aVM.OnNextEvent().flatMap(new Function<...>() {
    // dosth;
    returen bVM.OnNextEvent();
  })
  .takeUntil(killSwitcher);
}

....

or

Way 2:

class GroupViewModels extends ViewModel {
   private A_ViewModel aVM;
   private B_ViewModel bVM;

   priavte BehSubject<Boolean> killSwitcher;

  public GroupViewModels (A_ViewModel a, B_ViewModel  b) {
    aVM = a;
    bVM = b;

    // share data between ViewModels. eg:
    //a.subcribe(b);
   // b.subcribe(a);

   killSwitcher= BehaviorSubject.create();
 }

public void onClear() {
    killSwitcher.onNext(Boolean.TRUE);

    // don not need to call onClear() !!!
    // aVM.onClear();
    // bVM.onClear();
}

public Observable<Event> OnNextEvent () {
  return aVM.OnNextEvent().flatMap(new Function<...>() {
    // share data between ViewModels.
    returen bVM.OnNextEvent();
  })
  .takeUntil(killSwitcher);
}


public abstract class ShareViewModelFactory implements ViewModelProvider.Factory {

    private final Map<Class<? extends ViewModel>, Provider<ViewModel>> mCreators;

    public ShareViewModelFactory(Map<Class<? extends ViewModel>, Provider<ViewModel>> creators) {
        mCreators = creators;
        mShareCache = new HashMap<>();
    }

    @SuppressWarnings("unchecked")
    @Override
    public <T extends ViewModel> T create(Class<T> modelClass) {
        Provider<? extends ViewModel> creator = mCreators.get(modelClass);
        if (creator == null) {
            for (Map.Entry<Class<? extends ViewModel>, Provider<ViewModel>> entry : mCreators.entrySet()) {
                if (modelClass.isAssignableFrom(entry.getKey())) {
                    creator = entry.getValue();
                    break;
                }
            }
        }

        if (creator == null) {
            throw new IllegalArgumentException("unknown model class " + modelClass);
        }

        try {
            return (T) creator.get();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}



// Usage: 

class XXXActivity {
  public void onCreate() {
      Map<Class<? extends ViewModel>, Provider<ViewModel>> creators = new HashMap<>();
      final ViewModelProvider.Factory factory = new ShareViewModelFactory(creators);

      creators.put(A_ViewModel.class, ...);
      creators.put(B_ViewModel.class, ...);

      creators.put(GroupViewModels.class, new Provider<ViewModel>() {
             ViewModel get() {
                 return new GroupViewModel(
                              ViewModelProvider.of(XXXActivity.this, factory).get(A_ViewModel.class),
                              ViewModelProvider.of(XXXActivity.this, factory).get(B_ViewModel.class),
                 )
             }
     } );

    GroupViewModels gVm= ViewModelProvider.of(XXXActivity.this, factory).get(GroupViewModels .class);
  }
}

Warning:

No circular reference like below, please!

 GroupViewModels(A_ViewModel a, B_ViewModel b);

A_ViewModel (GroupViewModels g);

B_ViewModel (GroupViewModels g)

Was this page helpful?
0 / 5 - 0 ratings