I know now, that if I need to get a recource in some static function, I have to pass context or recources of the context there somehow - by parameter or through a static variable. But why is it neccessary? The id's of the resources are reachable in static surroundings, for example R.string.some_my_stuff. If I want a system resource, it is also visible there through Resources.getSystem().getString(android.string.some_common_stuff). But why can't I do something similar to get an application resource? The resource files are the usual static part of the sources. Resources are static and belong to application. The classes of application belong to it in the same way and I can access their static parts in a static way.
Why can't I use resources in all the application in same static way, which would be the most natural, but have to access them through instance instead?
I am afraid, I do not understand something very important.
Please, don't repeat that I can't do it. I know it, on my honour. Please, explain why, or show me the way... Only that will cure me from my sadness :-) Thank you.
The resource IDs are unique per application, they are not unique over all application (including the Android system). E.g. there may be two different string in different applications which have the same ID, say 42.
Therefore yon may access only one application statically (every programmer must agree which one that is, its the Android system (there no choice, its the only one always installed)). For all the other application you must be able to tell the system which application's resources you want to access. You do this using the context.
Related
I've read that one should not use TAGs like
private static final String TAG = ThisClassName.class.getSimpleName();
but rather
private static final String TAG = "MCLSN";
because ProGuard will create bugs and/or not obfuscate code correctly. Are these valid reasons?
References:
http://www.drewhannay.com/2016/02/android-logcat-tag-best-practices.html
https://blog.mindorks.com/applying-proguard-in-an-android-application
This can certainly be a problem. I'm working with code currently which uses getSimpleName() for TAGs and, as mentioned already, with proguard these can be obfuscated from say "FragmentA" to "a".
If these tags are used for identification, there can easily be bugs introduced in this way as there may be multiple names obfuscated to "a".
We have an extra problem in that these obfuscated TAGs are used in database ids and fields. So fixing this issue will break database behaviour for customers.
Bad stuff, best avoided early if possible.
Honestly, it's a matter of preference, but I prefer the simple String option.
The only benefit of using the getSimpleName() option is because it has support for refactoring. So it's only helpful if you're changing the class's name (which should rarely happen), or if you're copy/pasting a file to use as a template.
So if you're doing that often, I could see why you would prefer the first option. It just makes it easier to not have to manually change the TAG.
I also originally used getSimpleName() for TAGs until recently when I had experienced a minor issue.
When using MVVM architecture, there's really only one ViewModel per View, so I've created a ViewModelFactory that creates and returns the proper ViewModel for the View. Since it's meant to be unique, I decided to use the TAG as the identifier for the ViewModel I need.
Therefore, with a simple Switch-case statement on the TAG, I should be able to get the proper ViewModel. However, you simply can't use TAG as a case expression when you use getSimpleName(). I received the error: Constant Expression Required.
So if you only plan to use your TAG for certain situations like Logcat, you're fine with just using getSimpleName(). But if you plan to use them as a unique class identifier for a specific group of classes, then you'll need the pure String option.
Right now they are just stored on a class called Globals as static fields.
I'm not the one who made the app, but I am considering putting them in localized strings.xml files, such as <string name="API_URL">http://someurl</string>. Is this good or bad practice?
UPDATE:
I chose the answer that I feel answers the question most comprehensibly.
But after some re-thinking, I have chosen a different solution alltogether.
Given that URLs are actually based on the country which the app should be distributed for, it doesn't make sense to switch them based on locale, as the URLs should stay the same regardless of the language on the phone.
Instead, I have implemented Gradle Flavors, which create different APKs based on different settings and such. It allows you to create variations of the same app with the small changes that you need. :) So now I have the URLs in a flavor-specific file.
Thank you to everyone who took their time to comment and help me.
I agree with puneet, it's neither good nor bad. It depends on what you are doing with the API Urls.
Are you going to append them later with user input? If so I would suggest you keep them as global variables that way you can modify the API URL programatically as needed.
If the API Url are complete and will not need to be appended then putting them in the strings.xml would be fine. Just remember that you would still have to create a local String variable in the java to hold the text from the API_URL in the string.xml, which seems inefficient if what you're aiming for is to write less code.
Neither good nor bad.If your concern is the security then none of them provide the security as decompilation is possible.
I've written a networking library for my android app, and I want to be able to access a url value that I defined in my strings.xml file from that library. The problem is that the library isn't an Activity or Fragment or anything like that, and so it doesn't have access to the normal Context or other things that being a first-class Android citizen gets you. Is there any way for me to access the value without having a Context (or without having one passed in during function calls from Activities and Fragments)?
I know that I can access the R class easily, but all that gives me is byte offsets - I need the getString() method to turn that offset into something meaningful unless I want to do lots of fun romping in raw-bytes land (which I'd like to avoid).
Thanks!
No, there isn't, and manually parsing low level data is definitely not the solution here. The whole point of resources is to be retrieved according to the Context qualification (hence the powerful qualifiers system), and that's why I made that suggestion in the other question you just asked. :-)
Unless you provide a way (method parameter, for example), you won't be able to retrieve the resource. It comes to a point where you should rethink the architecture of your library: why do you need the URI to be qualified? If you're on a library, the client app will have its own Context, and can safely supply one to your library, thus retrieving the resource. If that's not the point (I.e., access the URI in code), then you shouldn't be using a resource, but a final static variable instead, like I suggested.
There are a few instances where you can benefit from the qualifiers capability when dealing with URIs, but, as I said, if you're using on your library only, you probably want a variable defined in code instead.
I have an android app that connects to a server at a static URL. I want to figure out where to put the url so that I can access it form my app.
The consensus seems to be that values/strings.xml is the way to go. However, I'm afraid that a single file for all of my static values could get unwieldy. Is there a way to use multiple different files for different types of strings (UI, internals, etc)? If I simply make different files, will android be smart about it and import them all? Is there an accepted canonical way of doing this?
Thanks!
Yes. You can provide many different XML files and name them the way you see fit. It's the resource qualifiers (the folder name) that matters.
Provide your string resource and you will be fine.
However, since your URI is static, I'd put them as a static final variable instead, in code. It will be easier to call it from places where supplying a Context may not be the best approach. And let's face it, there is probably no reason to make it a String resource and have to call it through the overhead of the resource system unless you need it in a XML layout, for example.
Facebook in their user guide suggest to keep a key in values/strings.xml file. Have never seen such an approach before and it sounds odd for me. Is it something everybody use? I always thought is it better to keep such a data in config files.
It is perfectly alright to keep data like this in strings.xml. Make sure you keep it in the default /res/values/strings.xml and not in any other values folder which has qualifiers attached to it. It may not be available on all devices if you do that.
Keeping this kind of data in config files is also perfectly acceptable (and the one I personally use, more because I find it easier to edit a Java file with static variables than an XML file in Eclipse).
Keeping the data in strings.xml means having an additional step in accessing it, as you'll need to get it from the resources using an instance of Context. Putting it as a static field in a Java class will make it slightly easier to access.
Both methods work fine, and are used commonly. It is really upto your personal preferences to pick one.