I have an object where I need to inject context as follows (lets focus on playButtonSound method):
object AWSound {
private var soundPool: SoundPool? = null
private var soundPoolMap: SparseIntArray? = null
private const val S2 = R.raw.button_press
//private lateinit var appContext: Context
private fun playSound(oContext: Context?, soundID: Int, soundType: Int) {
val sharedPref = PreferenceManager.getDefaultSharedPreferences(
oContext!!
)
val strButtonSoundOnOff = sharedPref.getString("buttonsound", "off")
val strPageFlipSoundOnOff = sharedPref.getString("pageflipsound", "off")
val strEndTestSoundOnOff = sharedPref.getString("endtestsound", "off")
var playSound = false
when (soundType) {
0 -> if (strButtonSoundOnOff != null && strButtonSoundOnOff == "on") {
playSound = true
}
1 -> if (strPageFlipSoundOnOff != null && strPageFlipSoundOnOff == "on") {
playSound = true
}
2 -> if (strEndTestSoundOnOff != null && strEndTestSoundOnOff == "on") {
playSound = true
}
else -> {}
}
if (playSound) {
val volume = 1.0.toFloat()
if (soundPool == null || soundPoolMap == null) {
initSounds(oContext)
soundPool!!.play(soundPoolMap!![soundID], volume, volume, 1, 0, 1f)
}
soundPool!!.play(soundPoolMap!![soundID], volume, volume, 1, 0, 1f)
}
}
/***
* Put sounds from raw into SoundPool
*/
private fun initSounds(oContext: Context?) {
soundPool = SoundPool.Builder()
.setMaxStreams(2)
.build()
soundPoolMap = SparseIntArray(2)
soundPoolMap!!.put(S2, soundPool!!.load(oContext, R.raw.button_press, 2))
}
fun playButtonSound() {
playSound(appContext, R.raw.button_press, 0) //0=>Button press sound
}
fun playPageFlipSound(context: Context?) {
playSound(context, R.raw.page_flip, 1) //1=>Page flip sound
}
}
As I know Hilt cannot @Inject into Kotlin objects (don't know why btw) I decided to try an approach I've found on SO, so my code ended like the next:
object AWSound : BaseClass() {
private var soundPool: SoundPool? = null
private var soundPoolMap: SparseIntArray? = null
private const val S2 = R.raw.button_press
//private lateinit var appContext: Context
private fun playSound(oContext: Context?, soundID: Int, soundType: Int) {
val sharedPref = PreferenceManager.getDefaultSharedPreferences(
oContext!!
)
val strButtonSoundOnOff = sharedPref.getString("buttonsound", "off")
val strPageFlipSoundOnOff = sharedPref.getString("pageflipsound", "off")
val strEndTestSoundOnOff = sharedPref.getString("endtestsound", "off")
var playSound = false
when (soundType) {
0 -> if (strButtonSoundOnOff != null && strButtonSoundOnOff == "on") {
playSound = true
}
1 -> if (strPageFlipSoundOnOff != null && strPageFlipSoundOnOff == "on") {
playSound = true
}
2 -> if (strEndTestSoundOnOff != null && strEndTestSoundOnOff == "on") {
playSound = true
}
else -> {}
}
if (playSound) {
val volume = 1.0.toFloat()
if (soundPool == null || soundPoolMap == null) {
initSounds(oContext)
soundPool!!.play(soundPoolMap!![soundID], volume, volume, 1, 0, 1f)
}
soundPool!!.play(soundPoolMap!![soundID], volume, volume, 1, 0, 1f)
}
}
/***
* Put sounds from raw into SoundPool
*/
private fun initSounds(oContext: Context?) {
soundPool = SoundPool.Builder()
.setMaxStreams(2)
.build()
soundPoolMap = SparseIntArray(2)
soundPoolMap!!.put(S2, soundPool!!.load(oContext, R.raw.button_press, 2))
}
fun playButtonSound() {
playSound(appContext, R.raw.button_press, 0) //0=>Button press sound
}
fun playPageFlipSound(context: Context?) {
playSound(context, R.raw.page_flip, 1) //1=>Page flip sound
}
}
abstract class BaseClass {
@Inject lateinit var appContext: Context
}
And the error I get when calling playButtonSound is "lateinit property appContext has not been initialised".
Well, maybe with a slight modification it might work, I thought:
@AndroidEntryPoint
abstract class BaseClass : Service() {
@Inject lateinit var appContext: Context
}
Of course I don't need to inherit "Service()", but this way I can add the "@AndroidEntryPoint" decorator, but again, to no avail and the exact same error.
I thought "maybe I could try constructor injection", so BaseClass ended like this:
@AndroidEntryPoint
abstract class BaseClass
@Inject constructor (val appContext: Context) : Service() {
}
But this way ": BaseClass()" in AWSound complains that a constructor parameter is missing, and I don't know how to deal with this.
Lastly I have to mention that I have a "Dependencies" module where I provide context (among other dependencies):
@Module
@InstallIn(SingletonComponent::class)
class Dependencies {
@Provides
@Singleton
fun provideContext(@ApplicationContext appContext: Context): Context {
return appContext
}
}
Of course I can create an init function in AWSound like this:
private lateinit var context: Context
fun init(context: Context) {
this.context = context
}
And initialize it in ApplicationClass like this:
@HiltAndroidApp
class AWApplication : MultiDexApplication() {
override fun onCreate() {
super.onCreate()
AWSound.init(this)
}
}
And I'm sure it'll work (as I've done it in other places), but this way I'm not taking any benefit of Hilt, this is just a simple Kotlin singleton property initialisation. How is Hilt helping me this way?
I'm stuck, and I have to admit Hilt is driving me nuts. What it was supposed to simplify our programming life making our app maintainable, ended up being a nightmare (at least for me).
So, any help on injecting context (or whatever) in my objects.