Android 生命周期库 ViewModel 使用 dagger 2

新手上路,请多包涵

我有一个 ViewModel 类,就像在 体系结构指南连接 ViewModel 和存储库 部分中定义的一样。当我运行我的应用程序时,出现运行时异常。有谁知道如何解决这个问题?我不应该注入 ViewModel 吗?有没有办法告诉 ViewModelProvider 使用 Dagger 创建模型?

 public class DispatchActivityModel extends ViewModel {

    private final API api;

    @Inject
    public DispatchActivityModel(API api) {
        this.api = api;
    }
}

由以下原因引起:java.lang.InstantiationException:java.lang.Class 在 android.arch.lifecycle.ViewModelProvider\(NewInstanceFactory.create(ViewModelProvider.java:143) 的 java.lang.Class.newInstance(Native Method) 处没有零参数构造函数在 android.arch.lifecycle.ViewModelProviders\)DefaultFactory.create(ViewModelProviders.java:143) 在 android.arch.lifecycle.ViewModelProvider.get(ViewModelProvider.java:128) 在 android.arch.lifecycle.ViewModelProvider.get(ViewModelProvider.java: :96) 在 com.example.base.BaseActivity.onCreate(BaseActivity.java:65) 在 com.example.dispatch.DispatchActivity.onCreate(DispatchActivity.java:53) 在 android.app.Activity.performCreate(Activity.java: 6682) 在 android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118) 在 android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2619) 在 android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2727) 在 android。 app.ActivityThread.-wrap12(ActivityThread.java) 在 android.app.ActivityT hread$H.handleMessage(ActivityThread.java:1478) 在 android.os.Handler.dispatchMessage(Handler.java:102) 在 android.os.Looper.loop(Looper.java:154) 在 android.app.ActivityThread.main (ActivityThread.java:6121)

原文由 TheHebrewHammer 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 587
2 个回答

您需要实现自己的 ViewModelProvider.Factory 。 Google 创建了一个示例应用程序,演示了如何将 Dagger 2 与 ViewModel 连接起来。 链接。你需要这5样东西:

在视图模型中:

 @Inject
public UserViewModel(UserRepository userRepository, RepoRepository repoRepository) {

定义注释:

 @Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@MapKey
@interface ViewModelKey {
    Class<? extends ViewModel> value();
}

在 ViewModelModule 中:

 @Module
abstract class ViewModelModule {
    @Binds
    @IntoMap
    @ViewModelKey(UserViewModel.class)
    abstract ViewModel bindUserViewModel(UserViewModel userViewModel);

在片段中:

 @Inject
ViewModelProvider.Factory viewModelFactory;

@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
            userViewModel = ViewModelProviders.of(this, viewModelFactory).get(UserViewModel.class);

工厂:

 @Singleton
public class GithubViewModelFactory implements ViewModelProvider.Factory {
    private final Map<Class<? extends ViewModel>, Provider<ViewModel>> creators;

    @Inject
    public GithubViewModelFactory(Map<Class<? extends ViewModel>, Provider<ViewModel>> creators) {
        this.creators = creators;
    }

    @SuppressWarnings("unchecked")
    @Override
    public <T extends ViewModel> T create(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) {
            throw new RuntimeException(e);
        }
    }
}

原文由 Robert Wysocki 发布,翻译遵循 CC BY-SA 3.0 许可协议

今天我学会了一种避免为我的 ViewModel 类编写工厂的方法:

 class ViewModelFactory<T : ViewModel> @Inject constructor(
    private val viewModel: Lazy<T>
) : ViewModelProvider.Factory {
    @Suppress("UNCHECKED_CAST")
    override fun <T : ViewModel?> create(modelClass: Class<T>): T = viewModel.get() as T
}

编辑: 正如@Calin 在评论中指出的那样,我们在上面的代码片段中使用了 Dagger 的 Lazy ,而不是 Kotlin 的。

您可以将通用的 ViewModelFactory 注入到您的活动和片段中,并获取任何 ViewModel :79- 的实例,而不是注入 ViewModel

 class MyActivity : Activity() {

    @Inject
    internal lateinit var viewModelFactory: ViewModelFactory<MyViewModel>
    private lateinit var viewModel: MyViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        AndroidInjection.inject(this)
        super.onCreate(savedInstanceState)
        this.viewModel = ViewModelProviders.of(this, viewModelFactory)
            .get(MyViewModel::class.java)
        ...
    }

    ...
}

我使用了 AndroidInjection.inject(this)dagger-android 库一样,但是你可以按照你喜欢的方式注入你的活动或片段。剩下的就是确保您从模块中提供 ViewModel

 @Module
object MyModule {
    @JvmStatic
    @Provides
    fun myViewModel(someDependency: SomeDependency) = MyViewModel(someDependency)
}

或将 @Inject 注释应用于其构造函数:

 class MyViewModel @Inject constructor(
    someDependency: SomeDependency
) : ViewModel() {
    ...
}

原文由 argenkiwi 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题