注入注入的片段(没有重复的组件)

时间:2017-02-13 08:04:48

标签: android android-fragments dependency-injection dagger-2

我有一个MainActivity,需要一个MeasurementFragment,而这又需要一个转换器。

问题是:当<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div class="affiliate-links"> <table class="affiliateLinksTable"> <tbody> <tr> <td><label for=""> FIrst Product Name</label></td> <td><input class="myClass" id="affiliateLinkGenerated" type="text" name="affiliate-link" value="http://firstproduct.html?A="></td> </tr> <tr> <td><label for=""> Second Product Name</label></td> <td><input class="myClass" id="affiliateLinkGenerated" type="text" name="affiliate-link" value="http://secondproduct.html?A="></td> </tr> <tr> <td><label for=""> FIrst Product Name</label></td> <td><input class="myClass" id="affiliateLinkGenerated" type="text" name="affiliate-link" value="http://thirdproduct.html?A="></td> </tr> <tr> <td><label for=""> FIrst Product Name</label></td> <td><input class="myClass" id="affiliateLinkGenerated" type="text" name="affiliate-link" value="http://fourthproduct.html?A="></td> </tr> <tr> <td><label for=""> FIrst Product Name</label></td> <td><input class="myClass" id="affiliateLinkGenerated" type="text" name="affiliate-link" value="http://fifthproduct.html?A="></td> </tr> <tr> <td><label for=""> FIrst Product Name</label></td> <td><input class="myClass" id="affiliateLinkGenerated" type="text" name="affiliate-link" value="http://sixthproduct.html?A="></td> </tr> <tr> <td><label for=""> FIrst Product Name</label></td> <td><input class="myClass" id="affiliateLinkGenerated" type="text" name="affiliate-link" value="http://seventhproduct.html?A="></td> </tr> </tbody> </table> <div > <div class="affiliate-id-form"> <input type="text" name="affiliateID" id="affiliateID" placeholder="Enter your affiliate ID eg. 124531" /> <input type="button" name="generate-links" id="btnGenerateLinks" value="Generate Links"> </div>注入MesurementFragment时,其自身的依赖关系[1] converter将被取消注入。

[2]

有没有办法让注入“级联”,以便在注入class MainActivity extends AppCompatActivity { @Inject MeasurementFragment measureFrag; @Override protected void OnCreate(Bundle b){ //[1]* DaggerMainActivityComponent().create().inject(this); } } 时注入converter

我可以在构造函数(measureFrag)中创建DaggerMainActivityComponent的第二个实例并注入其中,但这听起来不错。

[3]

其他可能相关的代码(组件和模块):

class MeasurementFragment extends Fragment {

    // [2]*
    @Inject Converter converter;

    // required *empty* constructor
    MeasrementFragment(){
        // [3]*
    }
}

有没有更好的设计来实现这一目标?

1 个答案:

答案 0 :(得分:1)

有时当我们学习像Dagger 2这样的依赖注入框架时,会产生误解,即不惜一切代价避免使用new关键字和静态工厂,并且每个对象应该注射。

对于Fragments,实例化的best practice是使用静态工厂方法。尽管之前的DI框架Roboguice鼓励将Fragments注入活动的属性(@Inject MeasurementFragment mf),但使用Dagger 2尝试不同的方法可能会更好。这样做的原因是我们需要与活动的FragmentManager进行协调:

对于给定的Activity,片段由FragmentManager处理。当调用Activity onSaveInstanceState(Bundle outBundle)时(例如,在内存不足的情况下),FragmentManager将保存每个Fragment的实例状态以便在onCreate(Bundle savedInstanceState);内进行恢复。

这就是您经常在Android示例中看到的原因:

    if (savedInstanceState == null) {
        // During initial setup, plug in the details fragment.
        DetailsFragment details = new DetailsFragment();
        details.setArguments(getIntent().getExtras());
        getFragmentManager().beginTransaction().add(android.R.id.content, details).commit();
    }

检查saveInstanceState == null以防FragmentManager中已存在Fragment。如果从已保存的实例状态恢复活动,您可以使用:

fragmentManager.findFragmentByTag(String tag)

获取它的句柄。这意味着使用Dagger 2在Activity内部简单地注入Fragment不足以解释Fragments和Activities的复杂生命周期。

更好的方法可能是放弃在Activity中注入Fragment的属性,并按照Developer's Guide中的建议使用静态工厂。然后,您将在Fragment本身中为Fragment 注入依赖项。像这样:

class MeasurementFragment extends Fragment {

    @Inject Converter converter;

    static MeasurementFragment instantiate() {
        //if MeasurementFragment comes to require params in the future
        //you can pass them in here and use setArguments(Bundle params);
        return new MeasurementFragment(null); 
    }

    MeasurementFragment(){
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        DaggerMainActivityComponent.builder()
            .build()
            .inject(this);
    } 
}

现在,当您在Activity中的fragmentManager.beginTransaction().add()上使用MeasurementFragment时,当Android系统调用生命周期回调到onActivityCreated(Bundle bundle)时,将在提交时执行注入。

使用此方法,您的活动可能会是这样的:

class MainActivity extends AppCompatActivity {

    public static final String MEASUREMENT_FRAG = "MEASUREMENT_FRAG";

    MeasurementFragment measureFrag;

    @Override
    protected void OnCreate(Bundle b){
       super(b);
       injectMembers();
       if (b == null) {
           measureFrag = MeasurementFragment.instantiate();
           getFragmentManager().beginTransaction().add(R.id.frag_container, measureFrag, MEASUREMENT_FRAG).commit();
       }
       else {
           //frag is already instantiated and added to container
           measureFrag = getFragmentManager().findFragmentByTag(MEASUREMENT_FRAG);
       }
    }

    @VisibleForTesting
    void injectMembers() {
       DaggerMainActivityComponent().create().inject(this);
    }
}

我在这里概述的是在这个流行的Dagger 2 example on Github中演示的片段内注入成员的方法。更进一步的是使Fragments尽可能轻量级,并完全避免在其中注入依赖项,如Google Android Architecture Blueprint for Dagger 2中所示。