Way to group resources - android

I'd like to group my drawables in some way that doesn't involve some crazy approach (for example reflection on the generated R class).
For example I have 10 types of some object in a game. I'd like to load them all into an array without actually copying:
enemy[0] = resources.getDrawable(R.drawable.enemy_image_0)
enemy[0].set....
enemy[1] = resources.getDrawable.....
Is there some way to group them and load in a loop? Any way to do that without getting into how R is generated and changing its structure?

Is there some way to group them and load in a loop?
Use getIdentifier() on the Resources object (which you typically get via getResources() on your activity or other Context).
Since this, under the covers, uses a "crazy approach" (specifically "reflection on the generated R class"), and since reflection is not especially speedy, please cache these values where possible.

Related

Why does the R class not contain the field type?

Whenever we want to inflate a view or get a resource we have to cast it in run-time. views, for example, are used like so:
In the past, we would have needed to cast it locally
(RelativeLayout) findViewById(R.id.my_relative_layout_view)
Now, we use generics
findViewById<RelativeLayout>(R.id.my_relative_layout_view)
my question is why doesn't the compiler(or whoever generates the R class) doesn't also keep some kind of a reference to the type of the element(doesn't matter if it's a string or an int or any other type) that way casting problems should not occur
We cannot really speculate on that, that would be a design choice.
It might be that they wanted to avoid bloating the APK. Every ID would need a full package name to the class. So would each ID in android.R too. Since R is packaged in every APK.
Solutions
However, if you are using Kotlin, you can even do away with the generics check. Kotlin will determine it automatically.
val view = findViewById(R.id.my_relative_layout_view)
view.method()
Or event simpler, if you use synthetics:
my_relative_layout_view.method()
Also, if you are using data bindings, you can just access it like this:
binding.my_relative_layout_view.method()

Is there a way to override getString() for resources the android framework inflates?

Is there any way to intercept the Android framework's inflation of xml resources (menus and layouts) to change the strings it uses (e.g. for attributes like android:text="#string/button_trade_commit".)
I know it's possible to override getString() as it's called from an Activity. But framework code doesn't seem to use getString(). For example, in MenuInflator.java, strings come from mContext.obtainStyledAttributes(), and obtainStyledAttributes() is final: I can't override it.
Anybody know of another way to accomplish this?
Background: I want to allow non-English-speaking users to localize my app themselves. I imagine an interface that displays the English strings and lets them enter a translation which is then used in place of the English string from then on. I can imagine also providing a "Share translations" button that uploads the translations, and then,
on the server side, incorporating them into a downloadable module that other users of the same language would get. Being able to substitute strings at runtime is the blocking piece that I can't figure out.
I don't believe you can override the systems getString() methods the way you are looking at it.
It might be worth trying to use a custom attribute and handle the work there: http://developer.android.com/training/custom-views/create-view.html#customattr
I don't think you will be able to modify the process Android uses when inflating resources the way you wanted to.
What you can do is to simply not provide any strings (android:text, etc.) in XML files. You can always obtain a reference to any element in your XML file in the code. Once you have a reference, you can provide texts in the code, taking properly localized strings from your custom framework.
I am not sure about this, but i think you can examine the source of Calligraphy library for Android. It is overriding system LayoutInflater to change the FontType, so i imagine you can do the same to change the strings.

what R.java file actually does and how

I have been working on a simple android tutorial and while browsing through the project folders I found this R.java file in gen folder...
When I opened it seemed to me as a mess...
first R itself is a class.
it had multiple Inner classes defined within eg drawable,id,layout,etc.
and that inner classes had lots of variables declared as below which were assigned with hex values
public static final int addr=0x7f080003;
...
...
and much more
R is auto generated and acts as some pointer for other files
Questions for R.java
what it is basically for
how it works
why
values are in hex
what role did it performs while the actual application is running
"Acts as some pointer to other files" is actually absolutely correct, now the question is which files it points to how it is done.
What does it contain?
R file contains IDs for all the resources in the res folder of your project and also some additional IDs that you define on your own (in the layouts, for example). The IDs are needed for the Android resource management system to retrieve the files from the APK. Each ID is basically a number which corresponds to some resource in the resource management system.
The file itself is needed so you can access or reference the resource from code by giving the ID of the resource to the resource manager. Say, if you want to set the view in the activity, you call
setContentView(R.layout.main);
main in the R file contains the number which is understood by the Android resource management system as the layout file which is called main.
Why is it better than just plain file names?
It's harder to make a mistake with the generated fields. If you write the field name incorrectly, your program won't compile and you will know that there's an error immediately. If you write an incorrect string, however, the application won't fail until it is launched.
If you want to read more on this topic, you should check the Android documentation, especially the Accessing Resources part.
This holds your resource ids. So when you do something like
TextView tv = (TextView) findViewById(R.id.mytextview);
it looks up your id here for that View, layout, etc... This way the app has an easy way to look up your ids while you can use easy to remember names. Anytime you create a resource it automatically creates an id for it and stores it here. That's why you never want to try and edit this file yourself.
One way to think about how valuable R.java is, imagine a world without it. Its amazing how android brings the xml and java world together to help avoid coding the UI manually completely. With legacy java building UI using the java language was a pain. Invaluable.
With Android you can not only build your UI using only xml, but also see it while you build it. Invaluable.
Every element in the xml can be referenced in the java code WITHOUT writing a single line of code to parse the xml :). Just R.id.nameOfElement. Invaluable.
Rapid development is beautifully done in android. Imagine if iPhone would have 5000 screens to fit that one piece of code, they would crumble on their XCode. Google has done a wonderful job with just R.java. Invaluable.

Android: Is it possible to alias R from app and lib to distinguish between the two?

Can I somehow alias a generated R file from a library and a generated R file from an application?
IE: I have two projects, one being a library. I reference the library in the application.
The library creates one R file, the application creates two: com.example.mapplication.R and the R from the referenced library, com.example.mlibrary.R. However, since I want to use both frequently in the application, I want to alias both the R classes. For example, call the library R something like libR and the app R something like appR.
I tried a couple of things which are of such stupidity, I won't even fully mention them, but I did some things like private com.example.mapplication.R appR = com.example.mapplication.R (immediately realising this wasn't gonna work), and private Class<com.example.mapplication.R> appRclass = com.example.mapplication.R.class;, but that didn't give me the desired effect. I do, however, use the latter method and some reflection to make it possible to be able to get the field and inner classes like this:
Class<com.example.mapplication.R> appRclass = com.example.mapplication.R.class;
int activity_main_layoutid = Toolkit.getFromClass(appR).
getMeTheInnerClass("layout").getMeAField("activity_main");
I haven't fully implemented the Toolkit method, but as we all know refletion can do this kind of stuff, but at the end of the day it's just as much work as just typing com.example.mapplication.R or com.example.mlibrary.R everywhere.
So to wrap thing up: Is it possible to alias multiple R's so that I can use appR and libR to distinguish the two?
I wish we could, but according to what I know, it isn't possible, at least not yet.
I also wish we could put resources in sub folders, but even this is impossible.
What you can do is setting a unique prefix (rename each resource file) for each library, as it's done by some third party libraries (like actionBarSherlock, which uses "abs" as the prefix).
Alternatively, you can have a special trick and put the files in the src folder and reach them from there, but that's more of a workaround, since the R won't have a reference to any of the resources there.
For example, you can put an image called image.png into the src/com/company/app_name, and then create a bitmap from it using:
final InputStream fis = getClass().getResourceAsStream("/com/company/app_name/image.png");
final Bitmap bitmap = BitmapFactory.decodeStream(fis);
By the way, if you've thought of using the assets folder, you can't do it for library projects, since it requires you to have the files in the project that uses the library project. It will work, but it misses the encapsulation idea...

Batch getting many bitmap resources on Android

I have a long series of graphics -- icon1_0.png, icon1_1.png, icon1_2.png..., icon12_0.png, icon12_1.png, icon12_2.png -- and I'd like to package them with my android application. Ideally I think I should be able to load them as resources but the resource id's are set up as java identifiers. Of course, java identifiers can't be assembled at runtime. I have to ask for R.drawable.icon12_00 so I cannot set up a loop
for(int icon=0;icon<12;icon++)
for(int frame=0;frame<3;frame++)
//syntax error obviously
BitmapFactory.decodeResource(getResources(), R.drawable."icon" + icon + "_" + frame + ".png");
So is there any way to get resources by their names? Better yet, is there a canonical way outside the resource system to pack data files into an android application package so that I can get at them?
I'm thinking about reflection but that doesn't seem like the right solution to me.
Use getResources().getIdentifier() from your Context (e.g., Activity), but please cache the result if you will use it more than once. getIdentifier() is implemented on Resources.
I know you've found an answer already, but if you use reflection then you will see a good speed increase, as getIdentifier() is slower. I wrote about how to do the reflection method here. However, this only works if you're accessing your own resources.
Reflection is also very slow, you should just create an array with all of your identifies in it.

Categories

Resources