[todo-mvp-dagger] DaggerAppCompatActivity - more downsides than benefits?
Biggest problem for me when using DaggerAppCompatActivity is that there is no good way of handling data in savedInstanceState object or some other configuration change behaviours.
In AddEditTaskActivity, mIsDataMissing is extracted from savedInstanceState and can be accessed through method isDataMissing(). This method must be public as it is called from AddEditTaskModule. It finally must be called by AddEditTaskPresenter using Dagger Lazy functionality in a specific place - in takeView method - because if it is called any sooner, that variable will not be set in AddEditTaskActivity at all.
Another example is TasksActivity, where filter type in TasksPresenter is set through contract TasksContract.Presenter method setFiltering.
I guess that there is no unified way of initializing Presenter class or handling various Android specifics, like configuration changes, saving instance state etc. Therefore, I think that DaggerAppCompatActivity usage brings more "mess" to the code than simply calling good old inject method on Activity's onCreate method, where custom module parameters can be set and finally passed to Presenters constructor in a clear injection way.
Please correct me if I am wrong.
The key pain points they highlight
- SavedInstanceState & config changes In AddEditTaskActivity, the mIsDataMissing flag is computed from savedInstanceState after injection.
But because DaggerAppCompatActivity injects before your onCreate() logic runs, you can’t directly pass that flag into Dagger modules at injection time.
This forces awkward workarounds:
isDataMissing() made public just so the module can read it later.
The Presenter must request it lazily (Lazy<>) in takeView() to ensure it’s set.
- Presenter initialization order Example: TasksActivity’s filter type is set via setFiltering() after the Presenter is already injected.
If you wanted to pass that filter into the Presenter’s constructor, you couldn’t without adding extra plumbing.
- Loss of flexibility With DaggerAppCompatActivity, injection timing is fixed — you can’t say “I’ll read my Intent extras first, then build my Dagger graph with those parameters.”
This creates a mismatch between Android lifecycle needs and Dagger injection timing.
Why the author prefers manual injection They’d rather:
@Override protected void onCreate(Bundle savedInstanceState) { // Read data first boolean isDataMissing = savedInstanceState == null; String taskId = getIntent().getStringExtra(EXTRA_TASK_ID);
// Pass to Dagger here (via module constructor args)
AndroidInjection.inject(this);
super.onCreate(savedInstanceState);
// Now the Presenter can be constructed cleanly with runtime params
} Advantages:
Control over when injection happens.
Can read and pass runtime values into modules before injection.
No need for public getters, Lazy<>, or weird delayed initialization.
Common real-world choice A lot of experienced Android + Dagger devs skip DaggerAppCompatActivity entirely, instead:
Extend AppCompatActivity
Call AndroidInjection.inject(this) manually before super.onCreate()
For Fragments, call AndroidSupportInjection.inject(this) in onAttach()
Pass runtime parameters to the component/module during injection
That preserves Dagger’s benefits but avoids the lifecycle/state headaches described in this issue.