-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support getting resources by key #4880
Comments
Very useful feature and a bit of blocker for me, especially with the lack of reflection in Native. |
Wow thank you! Any chance that it will be available the same for strings? |
No chance. If you want to read strings by path then just read a text file by a path. String items don't have a file path |
What about getting a string by key, eg. |
No. How will it work with qualifiers and arguments? |
If you notice the API I understand that you would like to have something like a runtime search in your string resources based on a string key and a current environment but it is a huge performance problem. That's why we converted XML files to the internal format and use generated classes instead. To iterate by files in the runtime is not possible. So, for your case you have to save strings to the regular txt file and read it as string on your side. |
My current implementation consisted in creating a mapper that maps a string (the key) with the Resource. I had to do it like that because I was not able to use reflection. The main problem is that I need to mantain this file manually and it is very susceptible to bugs. Sorry because of my ignorance because I don't know how the resources are internally working, but it wouldn't be possible to generate this mapping internally so we could access them through it? |
It is possible but the case is rare enough to maintain it. It requires more resources to support it than a real profit. |
I fully agree that the recommended and performant way to access resources, especially string resources, is through static accessors. Android supports accessing resources by key, it discourages this practice for performance reasons. However, this capability exists for special cases where it might be necessary. @Discouraged(message = "Use of this function is discouraged because resource reflection makes "
+ "it harder to perform build optimizations and compile-time "
+ "verification of code. It is much more efficient to retrieve "
+ "resources by identifier (e.g. `R.foo.bar`) than by name (e.g. "
+ "`getIdentifier(\"bar\", \"foo\", null)`).")
public int getIdentifier(String name, String defType, String defPackage) My proposal is to introduce an opt-in feature that allows accessing resources by key. Should be discouraged, but available for the cases where is needed. This feature could look something like the following: private val stringResourcesMap: Map<String, StringResource> = mapOf(
"key1" to Res.string.resource_with_key_1,
"key2" to Res.string.resource_with_key_2
)
fun Res.string.byPath(key: String): StringResource? {
return stringResourcesMap[key]
}
|
+1 I use JSON to define a catalog of weather data types which includes the name, name_string_key, description, units, icon id, etc... I used the |
Until this is resolved, i use a bash script to extract keys from xml and create a map<String, StringResouce>. Example generated class: object StringResourcesMap {
val strings: Map<String, StringResource> = mapOf(
"id_1030_minutes" to Res.string.id_1030_minutes,
"id_12_confirmations" to Res.string.id_12_confirmations,
"id_12_months_51840_blocks" to Res.string.id_12_months_51840_blocks,
"id_12_words" to Res.string.id_12_words
....
}
}
@Composable
fun stringResourceFromId(id: String): String {
return StringResourcesMap.strings[id]?.let {
stringResource(it)
} ?: id
}
suspend fun getStringFromId(id: String): String {
return StringResourcesMap.strings[id]?.let {
getString(it)
} ?: id
} |
@angelix, I am manually creating a map for my drawables but it got me wondering - does this cause hundreds of string and drawable resources to be instantiated? Is this inefficient? I notice the generated I wonder if using a |
An associated question, it there a way to check if a resource exists? |
You have a point, all StringResources are initialized, but not the actual strings or drawables, only the representation of them. That's why we need an official solution and not a custom one. It's a custom solution, so yes, you can have a function to check the existence of the key. |
I've got a solution that doesn't initialize references to resources:
But this only worked on Android. My iOS build and runs but I was unable to catch the exception. I got an "Uncaught Kotlin exception". If anyone has a solution to catching the exception on iOS, please let me know. It would be good if we had a My final solution still requires manually adding the resources:
I wonder if this will cause a concurrent mutation of the icons mutable map?? |
The reason the fist solution doesn't work on iOS is that However, if I replace it with the inefficient It would be great if we can get a |
Ok, I've got something that works. It's implemented for drawables but should be extendable to strings as well.
Iconic.android.kt
Iconic.ios.kt
|
The PR adds a generation special properties with maps a string ID to the resource for each type of resources: ```kotlin val Res.allDrawableResources: Map<String, DrawableResource> val Res.allStringResources: Map<String, StringResource> val Res.allStringArrayResources: Map<String, StringArrayResource> val Res.allPluralStringResources: Map<String, PluralStringResource> val Res.allFontResources: Map<String, FontResource> ``` <!-- Optional --> Fixes #4880 Fixes https://youtrack.jetbrains.com/issue/CMP-1607 ## Testing I checked it in the sample project but this should be tested by QA (KMP and JVM only projects) ## Release Notes ### Features - Resources - Now the gradle plugin generates resources map to find a resource by a string ID
Please check the following ticket on YouTrack for follow-ups to this issue. GitHub issues will be closed in the coming weeks. |
Hello!
I would like to be able to get resources given a key name. I think it is quite useful as you can load images or strings dynamically. For example, given a list of countries (which their ISO code) you can have their translated name and their flag just passing their code to the corresponding function. If you want to get it from Spain (ES):
You can access it through
getString(Res.string.es)
orgetString("es")
.The same with images, if you have a file
es.png
, you can access it throughgetDrawable("es")
.Why is it useful? Because if you have a big list of data, you don't need to manually define their images/strings for each element, for example in a list. You can just iterate over your items and get their resource by their code or id.
The text was updated successfully, but these errors were encountered: