Android Dagger-2 how to provide the dependency for

2019-03-05 14:36发布

I have a module FragmentModule

@Module
public class FragmentModule
{
    @Provides
    public static PickerDashboardFragment providesPickerDashboard(int status, String name, Object someComplexObject)
    {
        PickerDashboardFragment fragment = new PickerDashboardFragment();
        Bundle b = new Bundle();
        b.putInt("status", status);
        b.putString("name", name);
        b.putInt("object", someComplexObject);
        fragment.setArguments(bundle);
        return fragment;
    }

    @Provides
    public static PickingFragment providesPickingFragment()
    {
        PickingFragment fragment = new PickingFragment();
        return fragment;
    }
}

Here's my Component class

@Component(modules = {UtilModule.class, FragmentModule.class})
public interface ApplicationComponent
{
    void inject(PickerDashboardActivity target);
}

In my activity this is how i'm injecting the PickerDashboardActivity

@Inject 
PickerDashboardFragment frag;

ApplicationComponent component = DaggerApplicationComponent.builder().build();
        component.inject(this);

My question is what's the best and easiest way to provide the dependencies for PickerDashboardFragment providesPickerDashboard(int status, String name, Object someComplexObject) i.e status, name and someComplexObject.

Best Regards

2条回答
beautiful°
2楼-- · 2019-03-05 15:00

Don't inject Fragments into your Activities using Dagger 2. Why? Fragments have a lifecycle controlled by the Android OS. When you add a Fragment to an Activity using a transaction, the FragmentManager will retain a reference to the Fragment. When the Activity instanceState is saved, the Fragments added to FragmentManager will be saved. When the Activity is restored, if you request injection without checking for the presence of the Fragment in the FragmentManager, your Activity begin to reference two instances of the Fragment and create a memory leak.

For this reason, in void onCreate(Bundle savedInstanceState) method you should check for the presence of the retained Fragment in the FragmentManager rather than request injection from Dagger 2. If the Fragment is not retained then you can instantiate it at that point. It is perfectly fine to use the new keyword or static factories for this.

Example:

MyFragment frag;

void onCreate(Bundle savedInstanceState) {
     setContentView(R.layout.content);
     frag = fragmentManager.findFragmentByTag(MyFragment.TAG);
     if (frag == null) {
         frag = MyFragment.instantiate(new Bundle());
     }
}

However, at another level it seems you are asking how to combine parameters and dependencies. A good solution for these is often Factories. Say you have a CoffeeMaker:

class CoffeeMaker {

    private final Kettle kettle;
    private final Grinder grinder;
    private final BeanFlavour beanFlavour;

    CoffeeMaker(Kettle kettle, Grinder grinder, BeanFlavour beanFlavour) {
        this.kettle = kettle;
        this.grinder = grinder;
        this.beanFlavour = beanFlavour;
    }
}

The beanFlavour is variable (dark, roasted etc.) and varies and so is more like a parameter than a dependency. You could then write a CoffeeMakerFactory and inject this using Dagger 2:

 class CoffeeMakerFactory {

     private final Kettle kettle;
     private final Grinder grinder;

     @Inject
     CoffeeMakerFactory(Kettle kettle, Grinder grinder) {
         this.kettle = kettle;
         this.grinder = grinder;
     }

     public CoffeeMaker create(BeanFlavour beanFlavour) {
         return new CoffeeMaker(kettle, grinder, beanFlavour);
     }
 }

Factories are the standard solution for a combination of dependency and parameters see here and they can even be be generated using code generation tools like Google Auto.

查看更多
劫难
3楼-- · 2019-03-05 15:02

Add attributes and Provides methods to your module like this:

@Module
public class FragmentModule
{

    private final int status;
    private final String name;
    private final Object someComplexObject;

    public FragmentModule(int status, String name, Object someComplexObject) {
        this.status = status;
        this.name = name;
        this.someComplexObject = someComplexObject;
    }

    @Provides
    int providesStatus() {
        return status;
    }

    @Provides
    String providesName() {
        return name;
    }

    @Provides
    Object providesSomeComplexObject() {
        return someComplexObjext;
    }

    @Provides
    public static PickerDashboardFragment providesPickerDashboard(int status, String name, Object someComplexObject)
    {
        PickerDashboardFragment fragment = new PickerDashboardFragment();
        Bundle b = new Bundle();
        b.putInt("status", status);
        b.putString("name", name);
        b.putInt("object", someComplexObject);
        fragment.setArguments(bundle);
        return fragment;
    }

    @Provides
    public static PickingFragment providesPickingFragment()
    {
        PickingFragment fragment = new PickingFragment();
        return fragment;
    }
}

Having a module providing ints and Strings will probably make you use some qualifiers (such as Named) in order to avoid collisions

查看更多
登录 后发表回答