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

问题描述 投票:0回答:1

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

java android mvvm dependency-injection dagger-2
1个回答
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的建议。

© www.soinside.com 2019 - 2024. All rights reserved.