2017-09-01 31 views
0

我用匕首注入一个ViewModel成片段之前:匕首2:注射对象可能仍然为空onAttach在片段称为

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 
    } 

} 

因此,在短期我注入视图模型在构造函数中,如果它在onAttach仍然是空的东西是错误的。

这绝不会发生,除非是100000次中的1次。只是几个崩溃。但无法弄清楚为什么。这种方法是错误的吗? Dagger是否对参数化对象有问题?

我不直接实例化BaseFragment,因此类型应该可以工作,它通常会这样做,那么为什么它在某些情况下不起作用?

+0

因此,有时'if(viewModel == null)'计算为'true'? – azizbekian

+0

是的。非常稀有。 – breakline

回答

2

在一个片段的构造注射不正确:

public MyFragment() { 
    //MyApp.getInstance().getComponent().inject(this);  
    //don't inject in a constructor! 
} 

虽然这对于一个非常简单的工作流程的工作,它不会正确处理片段生命周期。特别是,存在片段存在但与活动分离的情况。当发生这种情况并且需要向再次用户显示片段时,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 
} 

这将更加准确地跟踪片段的生命周期。

请注意super呼叫之前的注射请求。这是根据Dagger official documentation中的建议。

+0

片段重新连接时会发生什么?我想避免在可以多次调用的方法中注入事物 – breakline

+0

@breakline对不起,但对于Android活动和片段,除了在生命周期回调('onAttach'等)中插入注释,如果您希望自己的应用程序正确处理生命周期。对于其他类,欢迎使用构造函数注入,这是首选。 –