Android — Content Providers + Dependency Injection (Dagger 2)

Pedro Okawa
3 min readSep 12, 2018

Are you an Android Developer? Do you use Dagger for Dependency Injection? Do you need to implement a Content Provider and don’t want to create a Singleton?
Well, that was my situation a few days ago and I didn’t have any idea on how to do so.

My “How can I do it?” reaction

The project that I worked on consisted on a VoIP mock application, using the phone contacts requested by a CursorLoader and allowing the user to make a “call” to a contact by clicking them. So, I used a ContentProvider and SQLite scripts to store these fake calls on database (Yeah, I know that I could store it using Room, Realm, GreenDAO etc, but I wanted to make it using SQLite). You may check the project here https://github.com/PedroOkawa/voip-app.

The point is, how can I create a ContentProvider in a dependency Injection context? How can I provide a database instance to my ContentProvider? The answer is simple… Dagger 2.

Dagger has some new amazing features that can help us. These features include the power to allow you inject dependencies into Services, BroadcastReceivers and ContentProviders without making a reference to it in your application Component. You may find these new types described here: https://google.github.io/dagger/android

My “Is that possible?” reaction

Ok, let’s show some code now. What are the steps that I need to implement it?

First, you need to include Dagger Android dependency in your gradle file

// In my case I used 2.16 version
implementation 'com.google.dagger:dagger-android:[DaggerVersion]'

Second, it’s time to implements the interface HasContentProviderInjector in your custom application class. It will return an instance of an AndroidInjector based on ContentProvider type.

PS: Note that I called my injection method into attachBaseContext method, because the Provider onCreate method is called before Application onCreate and I got this by this StackOverflow post: https://stackoverflow.com/a/44413873/2200209

class App : Application(), HasActivityInjector, HasContentProviderInjector {

@Inject
lateinit var androidInjector: DispatchingAndroidInjector<Activity>

@Inject
lateinit var contentProviderInjector: DispatchingAndroidInjector<ContentProvider>


override fun activityInjector() = androidInjector

override fun contentProviderInjector() = contentProviderInjector

override fun attachBaseContext(base: Context?) {
super.attachBaseContext(base)
setupDependencyInjection()
}

/**
* Injects the app component
*/
private fun setupDependencyInjection() {
DaggerAppComponent.builder().application(this).build().inject(this)
}

}

Third and finally you just have to inject the database into your ContentProvider class by doing:

class VoIPAppProvider: ContentProvider() {

@Inject
lateinit var databaseHelper: DatabaseHelper


override fun onCreate(): Boolean {
AndroidInjection.inject(this)
return true
}

override fun insert(uri: Uri?, contentValues: ContentValues?): Uri? {
...
return uri
}

override fun query(uri: Uri?, projection: Array<out String>?, selection: String?, selectionArgs: Array<out String>?, sortOrder: String?): Cursor {
...
return cursor
}

override fun getType(uri: Uri?): String {
...
return type
}
override fun update(uri: Uri?, contentValues: ContentValues?, selection: String?, selectionArgs: Array<out String>?): Int {
...
return rowsUpdated
}

override fun delete(uri: Uri?, selection: String?, selectionArgs: Array<out String>?): Int {
...
return rowsDeleted
}
}

Afterwards, you’ll be fine to use your databaseHelper instance along your ContentProvider class.

Woooow! We did it!

I hope it helped anyone that is reading and if you have any suggestion about this post, just tell me. Maybe there are better ways to solve this.

Thanks to Mick (https://stackoverflow.com/users/1384374/mick) for the answer on StackOverflow and LeEnot (https://toster.ru/user/LeEnot) for the answer on https://toster.ru/q/287891

--

--