了解 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 上的多处理

    我一直在 Android 上执行一些测试 以验证并行化算法 如 FFT 的性能可以提高多少 我通过使用带有 JNI FFTW 的 pthread 和 Java 线程 来自 JTransforms 来实现这些算法 我没有像预期那样通过使用线程
  • 如何设计Android建筑物室内地图? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我想设计一个 Android 应用程序 它可以帮助学生和其他人在特定建筑物 一层 中导航 显示前往教室的步行方向 我需要帮助 这是您通
  • 为什么Android room不建议使用allowMainThreadQueries()?

    我正在创建一个小型应用程序 仅在数据库中保存一些计数器 如果不存在 请插入一个 如果是的话 增加更新 该应用程序没有任何用户界面 它是一个保存和读取数据 少量表 少量记录 的插件 我可以用吗允许主线程查询 在这种情况下 每次我读到一些关于这
  • 从txt文件中读取数据而不下载它?

    我想从提供的文本文件中解析信息 有没有一种方法可以在应用程序中执行此操作 而无需先下载文件 以某种方式传输文本内容 打开到 URL 的 Http 连接 使用内置 HttpURLConnection 或使用 commons httpclien
  • 从 Android 函数更新 Textview

    有人可以告诉我如何从函数更新 Android Textview 控件吗 我在互联网上进行了深入搜索 看到很多人都问同样的问题 我测试了线程但无法工作 有人有一个简单的工作示例吗 例如 调用一个函数 在循环中运行多次 并且该函数在 TextV
  • Android 偏好设置中的“是”或“否”确认[重复]

    这个问题在这里已经有答案了 我需要在 设置 中实现 重置 选项 单击该设置后 将打开一个简单的对话框 要求确认 我看过了DialogPreference但我似乎无法在任何地方找到好的解决方案或教程 有人可以帮我吗 我是初学者 想法甚至代码都
  • openFileOutput 在单例类中无法正常工作 - 想法/解决方法?

    作为一名 Android 开发新手 我遇到了一些奇怪的问题 我想创建一个类 它方法其他类 活动 任何可以用于以某种特殊方式处理文件的类 假设为了简单起见 我们将记录一些内容 如果我在活动中执行以下操作 例如在 OnClick 侦听器中 则一
  • 彩信数据总是错误

    我正在从 Galaxy S6 读取短信和彩信数据 所有 SMS 消息都有一个date像这样的字段1456252633000 该数字是 unix 时间戳 1000 我发送 未收到 的彩信具有如下日期字段 1440628863时间戳是正确的 u
  • 如何以编程方式关闭画中画

    我在使用画中画模式时遇到了这个问题 当从 PIP 本身以外的其他位置再次打开 Activity 时 我想关闭 PIP 画中画 不是来自关闭按钮 我想要与 youtube 相同的场景 即当用户单击 PIP 画中画 时 它会打开相同的活动 但是
  • 移动到SD卡

    我知道从 android 2 2 开始可以使用移动到 SD 卡功能 我想知道有没有办法在我的程序中检测设备是否支持移动到 SD 卡功能 如果支持 则可以移动 否则如果不支持 则什么也不会发生 将在手机内存中 我的主要问题是我的应用程序支持
  • Horizo​​ntalScrollView 将 GridView 缩小为小行

    当我将 Horizo ntalScrollView 放在 GridView 周围时 GridView 会被压缩到左侧的一个小列中 Gridview 的垂直滚动条甚至出现在左侧 Horizo ntalScrollView 的宽度设置为 fil
  • 在 Unity 中构建 apk 应用程序时包含文件

    在unity中构建apk文件时如何将文件和文件夹添加到apk文件中 我需要的是在Android上安装应用程序后 在应用程序的父目录 android data com company product files 中存在一些文件和文件夹 这是我
  • 无法读取第 0 行,第 -1 列

    我正在尝试复制使用 SQLite 管理器创建的数据库 我在其中执行了以下操作 CREATE TABLE android metadata locale TEXT DEFAULT en US and INSERT INTO android m
  • Android 10 中没有设备筛选器的 USB_DEVICE_ATTACHED

    我正在开发一个 Android 应用程序 它在清单中为 BroadcastReceiver 注册了四个意图过滤器 这些都是 android hardware usb action USB DEVICE ATTACHED android ha
  • React Native v0.71.8 React-native-vector-icons 你看不到的图标

    我在用react native版本v0 71 8 我安装了react native vector icons库 但图标未显示 似乎链接在最新版本的 React Native 中不再起作用 所以我按照说明进行操作 但它不再编译 出现以下错误
  • 如何在捆绑中存储稀疏数组

    我有一个SparseArray
  • 在 Tensorflow-lite Android 中将位图转换为 ByteBuffer(浮点)

    在用于图像分类的tensorflow lite android演示代码中 图像首先转换为ByteBuffer格式以获得更好的性能 这种从位图到浮点格式的转换以及随后到字节缓冲区的转换似乎是一个昂贵的操作 循环 按位运算符 float mem
  • 如何将 Android 应用程序添加到已在 iOS 应用程序中使用的现有 Firebase 项目?

    我一直在我的 iOS 应用程序中使用 Firebase 项目 我现在想开始为 Android 应用程序使用相同的 Firebase 项目及其所有数据库和存储 在您的应用程序下Overview菜单 你应该按添加另一个应用程序并选择Androi
  • 如何像UCBrowser一样使用webview打开url

    我是安卓新手 我正在尝试制作一个示例应用程序来在 webview 中打开网站 问题是 网站以桌面模式打开 如何才能像UC浏览器 手机模式 一样打开网站 尝试这个 它应该有效 webview1 getSettings setJavaScrip
  • 如何获取视图到手机底部的距离?

    如果我在布局上有某个视图 ImageView 例如 是否可以找到View的下边框到手机屏幕底部的距离 Thanks instantiate DisplayMetrics DisplayMetrics dm new DisplayMetric

随机推荐

  • 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 当用户选择一名员工时 她的详细