If I have different resource names like elephant, tiger and cat. And I want to create a method accepting the resource name and return the drawable object. Then I wrote this
public Drawable getDrawable(String name){
int defaultResId= ResourceOptimizer.getResId(name,R.drawable.class);
return getResources().getDrawable(defaultResId);
}
which the ResourceOptimizer is
public class ResourceOptimizer {
public static int getResId(String resName, Class<?> c) {
try {
Field idField = c.getDeclaredField(resName);
return idField.getInt(idField);
} catch (Exception e) {
e.printStackTrace();
return -1;
}
}
}
But the problem is that getResources() needs to be called
in an activity or fragment, otherwise you to pass the context.
Passing the context might cause memory leak. Especially, when
it has to be passed through several classes. I’m wondering if
there is some way to get the resource by a better convenient way.
like
R.id.DRAWABLE_NAME
which the ResourceOptimizer is
Resources already has a getIdentifier() method.
But the problem is that getResources() needs to be called in an activity or fragment, otherwise you to pass the context.
Correct. Resources are only available by means of a suitable Context. Note that "suitable" depends on circumstances; for UIs, you almost always want to use the Context from your activity or fragment. For example, you might want different drawables based on whether the device is in dark mode or not on Android 10+.
Passing the context might cause memory leak
Not with the code that you have here, as you are not saving the Context, or anything from it, in a field that might outlive the Context itself.
I’m wondering if there is some way to get the resource by a better convenient way. like R.id.DRAWABLE_NAME
getDrawable() is a method on Context. So, call getDrawable(R.drawable.elephant).
Your code is trying specifically to avoid using R.drawable, instead using the String name. So, this turns into:
getDrawable(getResources().getIdentifier(yourString, "drawable", getPackageName()))
where yourString is the string basename of your resource (e.g., "elephant").
Ideally, you would cache the value returned by getIdentifier(), if you expect to retrieve the same resource by this code many times within the life of your process. Reflection is not cheap.
Related
In my current application, I am implementing localization. I came across various ways to access the string (external string). Some methods are:
Accessing directly using R.string.hello
Using getResourse().getString(R.string.hello)
getString.
The Eclipse tool to externalize resources, which creates a message.property file and access the string from a snippet.
The main confusion is between 1 and 2. If I use "1" that is accessing directly, can I get resources based on locale?
TL;DR
It doesn't matter whether you use R.string.hello or getResources().getString(R.string.hello).
Both will point the same thing.
So, yes, for your localization, then it will point to the right stuff.
It's been taken care of.
Some trivial stuff:
R.string.hello is actually an integer.
And most methods, that are used by passing R.string.hello (or other resources) as its argument, basically have the function to translate to corresponding string of the number.
Let's take TextView as an example.
It has two methods for setText.
First:
public final void setText(CharSequence text)
Second:
public final void setText(int resid)
So, when you call using getResources().getString():
myTextView.setText(getResources().getString(R.string.hello);
Then the first method is called.
And when you call using R.string.hello directly, then the second method is called.
If you take a look closer to the source, the second method's content (calling using R.string.hello directly) is actually calling the first method.
https://github.com/android/platform_frameworks_base/blob/master/core/java/android/widget/TextView.java#L4133
Both are provided for our convenience, so that we can use either direct resource R.string.hello or using getResources().getString(R.string.hello).
Implementation of Context method getString():
/**
* Return a localized string from the application's package's
* default string table.
*
* #param resId Resource id for the string
*/
public final String getString(int resId) {
return getResources().getString(resId);
}
So it's the same as using getResourse().getString(R.string.hello) (2), and it returns the result in the proper locale.
I have several classes in my application that uses the Context object to access SharedPreferences and serialize files. Simply put, I want to know how to "design away" the Context.
The background to why I want to do this is because:
The classes should be created in the onCreate() method of a Fragment (and the Context is not decided at this point)
It's just plain ugly to pass around the Context all the time. Especially since I use Singleton-reminding instantiation of these classes (Don't judge, please)
The specific context isn't really needed here, so it should be possible to design away... (What I mean is that I only need the Application Context)
An example of why this is ugly is my Cache object. It holds cached values downloaded from 1-5 different sources decided at runtime.
public static Cache getInstance(Context context) {
if(instance == null) {
instance = new Cache(context);
}
return instance;
}
When later using this object, it needs to read a SharedPreference which needs the Context, so it has to be passed around every single time I want to get an instance of the Cache.
So how can I get rid of these ridiculous contexts? Using the Application Context should be just fine... I guess that the problem can be boiled down to something like "How do I get a SharedPreferences object" in an object without a specific Context?"
I guess that the problem can be boiled down to something like "How do
I get a SharedPreferences object" in an object without a specific
Context?"
Using the Application Context. For this purpose you can subclass Application, registering it in your AndroidManifest file, and have a method to retrieve it from every where, like a singleton
I have seen the static getContext() method on the Application object before and I think it's slightly ugly and I wasn't sure that it was "Risk free" and correct. I was just about to implement it when I found this: https://androidcookbook.com/Recipe.seam?recipeId=1218 which basically says that the Application object in Android can be treated as a Singleton and that I should place my own Singletons inside that object.
It's essentially the same as #Blackbelt 's solution, but gives a slightly nicer vibe!
Going through some supposedly "good" sources sources to learn the details and tricks of context handling in Android I have come across one pattern multiple time that I fail to understand.
What is the advantage of using a ContextWrapper when you could equally well use the implicit context?
For example why use the following in an activity method (defined directly in an Activity class)
...
ContextWrapper cw = new ContextWrapper(getApplicationContext())
File filesDir = cw.getFilesDir();
...
Instead of just
...
File filesDir = getFilesDir();
...
even though getFilesDir() is defined in the ContextWrapper class the Activity is anyway a subclass of ContextWrapper so you have direct access to the method anyway.
So what potential issue (that I fail to see) does this added complexity address?
I'd say (and I might be wrong) that in the scenario (and context) you presented might not make a difference. getApplicationContext().getFilesDir() could have been used just as easily.
However, I believe ContextWrapper might be useful in other scenarios. From what I understand, this is the adapter pattern. You may want to provide different behaviour only for certain methods while proxying all other to the original context reference you pass in.
Check out this piece of code from RemoteViews:
// RemoteViews may be built by an application installed in another
// user. So build a context that loads resources from that user but
// still returns the current users userId so settings like data / time formats
// are loaded without requiring cross user persmissions.
final Context contextForResources = getContextForResources(context);
Context inflationContext = new ContextWrapper(context) {
#Override
public Resources getResources() {
return contextForResources.getResources();
}
#Override
public Resources.Theme getTheme() {
return contextForResources.getTheme();
}
};
I am wondering about the getString().
I can see that doing getString(R.string.some_text) works. Also getResources().getString(R.string.connection_error) works.
So my question is why should we use the getString or when?
Thanks!
The question is easy to misinterpret.
If you are in a valid context (like an Activity), there is no difference, because the context has a reference to the resources, so it can resolve a getString(int); directly, which returns a String.
Adding more information for your peace of mind.
If you can use getString directly, go ahead and do it. Now sometimes you might need to use getResources() because it contains a lot of helper methods.
This is the Android source code for getResources.getString():
/**
* Return the string value associated with a particular resource ID. It
* will be stripped of any styled text information.
* {#more}
*
* #param id The desired resource identifier, as generated by the aapt
* tool. This integer encodes the package, type, and resource
* entry. The value 0 is an invalid identifier.
*
* #throws NotFoundException Throws NotFoundException if the given ID does not exist.
*
* #return String The string data associated with the resource,
* stripped of styled text information.
*/
public String getString(int id) throws NotFoundException {
CharSequence res = getText(id);
if (res != null) {
return res.toString();
}
throw new NotFoundException("String resource ID #0x"
+ Integer.toHexString(id));
}
Neat huh? :)
The truth is that the Resources object does a lot more than just "get strings", you can take a look here.
Now compare with the Activity version of getString():
Return a localized string from the application's package's default
string table.
So in summary, other than the fact that the Resources object will be stripped of any styled text information. and that the Resources object can do a lot more, the end result is the same. The Activity version is a convenient shortcut :)
The methods are same. Logically, there's not a difference. you can assume, it does exactly:
public final String getString(int resId) {
return getResources().getString(resId);
}
The only difference I know is that getResources() may be required to fetch other apps resources as object. getString() will access your own resources.
If you use it for TextView there are two methods setText() in it. One takes (CharSequence string) and another takes (int resId). That's why your both variants work.
Generally I would recommend to define all strings in strings.xml files and get them via getResources().getString(int resId) in the code. Having that approach you'll be able to easily localize your app. You can read more about app resources here
Very Basic difference.
R.string.some_text = return ID integer, identifying string resource in your space
getResources().getString(R.string.connection_error) = Will return you actualy string associated with ID `R.string.connection_error`
They both can be made use in Android system, where many of widgets can take directly id or value of a resource. Practically there is no difference in value returned only difference is is the Term Context, from you activity context is available to you hence calling getString directly routes to resources for this context, while from classes where context is not available say from a Adapter, you will need to first access the Context, then the resource associated with the context and at the end the String so you write getContext().getResources().getString(R.string.connection_error)
I hope it clears your confusion.
One good reason is about formating & styling like :(http://developer.android.com/guide/topics/resources/string-resource.html#FormattingAndStyling)
What is the difference between getResources().getString(...) and getString() when called from my activity? I read that getText(...) returns stylized text, but when should I use getResources() as opposed to directly calling getString()?
They are the same nothing special about them if you fetch the Android source code and specially the Context Class for exemple
public final String getString(int resId) {
return getResources().getString(resId);
}
getString() is a convenient way since it is used regularly (you don't need to type getResources()…). Other than that, they're same.