【问题标题】:Android / Dagger2 - How to add bundle arguments ? Inject fragment or use newInstance?Android/Dagger2 - 如何添加捆绑参数?注入片段还是使用 newInstance?
【发布时间】:2018-08-29 19:02:11
【问题描述】:

我正在寻找有关如何注入片段并向其传递参数的解决方案。 而且我没有找到任何合适的解决方案,因为通过构造函数注入片段意味着对状态不安全。

有没有办法做到这一点,而不调用 newInstance 模式?

谢谢,

最好的。

【问题讨论】:

    标签: android dagger-2


    【解决方案1】:

    由于 Android 管理您的 Fragment 的生命周期,您应该将 通过其 bundle 将状态传递到 Fragment使用可注入的 deps 注入 Fragment 的问题分开。通常,将它们分开的最佳方法是提供static factory method,您可能将其称为newInstance 模式

    public class YourFragment extends Fragment {
    
      // Fragments must have public no-arg constructors that Android can call.
      // Ideally, do not override the default Fragment constructor, but if you do
      // you should definitely not take constructor parameters.
    
      @Inject FieldOne fieldOne;
      @Inject FieldTwo fieldTwo;
    
      public static YourFragment newInstance(String arg1, int arg2) {
        YourFragment yourFragment = new YourFragment();
        Bundle bundle = new Bundle();
        bundle.putString("arg1", arg1);
        bundle.putInt("arg2", arg2);
        yourFragment.setArguments(bundle);
        return yourFragment;
      }
    
      @Override public void onAttach(Context context) {
        // Inject here, now that the Fragment has an Activity.
        // This happens automatically if you subclass DaggerFragment.
        AndroidSupportInjection.inject(this);
      }
    
      @Override public void onCreate(Bundle bundle) {
        // Now you can unpack the arguments/state from the Bundle and use them.
        String arg1 = bundle.getString("arg1");
        String arg2 = bundle.getInt("arg2");
        // ...
      }
    }
    

    请注意,这是一种不同于您可能习惯的注入类型:您不是通过注入来获取 Fragment 实例,而是告诉 Fragment 在附加后稍后注入自己到一个活动。此示例使用dagger.android 进行注入,它使用子组件和members-injection methods 注入@Inject-annotated 字段和方法,即使Android 在Dagger 控制之外创建Fragment 实例也是如此。

    还要注意,Bundle 是一个通用的键值对存储;我使用了“arg1”和“arg2”,而不是想出更多有创意的名字,但你可以使用任何你想要的字符串键。请参阅 Bundle 及其超类 BaseBundle 以查看 Bundle 在其 getput 方法中支持的所有数据类型。这个 Bundle 对于保存 Fragment 数据也很有用;如果您的应用被电话打断,Android 销毁您的 Activity 以节省内存,您可以使用 onSaveInstanceState 将表单字段数据放入 Bundle,然后在 onCreate 中恢复该信息。

    最后请注意,您不需要创建像newInstance 这样的静态工厂方法;您还可以让您的消费者创建一个 new YourFragment() 实例并自己传递特定的 Bundle 设计。但是,此时 Bundle 结构成为您的 API 的一部分,这可能是您不想要的。通过创建静态工厂方法(或工厂对象或其他结构),您可以让 Bundle 设计成为您的 Fragment 的实现细节,并为消费者提供一个文档化且保存完好的结构以创建新实例。

    【讨论】:

    • 嗨 Jeff,这意味着我必须为每个参数创建单独的不同实体?我怎样才能实现添加几个主要类型,如 String ?谢谢。
    • @JohnDot 您的静态工厂方法(例如newInstance)可以接受任意数量的参数,Bundle 是一个键值存储(如 Map),您可以在其中插入任何类型的数据你想。我在这里只列出了一个参数(“arg”),但您可以输入任意数量的参数。有关它支持的所有 getter 和 setter,请参阅 the Bundle docs
    • 对不起,我错过了您的第一条评论,我的意思是 2 个注入字段。但是没关系。所以如果我理解得很好,你是说我们不能注入带有参数的片段?我们必须使用静态工厂方法 newInstance ?
    • @JohnDot 我的意思是无论参数如何,你都不应该在 Fragment 上使用构造函数注入(或任何其他 Android 可以自行创建和销毁的对象,包括应用程序,活动、视图和服务)。您仍然可以注入 Fragment,但正确的位置是在 onAttach 中,如上所述。将状态和参数(“参数”)传递到 Fragment 的正确方法是使用 Bundle;您可以选择用静态工厂方法封装它。 (您也可以只要求您的消费者调用 new,然后使用特定的 Bundle 结构调用 setArguments。)
    • @JohnDot 我已经更新了答案以在 cmets 中包含一些信息,并阐明 Bundle 逻辑和 DI 代码的工作原理。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多