简体   繁体   中英

Inject Application Context in Repository with Dagger 2

I used the Dagger 2.17 to get the application context in the repository to access the resources:

ContextInjection.kt:

@Module
class ContextModule(private val context: Context) {

    @Singleton
    @Provides
    fun providesContext(): Context {
        return context
    }
}

@Singleton
@Component(modules = [ContextModule::class])
interface ContextComponent {
    fun inject(): Context
}

Initialization.kt:

class Initialization : Application() {

    override fun onCreate() {
        super.onCreate()

        contextComponent = DaggerContextComponent.builder()
            .contextModule(ContextModule(this.applicationContext))
            .build()
    }

    companion object { // for access in repository
        lateinit var contextComponent: ContextComponent
    }
}

Repository.kt:

@Singleton
class Repository {

    @Inject
    lateinit var context: Context

    /** the method is invoked from view model class */
    fun loadList(pageIndex: Int): List<String> {
        context = Initialization.contextComponent.inject()
        val input = context.assets.open("tab1/item1/description.txt")
        ...
    }
}

ViewModel.kt:

class PageViewModel : ViewModel() {

    @NonNull
    private val repository = Repository()

    private val pageIndex = MutableLiveData<Int>()

    val items = Transformations.map<Int, List<String>>(pageIndex) { index: Int ->
        repository.loadList(index)
    }

    fun setIndex(index: Int) {
        pageIndex.value = index
    } 
}

This works, but I have the next question : is there any other (better) way to get the context in the repository using a Dagger?

Note : I am confused by the static invoke:

context = Initialization.contextComponent.inject()

Not sure if this is good practice.

Thank you for any answer/comment!

You can use a dependency which provides these assets to the repository. And this dependency can contain a reference to the context. So your repository can simply query this dependency to get the assets it requires.

Here's a gist of it:

AssetProvider:

class AssetProvider @Inject constructor(
    private val context: Context
) {
    
    fun getDescription() = context.assets.open("tab1/item1/description.txt")
}

Repository:

@Singleton
class Repository @Inject constructor(
    private val assetProvider: AssetProvider
) {

    fun loadList(pageIndex: Int): List<String> {
        val input = assetProvider.getDescription()
        ...
    }
}

I like having repositories that have minimal dependency on Android specific stuff. So the repository logic is agnostic to the platform it runs on. This also helps in unit tests where you don't have to inject context to test your repository.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM