Dagger 2:在片段中调用onAttach之前,注入的对象可能仍为null

时间:2017-09-01 13:42:45

标签: java android mvvm dependency-injection dagger-2

我正在使用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,所以类型应该工作,它通常会这样做,那么为什么它在某些情况下不起作用?

1 个答案:

答案 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中的建议。