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!
source to share
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
).
source to share