gpt4 book ai didi

android - 旋转后重新创建 ViewModel;如果直接用 dagger2 注入(inject)

转载 作者:太空狗 更新时间:2023-10-29 15:58:29 25 4
gpt4 key购买 nike

this 可能重复

我正在使用 dagger2 探索 android 注入(inject) api。所以,在我的示例应用程序中,我直接在 Activity 中注入(inject)了 ViewModel;看看下面的代码 fragment 。

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 直接注入(inject)到 Activity 中。现在,如果我轮换 Activity ,注入(inject)的实例就会不同。

但是,如果我在 MainActivity 中注入(inject) MainViewModelProviderFactory 并执行

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

我没有发现我的实现有什么问题。

如有任何指点,我们将不胜感激。

最佳答案

所以在查看了ViewModelProvider的来源之后, ViewModelProviders , FragmentActivity是的 dagger2 documentation我有一个答案..

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

We must not inject ViewModel directly, we should inject factories instead.

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

根据 Dagger 作者

It is crucial to call AndroidInjection.inject() before super.onCreate() in an Activity

让我们在非常高的层次上看看这里出了什么问题..

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

因为我们在调用 super.onCreate() 之前注入(inject), 我们不会得到保留的 MainViewModel对象,但新对象。

如果您想了解详细信息,请继续阅读..


当 dagger 尝试注入(inject)时 MainViewModel它叫provideMainViewModel() MainModule的方法| ,它调用以下表达式(请记住 super.onCreate() 尚未调用)

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

ViewModelProviders.of将返回 ViewModelProvider其中包含 ViewModelStore 的引用资料各自的 Activity 和ViewModelProviderFactory

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

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

ViewModelStore.of(activity)最终会调用 Activity 的getViewModelStore()因为本例中的 Activity 是 AppCompatActivity实现ViewModelStoreOwner

AppCompatActivity创建新的 ViewModelStore如果它为 null & 持有对它的引用。 ViewModelStoreMap<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;
}
}

每当设备旋转时, Activity 都会使用 onRetainNonConfigurationInstance 保留其非配置实例状态并在 onCreate 中恢复它. (例如 mViewModelStore)

ViewModelProvider.get将尝试获取 ViewModel来自 Activity 的 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;
}

在这个特定的例子中;因为我们还没有调用 super.onCreate()方法但实现会询问 factory创建它并更新相应的 ViewModelStore .

因此我们最终得到了两个不同的 MainViewModel对象。

关于android - 旋转后重新创建 ViewModel;如果直接用 dagger2 注入(inject),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51534845/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com