如何在 SavedStateHandle-aware AndroidViewModel 中注入依赖项?

How to inject dependencies in a SavedStateHandle-aware AndroidViewModel?

假设视图模型如下:

public class FooViewModel extends AndroidViewModel {

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

我想使用 Dagger 2 注入 Bar。我正在开发 Android。

根据 SavedStateHandle docs:

You should use SavedStateViewModelFactory if you want to receive this object in ViewModel's constructor.

但是,SavedStateViewModelFactory docs 声明工厂是 final,这意味着我也不能在那里注入 Bar

到目前为止,我一直在通过 setter:

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

        viewModel.setBar(bar);

        return viewModel;
    }

有更好的方法吗?

我想使用构造函数注入,将 Bar 实例变量标记为 final 并删除 setter.

要提供 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.) 您只能在 AbstractSavedStateViewModelFactory 中得到 SavedStateHandle,因此您无法将其放入图表中。

2.) 您可以使用 https://github.com/square/AssistedInject 减少该提供程序的长度。理论上 AutoFactory 也可以,但相比之下似乎没有维护。

3.) 您将无法在您的 ViewModel 上获得 @Inject

此答案部分改编自 https://github.com/Zhuinden/DaggerViewModelExperiment/blob/c3cbf0a5bc85467cec08755fcc152db5e8c55f91/app/src/main/java/com/zhuinden/daggerviewmodelexperiment/features/second/SecondFragment.kt#L32-L47