Skip to content

Commit

Permalink
Simplify injection of ViewModelProvider.Factory instances by using Mu…
Browse files Browse the repository at this point in the history
…ltibinding.

Adding a ViewModel now only requires adding one method in ViewModelModule and no changes in GithubViewModelFactory.
  • Loading branch information
cypressious committed May 24, 2017
1 parent bf256af commit 619ef78
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 72 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,14 @@

package com.android.example.github.di;

import android.app.Application;
import android.arch.persistence.room.Room;

import com.android.example.github.api.GithubService;
import com.android.example.github.db.GithubDb;
import com.android.example.github.db.RepoDao;
import com.android.example.github.db.UserDao;
import com.android.example.github.util.LiveDataCallAdapterFactory;
import com.android.example.github.viewmodel.GithubViewModelFactory;

import android.app.Application;
import android.arch.lifecycle.ViewModelProvider;
import android.arch.persistence.room.Room;

import javax.inject.Singleton;

Expand All @@ -34,7 +32,7 @@
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

@Module(subcomponents = ViewModelSubComponent.class)
@Module(includes = ViewModelModule.class)
class AppModule {
@Singleton @Provides
GithubService provideGithubService() {
Expand All @@ -60,11 +58,4 @@ UserDao provideUserDao(GithubDb db) {
RepoDao provideRepoDao(GithubDb db) {
return db.repoDao();
}

@Singleton
@Provides
ViewModelProvider.Factory provideViewModelFactory(
ViewModelSubComponent.Builder viewModelSubComponent) {
return new GithubViewModelFactory(viewModelSubComponent.build());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.android.example.github.di;

import android.arch.lifecycle.ViewModel;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import dagger.MapKey;

@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@MapKey
@interface ViewModelKey {
Class<? extends ViewModel> value();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.android.example.github.di;

import android.arch.lifecycle.ViewModel;
import android.arch.lifecycle.ViewModelProvider;

import com.android.example.github.ui.repo.RepoViewModel;
import com.android.example.github.ui.search.SearchViewModel;
import com.android.example.github.ui.user.UserViewModel;
import com.android.example.github.viewmodel.GithubViewModelFactory;

import dagger.Binds;
import dagger.Module;
import dagger.multibindings.IntoMap;

@Module
abstract class ViewModelModule {
@Binds
@IntoMap
@ViewModelKey(UserViewModel.class)
abstract ViewModel bindUserViewModel(UserViewModel userViewModel);

@Binds
@IntoMap
@ViewModelKey(SearchViewModel.class)
abstract ViewModel bindSearchViewModel(SearchViewModel searchViewModel);

@Binds
@IntoMap
@ViewModelKey(RepoViewModel.class)
abstract ViewModel bindRepoViewModel(RepoViewModel repoViewModel);

@Binds
abstract ViewModelProvider.Factory bindViewModelFactory(GithubViewModelFactory factory);
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -16,42 +16,30 @@

package com.android.example.github.viewmodel;

import com.android.example.github.di.ViewModelSubComponent;
import com.android.example.github.repository.RepoRepository;
import com.android.example.github.repository.UserRepository;
import com.android.example.github.ui.repo.RepoViewModel;
import com.android.example.github.ui.search.SearchViewModel;
import com.android.example.github.ui.user.UserViewModel;

import android.arch.lifecycle.ViewModel;
import android.arch.lifecycle.ViewModelProvider;
import android.support.v4.util.ArrayMap;

import java.util.Map;
import java.util.concurrent.Callable;

import javax.inject.Inject;
import javax.inject.Provider;
import javax.inject.Singleton;

@Singleton
public class GithubViewModelFactory implements ViewModelProvider.Factory {
private final ArrayMap<Class, Callable<? extends ViewModel>> creators;
private final Map<Class<? extends ViewModel>, Provider<ViewModel>> creators;

@Inject
public GithubViewModelFactory(ViewModelSubComponent viewModelSubComponent) {
creators = new ArrayMap<>();
// we cannot inject view models directly because they won't be bound to the owner's
// view model scope.
creators.put(SearchViewModel.class, () -> viewModelSubComponent.searchViewModel());
creators.put(UserViewModel.class, () -> viewModelSubComponent.userViewModel());
creators.put(RepoViewModel.class, () -> viewModelSubComponent.repoViewModel());
public GithubViewModelFactory(Map<Class<? extends ViewModel>, Provider<ViewModel>> creators) {
this.creators = creators;
}

@SuppressWarnings("unchecked")
@Override
public <T extends ViewModel> T create(Class<T> modelClass) {
Callable<? extends ViewModel> creator = creators.get(modelClass);
Provider<? extends ViewModel> creator = creators.get(modelClass);
if (creator == null) {
for (Map.Entry<Class, Callable<? extends ViewModel>> entry : creators.entrySet()) {
for (Map.Entry<Class<? extends ViewModel>, Provider<ViewModel>> entry : creators.entrySet()) {
if (modelClass.isAssignableFrom(entry.getKey())) {
creator = entry.getValue();
break;
Expand All @@ -62,7 +50,7 @@ public <T extends ViewModel> T create(Class<T> modelClass) {
throw new IllegalArgumentException("unknown model class " + modelClass);
}
try {
return (T) creator.call();
return (T) creator.get();
} catch (Exception e) {
throw new RuntimeException(e);
}
Expand Down

0 comments on commit 619ef78

Please sign in to comment.