Reputation: 603
I'm trying to read a json file from res/raw folder, but I'm not in an Activity, it's in a Kotlin object
. I can't manage to read it without context
or applicationContext
which I don't have there.
I tried to create a class where I inject the context with Hilt, but that failed too because I can't inject that class in my object. I'm stuck, what am I missing? It can't be that difficult?
The json file is currently only
{
"spacer": 8
}
Perhaps in the future some more parameters will be added. I want to save this value in an object (which contains other values not from json) so I don't have to read it every time it's needed. The parameter is used in a Compose theme.
Upvotes: 2
Views: 1591
Reputation: 1195
Unfortunately, as Thales said in this comment, you can create an EntryPoint
to inject anything that Hilt is providing but you'll still need the applicationContext
to start with, so you will still have to workaround the fact that you don't have it in your object. You could have your Application
class inject its context in its onCreate
method, using a 'initializer' function for your object that will both save the applicationContext
for the use case that you need strings or other resources and also will enable things like injecting any object provided by Hilt in your application. I will give you an example on how you would need to change your application class and how your object could look like.
import android.app.Application
import dagger.hilt.android.HiltAndroidApp
@HiltAndroidApp
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
MyObject.initializeMyObject(applicationContext)
}
}
and your object could be something like this:
import android.annotation.SuppressLint
import android.content.Context
import dagger.hilt.EntryPoint
import dagger.hilt.InstallIn
import dagger.hilt.android.EntryPointAccessors
import dagger.hilt.components.SingletonComponent
// MyExampleInterface should be properly configured to be provided by Hilt
@EntryPoint
@InstallIn(SingletonComponent::class)
interface MyObjectEntryPoint {
fun myExampleInterface(): MyExampleInterface
}
@SuppressLint("StaticFieldLeak")
object MyObject {
private var myContext: Context? = null
private var injectedDependency: MyExampleInterface? = null
// make sure the context passed is applicationContext to avoid memory leaks
fun initializeMyObject(applicationContext: Context) {
myContext = applicationContext
myContext?.let {
val hiltEntryPoint =
EntryPointAccessors.fromApplication(it, MyObjectEntryPoint::class.java)
injectedDependency = hiltEntryPoint.myExampleInterface()
}
}
fun getResourceFromObject(): String {
return myContext?.getString(R.string.app_name) ?: "Context not injected"
}
fun usingInjectedDependency(): String {
return injectedDependency?.myExampleFunction() ?: "Dependency not injected"
}
}
I am not a super expert on memory leaks, but if you make sure the context
passed to initializeMyObject
is always the applicationContext
from its onCreate
method, you won't have any problems with leaks since the applicationContext
is not released until the application restarts or it is killed anyways.
if you were using Koin you could do something like this:
import android.content.Context
import com.your.app.R
import org.koin.java.KoinJavaComponent.get
object YourObject {
val context: Context = get(Context::class.java)
val yourString = context.getString(R.string.your_string)
// do other stuff with context here
}
you should just take care not to store this context object because it could cause memory leaks, you could just use it to get your resource without assigning it to any variables like
val yourString = get(Context::class.java).getString(R.string.your_string)
Upvotes: 0
Reputation: 21
You could try to use a context extension function to read your json file from /assets folder:
fun Context.getJsonFromAssets(fileName: String): String? {
val jsonString: String
try {
val inputStream = assets.open(fileName)
val size = inputStream.available()
val buffer = ByteArray(size)
inputStream.read(buffer)
inputStream.close()
jsonString = String(buffer, Charset.defaultCharset())
} catch (e: IOException) {
e.printStackTrace()
return null
}
return jsonString
}
Upvotes: 2