Calling injection () method from dagger module method - bad practice?

I am still new to Dependency Injection and I am trying to implement my application using the MVP design pattern . I am using a graph for each view. I decided that my adapter should be considered part of the view after reading this great article .

The view in my example is Fragment . I've created a module [called FragmentModule ] that provides Presenter and View .

Before I started to work around, the module only injected the Fragment and provided the FragmentAdapter by calling its constructor with the required parameters.

Module:

@Module(
        overrides = true,
        includes = BaseFragmentModule.class,
        injects = {
                MyFragment.class,
        }
)
public class FragmentModule {

    private MyFragment mFragment;

    // ... // Other methods removed for clarity

    @Provides
    @Singleton
    public FragmentAdapter provideAdapter() {
        return new FragmentAdapter(mFragment.getActivity(), mFragment);
    }

    // ... //
}

      

The FragmentAdapter constructor looked something like this:

private Context mContext;
private CustomListener mListener;

public FragmentAdapter(Context context, CustomListener listener)
{
    mContext = context;
    mListener = listener;
    // ... // 
}

      

This may be the "right way to do it", but I want to discuss how I am doing it now, so keep reading!

Then I rewrote it again so that the FragmentAdapter takes a reference to the Fragment instance . Then I assigned Context and Listener in the FragmentAdapter constructor .

private MyFragment mFragment;

@Provides
@Singleton
public FragmentAdapter provideAdapter() {
    return new FragmentAdapter(mFragment);
}

      

The Adapter constructor looks like this:

private Context mContext;
private CustomListener mListener;

public FragmentAdapter(MyFragment iFragment)
{
    mContext = iFragment.getActivity();
    mListener = iFragment;
    // ... // 
}

      

After that, I decided that for some reason I wanted to inject Context into the adapter. So I continued: I made a FragmentModule insert the adapter as well, for example:

@Module(
        overrides = true,
        includes = BaseFragmentModule.class,
        injects = {
                FragmentAdapter.class,
                MyFragment.class,
        }
)

      

Now I needed to learn how to inject a FragmentAdapter into an ObjectGraph with a fragment scope in a nice, clean way. First I called inject () from the FragmentAdapter constructor :

FragmentModule:

// ... //
private MyFragment mFragment;
// ... //
@Provides
@Singleton
public FragmentAdapter provideAdapter() {
    return new FragmentAdapter(mFragment);
}
// ... //

      

FragmentAdapter

@Inject Context mContext;
@Inject MyListener mListener;

public FragmentAdapter(MyFragment iFragment)
{
    iFragment.getObjectGraph().inject(this);
    // ... // 
}

      

Again, for some reason (remember that I study ..) - I wanted to injection worked, not passing a copy fragment in Designer FragmentAdapter , so I finished the call inject () from the class of Module:

    @Provides
    @Singleton
    public FragmentAdapter provideAdapter() {
        if (mAdapter == null) {
            mAdapter = new FragmentAdapter();
            mFragment.getObjectGraph().inject(mAdapter);
            mAdapter.initialize(); // Code moved from constructor which depends on injected members
        }
        return mAdapter;
    }

      

Now I'm wondering: what do you think is the best practice here? How would you implement the Adapter and Fragment dependencies with dagger injection? And why?

Thanks a lot for your feedback!

+3


source to share


1 answer


As I see ObjectGraph.inject(...)

it should be avoided as much as possible. Instead, you want to do a constructor installation: pass your nested dependencies into your constructor.

You can do this by adding a constructor to you @Inject

:

private final Context mContext;
private final MyListener mListener;

@Inject
public FragmentAdapter(Context context, MyListener listener)
{
    mContext = context;
    mListener = listener;
    // ... // 
}

      



Now you don't need it anymore provideAdapter()

as Dagger recognizes the annotation @Inject

in the constructor. You need to provide instances of Context

and MyListener

, which I assume you are already doing.

Which, having said, I don't believe what MyListener

should be entered. This is not your dependency FragmentAdapter

, but a function. Just call setListener(MyListener)

from your class Fragment

.

The last remark, sometimes inject(...)

, cannot be avoided. Especially when you are using classes whose constructors you do not control (for example, Activity

and Fragment

).

+1


source







All Articles