Dagger 2 множественных хранилища - PullRequest
0 голосов
/ 17 сентября 2018

Так что я новичок в Dagger 2 зависимости.Я создал собственный класс ViewModelFactory, который возвращает мой ViewModel.

@Singleton
public class CustomViewModelFactory implements ViewModelProvider.Factory {
    private final MyCatchesRepository repository;

    @Inject
    public CustomViewModelFactory(MyCatchesRepository repository) {
        this.repository = repository;
    }

    @NonNull
    @Override
    @SuppressWarnings("unchecked")
    public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
        if (modelClass.isAssignableFrom(MyCatchViewModel.class)) {
            return (T) new MyCatchViewModel(repository);
        } else {
            throw new IllegalArgumentException("ViewModel Not Found");
        }
    }
}

. CustomViewModel принимает MyCatchesRepository в конструкторе, а затем создает MyCatchViewModel.Как я могу изменить этот класс, чтобы я мог использовать этот ViewModelFactory для создания разных ViewModel с разными аргументами конструктора (репозитории)

Это модуль, в котором создается CustomViewModelFactory

@Module
public class RoomModule {

    private final MyDatabase myDatabase;

    public RoomModule(Application application) {
        this.myDatabase = Room.databaseBuilder(application,
                            MyDatabase.class, AppConstants.DATABASE_NAME)
                            .build();
    }

    @Provides
    @Singleton
    MyCatchesRepository provideCatchesRepository(MyCatchDao myCatchDao) {
        return new MyCatchesRepository(myCatchDao);
    }

    @Provides
    @Singleton
    MyCatchDao providesCatchDao(MyDatabase myDatabase) {
        return myDatabase.myCatchDao();
    }


    @Provides
    @Singleton
    LuresRepository provideLureRepository(LureDao lureDao) {
        return new LuresRepository(lureDao);
    }

    @Provides
    @Singleton
    LureDao provideLureDao(MyDatabase myDatabase) {
        return myDatabase.lureDao();
    }

    @Provides
    @Singleton
    MyDatabase provideDatabase(Application application) {
        return myDatabase;
    }

    @Provides
    @Singleton
    ViewModelProvider.Factory provideCatchesViewModelFactory(MyCatchesRepository catchesRepository) {
        return new CustomViewModelFactory(catchesRepository);
    }
}

ViewModelModule

@Module
public abstract class ViewModelModule {

    @Binds
    @IntoMap
    @ViewModelKey(MyCatchViewModel.class)
    abstract ViewModel myCatchViewModel(MyCatchViewModel myCatchViewModel);

    @Binds
    @IntoMap
    @ViewModelKey(FishingSpotViewModel.class)
    abstract ViewModel fishingSpotViewModel(FishingSpotViewModel fishingSpotViewModel);

    @Binds
    abstract ViewModelProvider.Factory bindCustomViewModelFactory(CustomViewModelFactory customViewModelFactory);

}

1 Ответ

0 голосов
/ 17 сентября 2018

Подход, который команда Google предложила в примерах компонентов архитектуры, заключается в использовании пользовательской аннотации для предоставления классов ViewModel через кинжал.

В Java аннотация выглядит следующим образом.

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

import androidx.lifecycle.ViewModel;
import dagger.MapKey;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@MapKey
@interface ViewModelKey {
    Class<? extends ViewModel> value();
}

При этом используется MapKey из Dagger, где любая аннотированная ViewModel будет скомпонована в Map, которую затем можно будет использовать в ViewModelFactory.

В примерах Google ViewModelFactory выглядит следующим образом, где при использовании инжектора конструктора выможет получить доступ к карте провайдеров ViewModel.

public class ViewModelFactory implements ViewModelProvider.Factory {

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

    @Inject
    public ViewModelFactory(Map<Class<? extends ViewModel>, Provider<ViewModel>> viewModels) {
        this.viewModels = viewModels;
    }

    @NonNull
    @Override
    public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
        Provider<ViewModel> viewModelProvider = viewModels.get(modelClass);

        if (viewModelProvider == null) {
            throw new IllegalArgumentException("model class " + modelClass + " not found");
        }

        //noinspection unchecked
        return (T) viewModelProvider.get();
    }
}

В вашем примере вы получите следующее для предоставления MyCatchViewModel.Другие ViewModels можно затем предоставить, следуя тому же шаблону.

@Module
public abstract class ViewModelModule {
    @Binds
    @IntoMap
    @ViewModelKey(MyCatchViewModel.class)
    abstract ViewModel myCatchViewModel(MyCatchViewModel myCatchViewModel);
}

Для полного примера вы можете посмотреть пример GithubBrowserSample от Google.https://github.com/googlesamples/android-architecture-components/blob/master/GithubBrowserSample/app/src/main/java/com/android/example/github/di/ViewModelModule.kt

...