旋转后重新创建ViewModel;如果直接注射dagger2

问题描述 投票:2回答:1

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)它返回与以前相同的实例。

我没有弄到我的实施有什么问题。

任何指针都会很明显。

android kotlin dagger-2 android-architecture-components android-mvvm
1个回答
7
投票

所以经过ViewModelProviderViewModelProvidersFragmentActivity的来源,是的dagger2 documentation我有一个答案..

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

我们不能直接注入ViewModel,我们应该注入工厂。

由于这条线AndroidInjection.inject(this),我正面临这个问题。

根据匕首作者

在Activity中的super.onCreate()之前调用AndroidInjection.inject()至关重要

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

活动将使用ViewModel保留它的旋转onRetainNonConfigurationInstance并将在onCreate()恢复它

正如我们在调用super.onCreate()之前注入的那样,我们不会得到保留的MainViewModel对象而是新的对象。

如果您需要详细信息,请继续阅读..


当匕首试图注入MainViewModel时,它调用provideMainViewModel()MainModule方法,调用以下表达式(请记住super.onCreate()尚未调用)

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

ViewModelProviders.of将返回一个ViewModelProvider,其中包含各自活动和ViewModelStoreViewModelProviderFactory的参考

public static ViewModelProvider of(@NonNull FragmentActivity activity,
        @Nullable Factory factory) {
    .
    .

    return new ViewModelProvider(ViewModelStores.of(activity), factory);
}

qazxsw poi将最终打电话给活动qazxsw poi,因为在这种情况下的活动是ViewModelStore.of(activity)实施getViewModelStore()

qazxsw poi创建新的qazxsw poi,如果它为null或持有它的引用。 AppCompatActivityViewModelStoreOwner的包装,另外还有AppCompatActivity方法

ViewModelStore

只要设备被旋转,活动就会使用ViewModelStore保留它的非配置实例状态,并在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方法,但实现将要求ViewModel创建它并将更新相应的ViewModelStore

因此我们最终得到了两个不同的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; } 对象。

© www.soinside.com 2019 - 2024. All rights reserved.