Currently, the approach to inject the presenter for a fragment into the hosting activity only works if the activity hosts a single fragment.
If we have multiple fragments under the same activity, we can't inject all presenters into the activity, because each component will be able to only provide the dependencies for a single presenter (for the very simple case the view).
This also makes things more complicated when the activity is killed but not the fragment, so the presenter must be initialized for each fragment in the back stack when the activity is recreated.
My questions are:
Hey @ialmetwally,
I agree, it doesn't make sense to have one presenter in an Activity for multiple Fragments, since you're most likely presenting different information for each Fragment.
For this reason I personally feel that it's best to create a presenter for each and every fragment. This is what I am doing for both personal and professional projects.
I know this doesn't answer the question of why they decided to inject the presenter at the Activity level. Maybe they did it simply because they know they were only going to use one Fragment per Activity
@TylerMcCraw I've been struggling with this as well. There are still some UI components like the Toolbar that have to be handled by the Activity rather than Fragments. Activities also need to also swap between the fragments displayed. If the Activity has no connection to the Presenter, how do you handle these behaviors? Have any sample app that I could look at? Thanks!
@amitav13
For that scenario, you have a few options.
In general, from an MVP perspective, I treat the Fragment as the View and the Activity as just some auxiliary piece of the view. Presenter shouldn't care/know about what comprises the view.
So, you can solve this by enlisting a listener interface that the Activity implements and whenever your Presenter needs to update the toolbar:
Presenter calls view.updateToolbar() ->
Fragment receives event and forwards event to "ToolbarListener" (which is the Activity) eventListener.updateToolbar() ->
Activity receives the event and updates the Toolbar UI.
You could also solve this via EventBus or some other subscription type design, but if it's a simple event, just stick to a simple interface.
If you need your Activity to notify your presenter, then use your FragmentManager to forward an event towards your Fragment and then have your Fragment call a Presenter method.
Hope this helps :)
We have a pr out #356 that will inject Presenters directly into fragments. The general flow: Activity creates a fragment, fragment registers with dagger, dagger injects the presenter directly into the fragment. This should help with use cases such as having a view pager of fragments that each need their own presenter. Thank you for suggestion!
I'm using it the way @TylerMcCraw is pointing out.
For each Fragment inside it hosts activity I inject the presenter, also I'm using Dagger 2 to be cleaner with the injections
Example Fragment
@Inject
lateinit var presenter: MapsPresenter
After the Fragment's view is destroyed, I release all the views and jobs (if using coroutines or other service) to be collected by the garbage collector, doing this you can release some memory on a large backstack.
override fun onDestroyView() {
super.onDestroyView()
presenter.detachView()
presenter.detachJob()
}
Most helpful comment
@amitav13
For that scenario, you have a few options.
In general, from an MVP perspective, I treat the Fragment as the View and the Activity as just some auxiliary piece of the view. Presenter shouldn't care/know about what comprises the view.
So, you can solve this by enlisting a listener interface that the Activity implements and whenever your Presenter needs to update the toolbar:
Presenter calls
view.updateToolbar()->Fragment receives event and forwards event to "ToolbarListener" (which is the Activity)
eventListener.updateToolbar()->Activity receives the event and updates the Toolbar UI.
You could also solve this via EventBus or some other subscription type design, but if it's a simple event, just stick to a simple interface.
If you need your Activity to notify your presenter, then use your FragmentManager to forward an event towards your Fragment and then have your Fragment call a Presenter method.
Hope this helps :)