我正在使用Dagger将viewModel注入片段:
class BaseFragment<T extends BaseViewModel> extends Fragment {
@Inject T viewModel;
@Override
public void onAttach(Context context) {
super.onAttach(context);
if(viewModel == null) {
throw new RuntimeException("Viewmodel was null: "+getClass());
}
viewModel.setContext(context);
viewModel.onAttach(context);
}
}
class MyFragment extends BaseFragment<MyViewModel> {
public MyFragment() {
MyApp.getInstance().getComponent().inject(this);
//viewModel should be available at this point, before OnAttach is called
}
}
所以简而言之,我在构造函数中注入了viewModel,如果onAttach仍然为null,那就错了。
这种情况从未发生过,除非它有100万次中的1次。只是几次崩溃。但无法弄清楚为什么。这种方法有误吗? Dagger以某种方式对参数化对象有问题吗?
我没有直接实例化BaseFragment,所以类型应该工作,它通常会这样做,那么为什么它在某些情况下不起作用?
答案 0 :(得分:2)
在Fragment的构造函数中注入是不正确的:
public MyFragment() {
//MyApp.getInstance().getComponent().inject(this);
//don't inject in a constructor!
}
虽然这可能适用于非常简单的工作流程,但它无法正确处理Fragment生命周期。特别是,存在片段存在但与活动分离的情况。当发生这种情况并且有必要将片段显示给再次用户时,Android OS将尝试重新附加缓存的片段而不调用构造函数(因为实例已经存在)。由于您依赖于构造函数在 onAttach
之前总是被称为的假设,因此可以想象这种情况会导致您的崩溃。
虽然通过与您的应用进行正常互动可能很难自行复制此问题,但我怀疑如果您在启用System/DeveloperOptions/Don't keep activities
的情况下测试应用,则更有可能遇到此问题。
注入片段子类的正确方法是onAttach(Context context)
:
@Override
public void onAttach(Context context) {
MyApp.getInstance().getComponent().inject(this);
super(context); //call super
}
这将更准确地跟踪Fragment生命周期。
请注意super
来电之前的注射请求。这符合Dagger official documentation中的建议。