Как внедрить зависимости в AndroidViewModel с поддержкой SavedStateHandle? - PullRequest
1 голос
/ 16 апреля 2020

Предположим, что модель представления выглядит следующим образом:

public class FooViewModel extends AndroidViewModel {

    @Inject public FooViewModel(Application app, SavedStateHandle handle, Bar bar) {
        // ...
    }
}

Я хочу внедрить Bar с помощью Dagger 2. Я работаю на Android.

Согласно SavedStateHandle docs :

Вам следует использовать SavedStateViewModelFactory, если вы хотите получить этот объект в конструкторе ViewModel.

Однако, SavedStateViewModelFactory документы заявляют, что фабрика имеет значение final, что означает, что я тоже не могу вводить Bar.

До сих пор я делал инъекции через сеттер:

    @Provides
    FooViewModel provideFooViewModel(ViewModelStoreOwner owner, Bar bar) {
        FooViewModel viewModel = new ViewModelProvider(owner).get(FooViewModel.class);

        viewModel.setBar(bar);

        return viewModel;
    }

Есть ли лучший способ сделать это?

Я хочу использовать инжектор конструктора, пометить переменную экземпляра Bar как final и исключить установщик.

1 Ответ

0 голосов
/ 17 апреля 2020

Чтобы предоставить FooViewModel, вам нужна пользовательская реализация AbstractSavedStateViewModelFactory.

MyComponent component = DaggerMyComponent.withViewModelStoreOwner(this)
.withSavedStateRegistryOwner(this)
.withDefaultArguments(this.arguments != null ? this.arguments : new Bundle())
.build();

и

    @Provides
    @Suppress("UNCHECKED_CAST")
    public MyViewModel viewModel(ViewModelStoreOwner viewModelStoreOwner, SavedStateRegistryOwner savedStateRegistryOwner, Bundle defaultArgs, Application application, Bar bar) {
        return new ViewModelProvider(
            viewModelStoreOwner,
            new AbstractSavedStateViewModelFactory(savedStateRegistryOwner, defaultArgs) {
                @Override
                public <T extends ViewModel> T create(
                    String key,
                    Class<T> modelClass,
                    SavedStateHandle handle) {
                    return (T) new MyViewModel(application, handle, bar);
                } 
            }).get(MyViewModel.class);
        });
    }

Примечание:

1.) вы получаете SavedStateHandle только внутри AbstractSavedStateViewModelFactory, поэтому вы не сможете вставить его в свой график.

2.) вы можете уменьшить длину этого провайдера, используя https://github.com/square/AssistedInject. Теоретически AutoFactory также будет работать, но, по сравнению с ним, он не поддерживается.

3.) Вы не сможете получить @Inject на вашей ViewModel.

Этот ответ был частично адаптирован из https://github.com/Zhuinden/DaggerViewModelExperiment/blob/c3cbf0a5bc85467cec08755fcc152db5e8c55f91/app/src/main/java/com/zhuinden/daggerviewmodelexperiment/features/second/SecondFragment.kt#L32 -L47 .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...