I started setting up dependency injection using Dagger as follows. Please feel encouraged to correct my implementation since I might have mistakes in there! The implementation follows the android-simple example provided by the project. In the following you can see how I successfully added dependency injection for Activities
and Fragments
. I try to keep it easy for now so I decided to inject Timber as a logger substitution for Android's log util.
import android.app.Application; import java.util.Arrays; import java.util.List; import dagger.ObjectGraph; import com.example.debugging.LoggingModule; public class ExampleApplication extends Application { private ObjectGraph mObjectGraph; protected List<Object> getModules() { return Arrays.asList( new AndroidModule(this), new ExampleModule(), new LoggingModule() ); } private void createObjectGraphIfNeeded() { if (mObjectGraph == null) { Object[] modules = getModules().toArray(); mObjectGraph = ObjectGraph.create(modules); } } public void inject(Object object) { createObjectGraphIfNeeded(); mObjectGraph.inject(object); } }
By now the AndroidModule
is not used anywhere it but might be helpful when a Context
and LayoutInflater
is needed e.g. in CursorAdapters
.
import android.content.Context; import android.view.LayoutInflater; import javax.inject.Singleton; import dagger.Module; import dagger.Provides; /** * A module for Android-specific dependencies which require a {@link Context} * or {@link android.app.Application} to create. */ @Module(library = true) public class AndroidModule { private final ExampleApplication mApplication; public AndroidModule(ExampleApplication application) { mApplication = application; } /** * Allow the application context to be injected but require that it be * annotated with {@link ForApplication @Annotation} to explicitly * differentiate it from an activity context. */ @Provides @Singleton @ForApplication Context provideApplicationContext() { return mApplication; } @Provides @Singleton LayoutInflater provideLayoutInflater() { return (LayoutInflater) mApplication .getSystemService(Context.LAYOUT_INFLATER_SERVICE); } }
I am not sure what application-specific providers would go here. I stay with logging for now.
import dagger.Module; @Module( complete = false ) public class ExampleModule { public ExampleModule() { // TODO put your application-specific providers here! } }
I prepared LoggingModule
which provides access to Timber.
package com.example.debugging; import javax.inject.Singleton; import dagger.Module; import dagger.Provides; import com.example.BuildConfig; import com.example.activities.BaseFragmentActivity; import com.example.activities.DetailsActivity; import com.example.fragments.BaseListFragment; import com.example.fragments.ProfilesListFragment; import timber.log.Timber; @Module(injects = { // Activities BaseFragmentActivity.class, DetailsActivity.class, // Fragments BaseListFragment.class, ProfilesListFragment.class }) public class LoggingModule { @Provides @Singleton Timber provideTimber() { return BuildConfig.DEBUG ? Timber.DEBUG : Timber.PROD; } }
The base class for Activities
injects itself into the object graph ...
package com.example.activities; import android.os.Bundle; import com.actionbarsherlock.app.SherlockFragmentActivity; import javax.inject.Inject; import com.example.ExampleApplication; import timber.log.Timber; public abstract class BaseFragmentActivity extends SherlockFragmentActivity { @Inject Timber mTimber; @Override protected void onCreate(Bundle savedInstanceState) { // ... super.onCreate(savedInstanceState); ((ExampleApplication) getApplication()).inject(this); } }
... and any sub class benefits from Timber being already present.
package com.example.activities; import android.os.Bundle; import com.example.R; public class DetailsActivity extends BaseFragmentActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_details); mTimber.i("onCreate"); // ... } }
Same for Fragments
: the base class does the dirty job ...
package com.example.fragments; import android.os.Bundle; import com.actionbarsherlock.app.SherlockListFragment; import javax.inject.Inject; import com.example.ExampleApplication; import timber.log.Timber; public abstract class BaseListFragment extends SherlockListFragment { @Inject Timber mTimber; @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); ((ExampleApplication) getActivity().getApplication()).inject(this); } }
... and the sub class benefits from its super class.
package com.example.fragments; import android.os.Bundle; public class ProfilesListFragment extends BaseListFragment { @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); // TODO This might be a good example to inject resources // in the base class. But how? setEmptyText(getResources() .getString(R.string.profiles_list_no_content)); mTimber.i("onActivityCreated"); // ... } }
So far so good. But how can inject Timber into BaseCursorAdapter
, BaseContentProvider
, BaseSQLiteOpenHelper
, BaseService
, BaseAsyncTask
and static
helper methods?
The deprecated android example by Christopher Perry points out how to inject an Adapter into a ListFragment but not how to inject Context
, Resources
, LayoutInflater
, Cursor
into the (Cursor)Adapter
or just Timber.
References:
In order to use dependency injection with the help of dagger 2 libraries, we need to add it's dependency. Go to Gradle Scripts > build. gradle(Module: app) and add the following dependencies. After adding these dependencies you need to click on Sync Now.
Types of Dependency Injection The injector class injects dependencies broadly in three ways: through a constructor, through a property, or through a method. Constructor Injection: In the constructor injection, the injector supplies the service (dependency) through the client class constructor.
Dagger automatically generates code that mimics the code you would otherwise have hand-written. Because the code is generated at compile time, it's traceable and more performant than other reflection-based solutions such as Guice. Note: Use Hilt for dependency injection on Android.
Check out Andy Dennie's examples for injecting in different scenarios:
https://github.com/adennie/fb-android-dagger
Some points where I inject:
Activity
, Service
, and Fragment
subclasses: in onCreate
BroadcastReceiver
subclasses (includes, e.g. AppWidgetProvider
): in onReceive
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With