Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to inject a singleton using hilt inside a composable

I'm trying to inject a singleton class that was defined in a hiltmodule inside a composable. I know how to inject viewmodels but what about singleton classes ?

@Inject
    lateinit var mysingleton: MySingletonClass

This code works fine in an activity but carrying it around from the activity to the composable that uses it is a long way ... Any better solution ?

like image 369
user3459435 Avatar asked Nov 27 '25 14:11

user3459435


2 Answers

You should not inject dependencies into a function, which is what a @Composable is. You may want to inject them into the ViewModel or the Activity.

If you need access to a ViewModel-scoped (or Application-scoped) singleton inside a @Composable, you can have that singleton injected into the ViewModel, and then access the ViewModel from the @Composable.

You can inject that singleton into the ViewModel by annotating the provider function for that object in the ViewModel hilt module as @ViewScoped.

You could install the provider into the SingletonComponent::class and annotate it as @Singleton, if you want a singleton for the whole app, instead of a singleton per ViewModel instance. More info here.

Hilt module file

@Module
@InstallIn(ViewModelComponent::class)
object ViewModelModule {

    @ViewScoped
    @Provides
    fun provideMySingleton(): MySingletonClass = MySingletonClass()
}

Your ViewModel class:

@HiltViewModel
class MyViewModel
@Inject constructor(
    val mySingleton: MySingletonClass
): ViewModel() {

...

}

Your @Composable function:

@Composable fun DisplayPrettyScreen() {
...
    val viewModel: MyViewModel = hiltViewModel()
    val singleton = viewModel.mySingleton  //no need to assign it to a local variable, just for explanation purposes

}
like image 106
Dissident Dev Avatar answered Nov 30 '25 04:11

Dissident Dev


I also thought that is not possible but then found way... tried it and seems it works.

define you entry point interface:

private lateinit var dataStoreEntryPoint: DataStoreEntryPoint

@Composable
fun requireDataStoreEntryPoint(): DataStoreEntryPoint {
    if (!::dataStoreEntryPoint.isInitialized) {
        dataStoreEntryPoint =
            EntryPoints.get(
                LocalContext.current.applicationContext,
                DataStoreEntryPoint::class.java,
            )
    }
    return dataStoreEntryPoint
}

@EntryPoint
@InstallIn(SingletonComponent::class)
interface DataStoreEntryPoint {
    val dataStoreRepo: DataStoreRepo
}

DataStoreRepo is singleton defined in Hilt

@Singleton
    @Provides
    fun provideDataStoreRepository(dataStore: DataStore<Preferences>): DataStoreRepo =
        DataStoreRepo(dataStore)

and then use in composable:

@Composable
fun ComposableFuncionName(dataStoreRepo: DataStoreRepo = requireDataStoreEntryPoint().dataStoreRepo){
...
}
like image 26
Peter Avatar answered Nov 30 '25 03:11

Peter



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!