我在Dagger 2中有与范围相关的错误,我试图理解如何解决它.
我有一个CompaniesActivity
显示公司.当用户选择项目时,将显示所选公司的员工EmployeesActivity
.当用户选择员工时,她的详细信息显示在EmployeeDetailActivity
.
class Company { Listemployees; }
类CompaniesViewModel
包含公司和选定的公司(或null
):
class CompaniesViewModel { Listcompanies; Company selected; }
CompaniesActivity
提到CompaniesViewModel
:
class CompaniesActivity extends Activity { @Inject CompaniesViewModel viewModel; @Override protected void onCreate(Bundle b) { //more stuff getComponent().inject(this); showCompanies(viewModel.companies); } //more stuff private onCompanySelected(Company company) { viewModel.selected = company; startActivity(new Intent(this, EmployeesActivity.class)); } }
类EmployeesViewModel
包含员工和选定的员工(或null
):
class EmployeesViewModel { Listemployees; Employee selected; }
EmployeesActivity
提到EmployeesViewModel
:
class EmployeesActivity extends Activity { @Inject EmployeesViewModel viewModel; @Override protected void onCreate(Bundle b) { //more stuff getComponent().inject(this); showEmployees(viewModel.employees); } //more stuff private onEmployeeSelected(Employee emp) { viewModel.selected = emp; startActivity(new Intent(this, EmployeeDetailActivity.class)); } }
最后,EmployeeDetailActivity
我从视图模型中选择了Employee并显示她的详细信息:
class EmployeeDetailActivity extends Activity { @Inject EmployeesViewModel viewModel; @Override protected void onCreate(Bundle b) { //more stuff getComponent().inject(this); showEmployeeDetail(viewModel.selected); // NullPointerException } }
我得到NullPointerException
因为EmployeesViewModel
实例与EmployeesActivity
the不同EmployeeDetailActivity
,在第二个中,viewModel.selected
是null
.
这是我的匕首模块:
@Module class MainModule { @Provides @Singleton public CompaniesViewModel providesCompaniesViewModel() { CompaniesViewModel cvm = new CompaniesViewModel(); cvm.companies = getCompanies(); return cvm; } @Provides public EmployeesViewModel providesEmployeesViewModel(CompaniesViewModel cvm) { EmployeesViewModel evm = new EmployeesViewModel(); evm.employees = cvm.selected.employees; return evm; } }
请注意,这CompaniesViewModel
是singleton(@Singleton
)但EmployeesViewModel
不是,因为每次用户选择公司时都必须重新创建(员工列表将包含其他项).
每次用户选择公司时,我都可以set
让公司的员工参与EmployeesViewModel
,而不是创建新的实例.但我想CompaniesViewModel
是不变的.
我怎么解决这个问题?任何建议将不胜感激.
不幸的是,我认为你在这种情况下滥用DI框架,你遇到的问题是"代码味道" - 这些问题暗示你做错了什么.
应该使用DI框架将关键依赖项(协作者对象)注入顶级组件,执行这些注入的逻辑应该完全独立于应用程序的业务逻辑.
从第一眼看,一切看起来都很好 - 你使用Dagger注入CompaniesViewModel
和EmployeesViewModel
进入Activity
.如果这些是真正的"对象",这可能没问题(虽然我不会这样做).但是,在您的情况下,这些是"数据结构"(因此您希望它们是不可变的).
对象和数据结构之间的区别并非易事,但非常重要.这篇博文非常好地总结了它.
现在,如果您尝试使用DI框架注入数据结构,最终将框架转换为应用程序的"数据提供者",从而将部分业务功能委托给它.例如:它看起来EmployeesViewModel
是独立的CompaniesViewModel
,但它是一个"谎言" - @Provides
方法中的代码将它们逻辑地联系在一起,从而"隐藏"依赖性.在这种情况下,良好的"经验法则"是,如果DI代码依赖于注入对象的实现细节(例如,调用方法,访问字段等) - 它通常表示关注点分离不充分.
两个具体建议:
不要将业务逻辑与DI逻辑混合在一起.在您的情况下 - 不要注入数据结构,而是注入提供对数据的访问(坏)的对象,或者在抽象数据时更好地公开所需的功能(更好).
我认为您在多个屏幕之间共享视图模型的尝试并不是一个非常强大的设计.最好为每个屏幕设置一个单独的View-Model实例.如果你需要在屏幕之间"共享"状态,那么,根据具体要求,你可以用1)Intent extras 2)全局对象3)共享首选4)SQLite