I have an app published on the play store and I am facing an annoying problem both for me and my users.
I am storing a list of Object as a JSON String like this:
val obj = JSONObject()
try {
...
obj.put("image", image)
} catch (e: JSONException) {
Log.d("JSONException: ", e.message)
}
where image: Int stores the value of R.drawable.image
The problem is that every time I release an update for my app this image gets replaced with another drawable (not always the same one) from the /res/ folder.
I suspect it has something to do with proguard's code shrinking, since I have both:
minifyEnabled true
shrinkResources true
How can I fix the problem?
If possible I would avoid not to shrink the images, since I have a fair amount of them and it would increase the download size of the app.
You simply cannot rely on the resource numbers to stay the same across builds. You will need to use another identifier to make persistent and then do a mapping to resource number in your app.
For example you could use an array that contains the resource numbers and you persist the index of a certain drawable.
From Google docs: "When your application is compiled, aapt generates the R class, which contains resource IDs for all the resources in your res/ directory. For each type of resource, there is an R subclass (for example, R.drawable for all drawable resources), and for each resource of that type, there is a static integer (for example, R.drawable.icon). This integer is the resource ID that you can use to retrieve your resource." so when you build the APK the ResourceID could change without any expectation...
You can use its Filename and get the ID in runtime using "getResources().getIdentifier(...)"
Related
Are int value of R.id.view is always same?
I tried printed it in two devices and it was same.
I also changed name of id but still the value was same.
But will it stay the same in all scenarios?
For any particular app resource, the particular R class associated resource ID will be the same in all scenarios during runtime as this resource ID is generated by aapt during compile time.
From Android Documentation:
Once you provide a resource in your application, you can apply it by referencing its resource ID. All resource IDs are defined in your project's R class, which the aapt tool automatically generates. When your application is compiled, aapt generates the R class, which contains resource IDs for all the resources in your res/ directory.
Thus printing it in two devices will result the same int value, provided that the same apk is used. Also note that the resource id is final in the respective R subclass.
From this answer:
Note that aapt by default makes no attempt to keep these identifiers
the same between builds. Each time the resources change, they can all
get new identifiers. Each time they are built, a new R.java is created
with the current identifiers so your code gets the correct values.
Because of this, you must never persist resource identifiers anywhere
where they can be used across different builds of your app.
Any changes to the resource might make the resource get an new R class resource ID.
Based on the way in which the R class Resource ID are calculated, as described in that answer, I think since you only changed the name of the XML resource ID, and didn't change the type of the resource nor the placement of the respective View object declaration in the respective XML file, the same R class Resource ID is being calculated.
A View ID is generated during Compilation, so Yes the ID will be the same in each Device if the APK is the same. Pay attention that "different compilations could generate different IDs".
I am building an Android(Kotlin) app which gets data from an API. Part of that data is an Image or more like a reference to an Image inside the Android app. Sadly Android does not accept names as arguments for images, so I have to send IDs(numbers). The Problem is that these IDs are changing when you add or remove a Image from the Android App and in general they do not seem to be "fixed" or unique.
My questions are:
Is there a bullet proof way to reference an Image via Text/Numbers?
Do IDs change from phone to phone? (Is ID "213226123" the same Image on every App where the app is installed?)
I could send an Image identifier made by myself and then work with a switch statement to check which image its supposed to be but this makes easy things complicated and would be incredible bad design.
You can get any resource (including images) id by name with getIdentifier method. Then you can get the resource using the id.
You can get the id of your image(s) dynamically calling the getIdentifier() method of the Resources, like this:
val id = context.resources.getIdentifier("my_image", "drawable", context.packageName)
1: For your request there is a solution but you'll have to do some mapping.
Say your API is returning images as a number: e.g.
{
...
"imageId": 243,
...
}
When setting the image, you map the imageId to the id of your drawable
imageView.setImageResource(findImageForId(myObject.imageId))
fun findImageForId(imageId: Int) = when(imageId){
1 -> return R.drawable.imageA
...
243 -> return R.drawable.imageXYZ
...
}
Id's of your drawables are generated at compile time so they won't change in between phones using the same APK. You can't be sure all your users have the same version (e.g. after an update) so you should never use your generated drawable id's to identify images
Does anyone know if it is possible to make Android not generate new ID's for resources that is added to raw, drawable and other resource-folders?
The problem is that if I for example add an image with the name 3.jpg, and later on adds another image called 2.jpg the ID for image 3.jpg gets changed.
I need to keep the ID's static as the ID's are defined in XML files and used in the app to get the resources based on the ID.
I may have done something wrong when I tested it so it may be that the ID does not get changed, but as far as I can remember ID got changed when adding new resources.
Thanks for any help.
As far as i know, R.java is autogenerated and all resource ID's are internally allocated by eclipse. Technically your code should not depend on the ID's generated. So even if ID's keep changing, it is absolutely fine. If you are depending on the generated ID's in your code, you will keep running into problems.
I have recently started developing a game in android, never used it before and was wondering if there is a simple way of getting a set of images loaded into the application. As my current implementation involves basically
Creating an int[] array,
Storing the values of each drawable into this array, (now this has to be hand coded, so if I add any more images it has to be added programmitically)
Then itterating through each item in the array and calling BitmapFactory to get the resource.
(Unfortunately I don't have the code with me as it is at home and I am at work, but that is the jist)
So 2 questions, is there a way of getting the drawables without having to put in each item manually to the int[] - ie looking for perhaps a file name prefix and then only loading the resource with the prefix?
Which leads me to my second question because I more than just these images in my drawable resource directory, is there a way to add extra organisation (folders) to manage the files better. As currently I have loads of images within the drawable file and how would I reference these sub folders/images.
You cannot have sub folders within the resources structure. Android depends on the folder layout to determine which resource to use in what condition (localization, different screen resolutions, etc).
I'm not sure why exactly you are trying to load up a whole bunch of images, but there are a couple of (slower) methods that allow you to look up a resource by string name. If you used a naming convention for your images you could look them up that way via [Resources.getIdentifier()][1]. However, in a game performance likely matters, so you are probably better off with a more manual approach using the int IDs directly since it is much more efficient.
[1]: http://developer.android.com/reference/android/content/res/Resources.html#getIdentifier(java.lang.String, java.lang.String, java.lang.String)
I am uploading a load of images as they will be shown to user for different items. Its not a system where responsiveness is critical so its okay in terms of what I want. Though...
public int getIdentifier (String name, String defType, String defPackage)
Since: API Level 1
Return a resource identifier for the given resource name. A fully qualified resource name is of the form "package:type/entry". The first two components (package and type) are optional if defType and defPackage, respectively, are specified here.
Note: use of this function is discouraged. It is much more efficient to retrieve resources by identifier than by name.
They suggest using the resource id but if I want to add a file later on then I have to re-compile the app to include the extra file, this is where it bugs me, as the pic gets associated to an item that I have in a string array. So I can add items to the array but not the images without a change of the code.
Surely there is a function to fix this?
Is there a way that i can see the resources from my app within my library?
I tried
Class res = Class.forName( extras.getString( R.string.getClass() ) ); <- apps' R class
final Field[] fields = res.getFields(); <- returns nothing
for(final Field field:fields){
....
}
Thanks
Update
The app could see the whole list by just getting R of the library, but now i cant get string value from the app
Is it possible that you really want to be using a raw resource, rather than the strings resource? If you want random access to strings, reading a file into memory would make things much easier.
The nature of the strings resource is more of a compile-time linking, not a database to search at run-time.