了解 Dagger 2 中的范围

2023-11-27

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

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

class Company {
    List<Employee> employees;
}

Class 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));
    }

}

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,我从视图模型中选择 Employee 并显示她的详细信息:

  class EmployeeDetailActivity extends Activity {

        @Inject
        EmployeesViewModel viewModel;

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

I get NullPointerException因为EmployeesViewModel实例在EmployeesActivity不一样EmployeeDetailActivity并且,在第二个中,viewModel.selected is 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) but EmployeesViewModel不是,因为每次用户选择公司时都必须重新创建它(员工列表将包含其他项目)。

I could set公司员工至EmployeesViewModel每次用户选择一个公司,而不是创建一个新实例。但我想CompaniesViewModel是一成不变的。

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


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

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

第一眼看上去一切都很好——你使用 Dagger 来注入CompaniesViewModel and EmployeesViewModel into Activity。如果这些是真正的“对象”,这本来可以很好(尽管我不会这样做)。但是,就您而言,这些是“数据结构”(因此您希望它们是不可变的)。

对象和数据结构之间的区别并非微不足道,而是非常重要。这篇博文总结得很好。

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

两个具体建议:

  1. 不要将业务逻辑与 DI 逻辑混合。在您的情况下 - 不要注入数据结构,而是注入提供对数据的访问权限的对象(不好),或者在抽象数据时公开所需的功能(更好)。
  2. 我认为您在多个屏幕之间共享视图模型的尝试并不是一个非常稳健的设计。最好为每个屏幕都有一个单独的视图模型实例。如果您需要在屏幕之间“共享”状态,那么根据具体要求,您可以使用 1) Intent extras 2) Global object 3) Shared prefs 4) SQLite 来实现
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

了解 Dagger 2 中的范围 的相关文章

  • Android Studio 3.0 Canary 9 - 无法解析包

    我在 Android Studio 3 0 Canary 9 中遇到几个错误 这些错误是 无法解析 android 软件包 下面列出了一些错误 我刚刚安装了 SDK 的所有额外软件包 但仍然收到 gradle 构建错误 Error 82 1
  • StrictMode 策略违规:我的应用程序中存在 android.os.strictmode.LeakedClosableViolation?

    Android 开发新手 第一次在我的应用程序上尝试 StrictMode 我注意到以下内容 并想知道这是否是我的应用程序或库中的问题 我不太清楚 谢谢你 D StrictMode StrictMode policy violation a
  • android中向sqlite中插入大量数据

    目前 我必须一次向我的 Android 中插入超过 100 亿条数据 然而 内存不足的问题会使程序崩溃 sqlite 插入测试非常简单 只需使用 for 循环生成 sql 插入命令并通过 开始 和 提交 进行包装 private Array
  • Android - 从资产中解析巨大(超大)JSON 文件的最佳方法

    我正在尝试从资产文件夹中解析一些巨大的 JSON 文件 我如何加载并添加到 RecyclerView 我想知道解析这种大文件 大约 6MB 的最佳方法是什么 以及您是否知道可以帮助我处理此文件的良好 API 我建议您使用GSON lib h
  • 计数物体和更好的填充孔的方法

    我是 OpenCV 新手 正在尝试计算物体的数量在图像中 我在使用 MATLAB 图像处理工具箱之前已经完成了此操作 并在 OpenCV Android 中也采用了相同的方法 第一步是将图像转换为灰度 然后对其进行阈值计算 然后计算斑点的数
  • 在画布上绘图

    我正在编写一个 Android 应用程序 它可以在视图的 onDraw 事件上直接绘制到画布上 我正在绘制一些涉及单独绘制每个像素的东西 为此我使用类似的东西 for int x 0 x lt xMax x for int y 0 y lt
  • Android 模拟器插件无法初始化后端 EGL 显示

    我在 Cloudbees 上设置了 Jenkins 作业 并且可以在那里成功签出并编译我的 Android 项目 现在我想在 android 模拟器中运行一些 JUnit 测试并添加 Android 模拟器插件 我将 显示模拟器窗口 选项设
  • Android 中 Kotlin 协程的正确使用方式

    我正在尝试使用异步更新适配器内的列表 我可以看到有太多的样板 这是使用 Kotlin 协程的正确方法吗 这个可以进一步优化吗 fun loadListOfMediaInAsync async CommonPool try Long runn
  • 在 HTTPResponse Android 中跟踪重定向

    我需要遵循 HTTPost 给我的重定向 当我发出 HTTP post 并尝试读取响应时 我得到重定向页面 html 我怎样才能解决这个问题 代码 public void parseDoc final HttpParams params n
  • 无法访问 com.google.android.gms.internal.zzbfm 的 zzbfm 类文件未找到

    我正在将我的 Android 应用程序项目从GCM to FCM 为此 我使用 Android Studio 中的 Firebase 助手工具 并遵循 Google 开发人员指南中的说明 一切都很顺利 并将我的应用程序代码更改为FCM根据助
  • 尝试将相机切换回前面但出现异常

    尝试将相机切换回前面 但出现异常 找不到 问题请检查并帮助 error 01 27 11 49 00 376 E AndroidRuntime 30767 java lang RuntimeException Unable to start
  • 在gradle插件中获取应用程序变体的包名称

    我正在构建一个 gradle 插件 为每个应用程序变体添加一个新任务 此新任务需要应用程序变体的包名称 这是我当前的代码 它停止使用最新版本的 android gradle 插件 private String getPackageName
  • 你的CPU不支持NX

    我刚刚下载了 android studio 但是我遇到了一个问题 当我运行它时 它说你的 cpu 不支持 NX 我应该怎么办 NX 或实际上是 NX 处理器位 是处理器的一项功能 有助于保护您的 PC 免受恶意软件的攻击 当此功能未启用并且
  • Android Studio 0.4.3 Eclipse项目没有gradle

    在此版本之前 在 Android Studio 中按原样打开 Eclipse 项目似乎很容易 无需任何转换 我更喜欢 Android Studio 环境 但我正在开发一个使用 eclipse 作为主要 IDE 的项目 我不想只为这个项目下载
  • Android访问远程SQL数据库

    我可以直接从 Android 程序访问远程 SQL 数据库 在网络服务器上 吗 即简单地打开包含所有必需参数的连接 然后执行 SQL 查询 这是一个私人程序 不对公众开放 仅在指定的手机上可用 因此我不担心第三方获得数据库访问权限 如果是这
  • Android 中麦克风的后台访问

    是否可以通过 Android 手机上的后台应用程序 服务 持续监控麦克风 我想做的一些想法 不断聆听背景中的声音信号 收到 有趣的 音频信号后 执行一些网络操作 如果前台应用程序需要的话 后台应用程序必须能够智能地放弃对麦克风的访问 除非可
  • Android:膨胀布局时出现 StackOverFlowError 和 InvokingTargetException

    首先 对不起我的英语 我在膨胀布局时有一个问题 我有一个自定义视图 从 LinearLayout 扩展而来 称为按钮帮助 我在名为的布局上使用该视图加载活动 我的以下代码在所有设备和模拟器上都能完美运行 但具有 QVGA 屏幕 例如 Sam
  • 将 Intent 包装在 LabeledIntent 中以用于显示目的

    要求 我的应用程序中有一个 共享 按钮 我需要通过 Facebook 分享 我需要选择是否安装原生 Facebook 应用程序 我们的决定是 如果未安装该应用程序 则将用户发送到 facebook com 进行分享 当前状态 我可以检测何时
  • 将两个文本视图并排放置在布局中

    我有两个文本视图 需要在布局中并排放置 并且必须遵守两条规则 Textview2 始终需要完整显示 如果布局中没有足够的空间 则必须裁剪 Textview1 例子 文本视图1 文本视图2 Teeeeeeeeeeeeeeeeeextview1
  • 按日期对 RecyclerView 进行排序

    我正在尝试按日期对 RecyclerView 进行排序 但我尝试了太多的事情 我不知道现在该尝试什么 问题就出在这条线上适配器 notifyDataSetChanged 因为如果我不放 不会显示错误 但也不会更新 recyclerview

随机推荐

  • Ruby 中使用 net-sftp 进行基于密钥的身份验证

    我希望能够使用 SFTP 登录多个服务器并下载某些文件 以帮助在问题出现时进行调试 虽然我们可以使用客户端 但我们希望开始自动化流程以简化一切 我的第一次尝试看起来像这样 def download files to download des
  • 通过比较行中的列来过滤 Pandas DataFrame

    我的数据框中的每一行都有两个日期列 如何过滤掉 日期 A 在 日期 B 之后的行 例子 symbol reports at as of signal A 2012 02 15T21 00 00Z 2012 02 01T12 00 00Z 6
  • 强制可选参数使用更广泛的类型,并具有更严格的默认值

    有没有办法进行可选参数f足够灵活 有类型 a gt b 但仍将其默认为identity 鉴于identity有类型 a gt a 之前的一个问题 begins通过准确地陈述我的问题 我想定义一个接受可选参数的函数 该参数是 一个函数 a g
  • 语音中的关键字识别[关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 目前不接受答案 有谁知道有一个免费的关键字识别系统 并且可能提供 API CMU Sphinx 4 和 MS Speech API 是语音识别引擎 不能用于 KWS
  • 在 Java 的 main() 中对 Thread 实例运行 wait()

    我正在尝试 java lang Object 中 wait 的定时版本 并观察到它在两种不同场景中的行为有所不同 场景1 使用Thread中run 的默认定义 public static void main String args thro
  • scanf 是否保证在失败时不会更改值?

    If a scanffamily 函数无法匹配当前说明符 是否允许写入成功时存储该值的存储 在我的系统上有以下输出213两次 但这能保证吗 标准中的语言 C99或C11 似乎没有明确规定原始值应保持不变 无论是否不确定 include
  • JavaScript 错误 - 找不到变量:谷歌

    我编写的代码在浏览器上运行得非常好 但是当我连接到 iPhone 上的 wifi 时 我在调试器中收到错误 JavaScript 错误 找不到变量 谷歌 每当我调用任何谷歌地图 方向 地理位置对象时都会发生这种情况 代码如下 map new
  • 使用 SVN 和 Eclipse 正确设置 GWT 项目

    我正在尝试使用 Eclipse 和 Google Web Toolkit 开发一个小项目 这是一个 小型 小组项目 所以我想使用 SVN 到目前为止 我已经在 Eclipse 中创建了一个 GWT 项目并将其添加到我的 SVN 存储库中 问
  • 如何减少 Entity Framework 4 查询编译时间?

    摘要 我们遇到了 EF4 查询编译时间超过 12 秒的问题 缓存查询只能让我们到目前为止 有什么方法可以真正减少编译时间吗 我们可以寻找哪些可能做错的事情吗 谢谢 我们有一个通过 WCF 服务公开的 EF4 模型 对于每种实体类型 我们公开
  • 为什么 Scala 改变了关系运算符与相等运算符的相对优先级(与 Java 相比)?

    在Java中 更新 这实际上是语言规范中的一个错误 在 Scala 中 在Scala 中它不是相反的 尝试这个 val what 5 8 lt 4 我收到编译时警告 comparing values of types Boolean and
  • mysql group by 返回最小值并获取对应行数据

    我有一个像这样的数据表 PK table merchantName price Product 1 argos 7 4 2 comet 3 4 1 Dixon 1 3 1 argos 10 4 我希望在mysql中选择产品的最低价格和相应的
  • 将 ajax 结果附加到 div

    我正在对 IMDb API 进行 ajax 调用 以获取 肖申克的救赎 的电影数据 我希望将这些数据放入我创建的 div 中 div div 我当前的js代码 init function init ajax dataType json ur
  • 如何测量Java线程的执行时间?

    我想测量Java中线程的执行时间 现在我正在监视线程的开始和结束时间 但我认为它不太准确 因为线程在执行期间可能会被挂起 Java MXBeans 可以提供每线程 CPU 时间 import java lang management Man
  • “@+android:id/title”是什么意思?

    正常情况下 我们应该使用 id 定义一个 id 并使用 id引用一个 id 今天我发现 android id title in apps settings res layout preferenc progress xml 如何理解它以及如
  • 比较相等的日期时间返回 false

    我有一个关于如何在 C 中比较 存储日期时间的查询 考虑以下代码 var createdDate DateTime Now using cr new LanguageDictionaryRepository ds cr Add new Sy
  • 在 Rcpp 中构造 3D 数组

    我正在尝试使用提供的维度列表将 1D 数组映射到 3D 数组 这是我的组件 SEXP data my 1D array I can initialise new 3D vector in the following way NumericV
  • Angular ngx-mat-select-search 自定义组件

    我正在尝试使用 ngx mat select search 组件在我的应用程序中放置一个带有搜索栏的 mat select 样式下拉菜单 https www npmjs com package ngx mat select search 我
  • 如何在 Liferay portlet 中设置 Cookie?

    我在尝试设置会话 cookie 时遇到问题Liferay 6 0 portlet 我希望能够向客户端浏览器设置一个 cookie 以存储用于 linkedin 身份验证的应用程序密钥 然后其他 portlet 可以在其中检索它 我可以使用以
  • 如何在 ReadTheDocs 导航栏中链接生成的索引页面?

    我正在 ReadTheDocs 上使用 Sphinx 主题创建我的文档 构建过程会生成一个 genindex html 文件 可以通过以下方式引用该文件 Link to the ref genindex page 这会创建 链接到Index
  • 了解 Dagger 2 中的范围

    我在 Dagger 2 中遇到了与范围相关的错误 我正在尝试了解如何解决它 我有一个CompaniesActivity这表明公司 当用户选择一个项目时 所选公司的员工会显示在EmployeesActivity 当用户选择一名员工时 她的详细