代码之家  ›  专栏  ›  技术社区  ›  Rupesh

旋转后重新创建ViewModel;如果直接使用dagger2注入

  •  2
  • Rupesh  · 技术社区  · 7 年前

    可能重复 this

    我正在用dagger2探索android注入api。所以,在我的示例应用程序中 ViewModel 直接在活动中;查看以下代码片段。

    class SampleApp : Application(), HasActivityInjector {
    
        @Inject
        lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Activity>
    
        override fun activityInjector(): AndroidInjector<Activity> =
                dispatchingAndroidInjector
    
        override fun onCreate() {
            super.onCreate()
    
            DaggerApplicationComponent.builder()
                    .application(this)
                    .build()
                    .inject(this)
        }
    }
    

    @Component(modules = [
        AndroidInjectionModule::class,
        ActivityBindingModule::class,
        AppModule::class
        /** Other modules **/
    ])
    @Singleton
    interface ApplicationComponent {
    
        @Component.Builder
        interface Builder {
    
            @BindsInstance
            fun application(application: Application): Builder
    
            fun build(): ApplicationComponent
        }
    
        fun inject(sampleApp: SampleApp)
    }
    

    @Module
    public abstract class ActivityBindingModule {
    
        @ContributesAndroidInjector(modules = MainModule.class)
        public abstract MainActivity contributeMainActivityInjector();
    }
    

    class MainActivity : AppCompatActivity() {
        @Inject
        lateinit var mainViewModel: mainViewModel
    
        override fun onCreate(savedInstanceState: Bundle?) {
            AndroidInjection.inject(this)
    
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_dashboard)
        }
    }
    

    @Module
    public class MainModule {
        @Provides
        public static MainViewModelProviderFactory provideMainViewModelProviderFactory(/** some dependencies **/) {
            return new MainViewModelProviderFactory(/** some dependencies **/);
        }
    
        @Provides
        public static MainViewModel provideMainViewModel(MainActivity activity, MainViewModelProviderFactory factory) {
            return ViewModelProviders.of(activity, factory).get(MainViewModel.class);
        }
    }
    

    你可以看到我注射了 MainViewModel 直接进入活动。现在,如果我旋转活动,被注入的实例就不同了。

    但是,如果我注射 MainViewModelProviderFactory MainActivity 表演

    ViewModelProviders.of(activity, factory).get(MainViewModel.class) 它返回与以前相同的实例。

    我不明白我的实现有什么问题。

    任何指针都是可观的。

    1 回复  |  直到 7 年前
        1
  •  7
  •   Rupesh    7 年前

    所以在经过 ViewModelProvider , ViewModelProviders , FragmentActivity 是的 dagger2 documentation 我有答案。。

    如果我错了,请随时纠正我。。

    我们 不能 注入 视图模型 我们应该直接注入工厂。

    因为这条线我面临这个问题 AndroidInjection.inject(this) .

    根据匕首作者的说法

    在活动中的super.onCreate()之前调用AndroidInjection.inject()非常重要

    让我们看看这里到底出了什么问题。。

    活动将保留 ViewModel 旋转时使用 onRetainNonConfigurationInstance 会恢复原状的 onCreate()

    我们在打电话给 super.onCreate() ,我们不会保留 MainViewModel 只反对新的。

    如果你想了解详情,请继续阅读。。


    当匕首试图注射 主视图模型 它叫 provideMainViewModel() 方法 MainModule ,它调用以下表达式(请记住 超级.onCreate() 尚未调用)

    ViewModelProviders.of(activity, factory).get(MainViewModel.class)
    

    这个 ViewModelProviders.of 将返回 视图模型提供程序 其中包含了 ViewModelStore 各自的活动和 ViewModelProviderFactory

    public static ViewModelProvider of(@NonNull FragmentActivity activity,
            @Nullable Factory factory) {
        .
        .
    
        return new ViewModelProvider(ViewModelStores.of(activity), factory);
    }
    

    ViewModelStore.of(activity) 最终将调用活动的 getViewModelStore() 因为本例中的活动是 AppCompatActivity 哪些工具 ViewModelStoreOwner

    应用兼容活动 创建新的 视图模型存储 如果为空,则保留对它的引用。 视图模型存储 是包装纸 Map<String, ViewModel> 附加方法 clear()

    @NonNull
    public ViewModelStore getViewModelStore() {
        if (this.getApplication() == null) {
            throw new IllegalStateException("Your activity is not yet attached to the Application instance. You can't request ViewModel before onCreate call.");
        } else {
            if (this.mViewModelStore == null) {
                this.mViewModelStore = new ViewModelStore();
            }
    
            return this.mViewModelStore;
        }
    }
    

    每当设备被旋转时,活动将使用 onRetainNonConfigurationInstance实例 把它复原 onCreate .

    ViewModelProvider.get 将尝试获取 视图模型 来自活动的 视图模型存储

    public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
        ViewModel viewModel = mViewModelStore.get(key);
    
        if (modelClass.isInstance(viewModel)) {
            //noinspection unchecked
            return (T) viewModel;
        } else {
            //noinspection StatementWithEmptyBody
            if (viewModel != null) {
                // TODO: log a warning.
            }
        }
    
        viewModel = mFactory.create(modelClass);
        mViewModelStore.put(key, viewModel);
        //noinspection unchecked
        return (T) viewModel;
    }
    

    在这个例子中 超级.onCreate() 方法,但实现将要求 factory 创建并更新相应的 视图模型存储 .

    因此我们有了两个不同的 主视图模型 物体。