How to use Android resource string in the constructor of Room Entity in Kotlin

Viewed 614

My goal is to add a default value to constructor of the Room @Entity. The default value must depend on the language settings of the user. The way suggested by android framework is to use resource strings.

Here's the code I have:

@Entity
data class ArmyEntity(
    @PrimaryKey(autoGenerate = true)
    val armyId: Long,
    val userOwnerId: Long,
    val name: String = R.string.untitled, // wrong type
    val description: String = R.string.no_description_yet, // wrong type
    val iconUri: String = "",
    val lastEdit: Timestamp = Timestamp(System.currentTimeMillis())
)

The two lines which interest me are labelled with the "wrong type" comments. Calling R.string.resource_string_name returns resource id, rather than the content of resource (returns Int, not String).

Android documentation suggests this way to get the string:

val string: String = getString(R.string.hello)

But the issue is that the getString() function is a member of the Context class and can be used in Activity. But Room Entity annotated doesn't know about context. (Context page for reference)

I tried passing context as a constructor parameter, but unfortunately, every constructor parameter in the data class has to be val or var. As long as I know, Room creates a column for every field in the class. What should I do to provide a language-dependent default value? Thank you!

2 Answers

FOR LOCAL RESOURCES

Define context in your Application class

class MyApplication : Application() {

    companion object {
        lateinit var context: Context
            private set
    }

    override fun onCreate() {
        super.onCreate()
        context = this
    }
}

and then just use MyApplication.context where you need

import com.example.myapp.R
import com.example.myapp.MyApplication

@Entity
data class ArmyEntity(
    @PrimaryKey(autoGenerate = true)
    val armyId: Long,
    val userOwnerId: Long,
    val name: String = MyApplication.context.getString(R.string.untitled),
    val description: String = MyApplication.context.getString(R.string.no_description_yet)
    val iconUri: String = "",
    val lastEdit: Timestamp = Timestamp(System.currentTimeMillis())
)

NOTE : Android studio will warn you about a memory leak. Check this question for more informations

FOR SYSTEM RESOURCES

You can import Resources to access an application's resources with Resources.getSystem(), and the R class.

import android.content.res.Resources
import com.example.yourapp.R

@Entity
data class ArmyEntity(
    @PrimaryKey(autoGenerate = true)
    val armyId: Long,
    val userOwnerId: Long,
    val name: String = Resources.getSystem().getString(R.string.untitled),
    val description: String = Resources.getSystem().getString(R.string.no_description_yet)
    val iconUri: String = "",
    val lastEdit: Timestamp = Timestamp(System.currentTimeMillis())
)

In my opinion you should use the id of that String. Change your DB texture a bit to follow this.

  @Entity
data class ArmyEntity(
    @PrimaryKey(autoGenerate = true)
    val armyId: Long,
    val userOwnerId: Long,
    val descriptionRes: Int = R.string.abc, // this is true for multi-languages
    val iconUri: String = "",
)

fun getDescription(context: Context,armyEntity : ArmyEntity,textView: TextView){
    textView.text = context.getString(armyEntity.descriptionRes)
}
Related