gpt4 book ai didi

android - 了解 Dagger 2 中的作用域

转载 作者:塔克拉玛干 更新时间:2023-11-02 20:31:49 24 4
gpt4 key购买 nike

我在 Dagger 2 中遇到与范围相关的错误,我正在尝试了解如何解决它。

我有一个显示公司的 CompaniesActivity。当用户选择一个项目时,所选公司的员工将显示在 EmployeesActivity 中。当用户选择一名员工时,她的详细信息显示在 EmployeeDetailActivity 中。

class Company {
List<Employee> employees;
}

CompaniesViewModel 类包含公司和所选公司(或 null):

class CompaniesViewModel {
List<Company> companies;
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 {
List<Employee> employees;
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 中,我从 View 模型中选择了 Employee 并显示她的详细信息:

  class EmployeeDetailActivity extends Activity {

@Inject
EmployeesViewModel viewModel;

@Override
protected void onCreate(Bundle b) {
//more stuff
getComponent().inject(this);
showEmployeeDetail(viewModel.selected); // NullPointerException
}
}

我得到 NullPointerException 因为 EmployeesActivity 中的 EmployeesViewModel 实例与 EmployeeDetailActivity 不同,并且在第二个,viewModel.selectednull

这是我的 Dagger 模块:

@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) 但 EmployeesViewModel 不是,因为每次用户选择公司时都必须重新创建它(员工列表将包含其他项目)。

每次用户选择公司时,我都可以将公司的员工设置 EmployeesViewModel,而不是创建一个新实例。但我希望 CompaniesViewModel 是不可变的。

我该如何解决这个问题?任何建议将不胜感激。

最佳答案

不幸的是,我认为您在这种情况下滥用了 DI 框架,您遇到的问题是“代码味道”——这些问题暗示您做错了什么。

应使用 DI 框架将关键依赖项(协作者对象)注入(inject)顶级组件,执行这些注入(inject)的逻辑应完全独立于应用程序的业务逻辑。

乍一看一切都很好 - 您使用 Dagger 将 CompaniesViewModelEmployeesViewModel 注入(inject) Activity。如果这些是真实的“对象”,这可能很好(尽管我不会这样做)。但是,在您的情况下,这些是“数据结构”(因此您希望它们是不可变的)。

对象和数据结构之间的这种区别不是微不足道的,而是非常重要的。 This blog post总结得很好。

现在,如果您尝试使用 DI 框架注入(inject)数据结构,您最终会将框架变成应用程序的“数据提供者”,从而将部分业务功能委托(delegate)给它。例如:看起来 EmployeesViewModel 独立于 CompaniesViewModel,但这是一个“谎言”——@Provides 方法中的代码将它们联系在一起从逻辑上讲,因此“隐藏”了依赖性。在这种情况下,好的“经验法则”是,如果 DI 代码依赖于注入(inject)对象的实现细节(例如调用方法、访问字段等)——这通常表明关注点分离不充分。

两个具体建议:

  1. 不要将业务逻辑与 DI 逻辑混在一起。在您的情况下 - 不要注入(inject)数据结构,而是注入(inject)对象,这些对象要么提供对数据的访问(坏),要么在抽象数据时公开所需的功能(更好)。
  2. 我认为您在多个屏幕之间共享 View 模型的尝试不是一个非常可靠的设计。最好为每个屏幕都有一个单独的 View-Model 实例。如果您需要在屏幕之间“共享”状态,那么根据具体要求,您可以使用 1) Intent extras 2) Global object 3) Shared prefs 4) SQLite

关于android - 了解 Dagger 2 中的作用域,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41824805/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com