gpt4 book ai didi

java - Android dagger2 使用 Factory 将 Intent 注入(inject) viewModel

转载 作者:行者123 更新时间:2023-11-30 05:04:04 24 4
gpt4 key购买 nike

例如,我使用的是 Google 样本 - GithubBrowserSample (我用的是java版,可以查到here)

想要实现的目标:

  1. 以额外的 Intent 开始 Activity
  2. 向 viewModel 构造函数中注入(inject)额外内容

我的 Activity (在女巫中我想要传递 Intent )模块:

@Module
public abstract class AddEditTaskModule {

@Provides
@Nullable
static String provideTaskId(AddEditTaskActivity activity) {
return activity.getIntent().getStringExtra(AddEditTaskActivity.EDIT_TASK_ID);
}

@ContributesAndroidInjector
abstract AddEditTaskFragment contributeAddEditTaskFragment();

@Binds
@IntoMap
@ViewModelScope(AddEditTaskViewModel.class)
abstract ViewModel bindAddEditTaskViewModel(AddEditTaskViewModel viewModel);
}

我的工厂:

public class ViewModelFactory implements ViewModelProvider.Factory {

private final Map<Class<? extends ViewModel>, Provider<ViewModel>> creators;

@Inject
public ViewModelFactory(Map<Class<? extends ViewModel>, Provider<ViewModel>> creators) {
Timber.d("@Inject constructor");
this.creators = creators;
}

@SuppressWarnings("unchecked")
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
Provider<? extends ViewModel> creator = creators.get(modelClass);
if (creator == null) {
for (Map.Entry<Class<? extends ViewModel>, Provider<ViewModel>> entry : creators.entrySet()) {
if (modelClass.isAssignableFrom(entry.getKey())) {
creator = entry.getValue();
break;
}
}
}
if (creator == null) {
throw new IllegalArgumentException("unknown model class " + modelClass);
}
try {
return (T) creator.get();
} catch (Exception e) {
Timber.e(e);
throw new RuntimeException(e);
}
}
}

在 Google 的示例中 - 工厂注释为 @Singleton

在我的例子中 - 我不能将它用作单例,因为我需要在 Activity 模块中绑定(bind) viewModel - 从那里传递 intentExtra。

所以,它工作正常,但每次我尝试通过以下方式获取 viewModel 时

@Inject
ViewModelProvider.Factory viewModelFactory;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
...
AddEditTaskViewModel mViewModel =
ViewModelProviders.of(this, viewModelFactory).get(AddEditTaskViewModel.class);
}

新工厂已创建。

这对我来说似乎是错误的。我做错了什么?

编辑:

解决方案#1:

为这种 ViewModel 创建自定义工厂

public class AddEditTaskViewModel extends ViewModel {

...

public static class Factory extends ViewModelProvider.NewInstanceFactory{
@NonNull
private final Application application;
@Nullable
private final String taskId;

@Inject
public Factory(@NonNull Application application, @Nullable String taskId){
Timber.d("Constructor");
this.application = application;
this.taskId = taskId;
}

@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
//noinspection unchecked
return (T) new AddEditTaskViewModel(application, taskId);
}
}
}

Activity 模块:

@Module
public abstract class AddEditTaskModule {
@Provides
@Nullable
static String provideTaskId(AddEditTaskActivity activity) {
return activity.getIntent().getStringExtra(AddEditTaskActivity.EDIT_TASK_ID);
}

@ContributesAndroidInjector
abstract AddEditTaskFragment contributeAddEditTaskFragment();

@Provides
static AddEditTaskViewModel.Factory bindAddEditTaskViewModelFactory(Application application, @Nullable String id){
return new AddEditTaskViewModel.Factory(application, id);
}
}

现在,在我们的 Activity 中使用 in 并在此 Activity 中使用 fragment :

@Inject
AddEditTaskViewModel.Factory viewModelFactory;

AddEditTaskViewModel mViewModel =
ViewModelProviders.of(this, viewModelFactory).get(AddEditTaskViewModel.class);

这也行。问题是,在这种情况下,我需要复制 ViewModel 的构造函数 3(!!) 次:1. 在 Dagger 模块中,2. 在工厂中,3. 在 vi​​ewModel 中。

我不能只使用:

@Binds
abstract AddEditTaskViewModel.Factory bindAddEditTaskViewModelFactory(AddEditTaskViewModel.Factory factory);

因为——循环依赖

这个解决方案对我来说似乎不好。

解决方案#2:

使用两个 ViewModelFactory。

第一个全局的,用@Singleton注释。 Witch 将用于 ViewModel,而不会出现诸如“将 Intent 额外注入(inject) ViewModel”之类的情况。

第二个 - ViewModelFactory 的副本,但没有 @Singleton 注释。应该在带有 @Named 标签的 Activity 模块中使用,如下所示:

@Binds
@Named(AddEditTaskViewModel.TAG)
abstract ViewModelProvider.Factory bindAddEditTaskViewModelFactory(ViewModelFactoryTarget factory);

在 Activity/fragment 中:

@Inject
@Named(AddEditTaskViewModel.TAG)
ViewModelProvider.Factory viewModelFactory;

好吧,除了几个“但是”之外,这似乎是比上述任何一个更好的解决方案:

  1. 我有两个相同的 ViewModelFactory 类,只有 @Singleton 注释不同。
  2. 使用 @Named 对我来说不是很优雅。

最佳答案

调出来了,比我想象的要简单。

对于常见的 ViewModel:

从 ViewModelFactory 中删除 @Singleton 注释。

@Singleton 添加到 ViewModelModule

@Binds
@Singleton
abstract ViewModelProvider.Factory bindViewModelFactory(ViewModelFactory factory);

对于 ViewModel,我们需要使用 Intent Extra 注入(inject):

Activity 模块:

@Provides
@Nullable
static String provideTaskId(AddEditTaskActivity activity) {
return activity.getIntent().getStringExtra(AddEditTaskActivity.EDIT_TASK_ID);
}

@Binds
@Named(AddEditTaskViewModel.TAG)
abstract ViewModelProvider.Factory bindAddEditTaskViewModelFactory(ViewModelFactory factory);

比在 Activity/fragment 中使用:

@Inject
@Named(AddEditTaskViewModel.TAG)
ViewModelProvider.Factory viewModelFactory;

关于java - Android dagger2 使用 Factory 将 Intent 注入(inject) viewModel,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54866036/

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