Difference in retrieving String and String Array resources? - android

I'm new to Android and trying to understand the code I wrote from a tutorial. Meanwhile, I'm referencing the documentation whenever I want to really understand something.
The documentation in question
That page discusses string resources.
For a string, under the String section it states I could retrieve a string defined in an XML file like this: String string = getString(R.string.hello);.
XML in question:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">Hello!</string>
</resources>
Now, for a string array, under the String Array section it states I could retrieve a string string array defined in an XML file like this::
Resources res = getResources();
String[] planets = res.getStringArray(R.array.planets_array);
XML in question:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="planets_array">
<item>Mercury</item>
<item>Venus</item>
<item>Earth</item>
<item>Mars</item>
</string-array>
</resources>
How come I have to do Resources res = getResources(); for a String Array, and not for a String in an XML file?
Would String[] planets = getStringArray(R.array.planets_arry); not work? Do resources have more methods, namely for more complex cases like String Arrays? is getString so simple it is fine to not need it under a resource? Where could I find a list separating what requires me to do Resources res = getResources(); versus what doesn't require that?
Lastly, does getResources get me every single resource in my Android project irregardless of what XML file it may be in?

How come I have to do Resources res = getResources(); for a String
Array, and not for a String in an XML file?
getString() is a method of your Context object (mostly an Activity but could also be a Service). The code for that method is:
public final String getString(int resId) {
return getResources().getString(resId);
}
Meaning getString() is just a convenience method that the Context class offers. In the end both calls do the same, namely retrieve a resource through the Resource object.
Would String[] planets = getStringArray(R.array.planets_array); not
work?
No because Context doesn't have a convenience method to retrieve String[].
Do resources have more methods, namely for more complex cases like
String Arrays?
Yes. See http://developer.android.com/reference/android/content/res/Resources.html.
I leave if up to you to decide whether they are more complex than getStringArray.
is getString so simple it is fine to not need it under a resource?
Resource does have a getString(int) method: http://developer.android.com/reference/android/content/res/Resources.html#getString(int)
Where could I find a list separating what requires me to do Resources
res = getResources(); versus what doesn't require that?
There's no such list. The JavaDoc for Context will tell you what convenience method you got:
http://developer.android.com/reference/android/content/Context.html
Lastly, does getResources get me every single resource in my Android
project regardless of what XML file it may be in?
Only if it's in a resource xml file. Layouts or Drawables can't contain String resources.

The call getString() is essentially the same thing as getResources().getStringArray(), as mentioned here the method getString() is just a convenience method, because it's used so often.
public final String getString(int resId) {
return getResources().getString(resId);
}
I'll also add that you can't use getStringArray in other resource files, like XML layouts, where getString() can be.

Related

In Kotlin for Android, I need a look-up table from which, at run time, a number is selected. How can I get this table from resources? [duplicate]

Just a quickie,
i have an xml resource in res/values/integers.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<integer-array name="UserBases">
<item>2</item>
<item>8</item>
<item>10</item>
<item>16</item>
</integer-array>
</resources>
and ive tried several things to access it:
int[] bases = R.array.UserBases;
this just returns and int reference to UserBases not the array itself
int[] bases = Resources.getSystem().getIntArray(R.array.UserBases);
and this throws an exception back at me telling me the int reference R.array.UserBases points to nothing
what is the best way to access this array, push it into a nice base-type int[] and then possibly push any modifications back into the xml resource.
I've checked the android documentation but I haven't found anything terribly fruitful.
You need to use Resources to get the int array; however you're using the system resources, which only includes the standard Android resources (e.g., those accessible via android.R.array.*). To get your own resources, you need to access the Resources via one of your Contexts.
For example, all Activities are Contexts, so in an Activity you can do this:
Resources r = getResources();
int[] bases = r.getIntArray(R.array.UserBases);
This is why it's often useful to pass around Context; you'll need it to get a hold of your application's Resources.
get an Array from array.xml in resources of android project can be accessed.
from array.xml
<string-array name="weather_values">
<item>sunny</item>
<item>cloudy</item>
<item>rainy</item>
</string-array>
in Activity
String[] stringsArray = getApplicationContext().getResources().getStringArray(R.array.weather_values);
in Fragment
String[] stringsArray = getContext().getResources().getStringArray(R.array.weather_values);
for output in log
System.out.println("Array Values " + Arrays.toString(stringsArray));
output is
I/System.out: Array Values [sunny, cloudy, rainy]

How do you use an integer from the resource file within a string in the same resource file?

Is it possible to use an integer:
<integer name="minstringlength">7</integer>
within the same resource file but within a string:
<string name="nametooshort">Please enter a name longer than #integer/minstringlength characters</string>
I presume you want to use different minimum limits based on device configuration. You can't use the #integer/minstringlength in the string content, so I think the best you can do is have a format argument and build the string yourself like this:
<integer name="minstringlength">7</integer>
<string name="nametooshort">Please enter a name longer than %1$d characters</string>
int nameMinLength = getResources.getInt(R.integer.minstringlength, 0);
String nametooshort = getString(R.string.nametooshort, nameMinLength);
This assumes you are using an Activity/Fragment, otherwise you need a Context in order to use getResources() and getString().
It can not be done in resource file.
As xml contains static content and also from android string-resource doc there is no sub tag or nested tag of <string>
It task can done easily in java file
getResources().getString(R.string.minstringlength);
getResources().getInteger(R.integer.nametooshort);
OR
Follow this post
<string name="meatShootingMessage">You shot %1$d pounds of meat!</string>
int numPoundsMeat = 123;
String strMeatFormat = getResources().getString(R.string.meatShootingMessage);
String strMeatMsg = String.format(strMeatFormat, numPoundsMeat);

Best way to use a static array

In my little app, I have a long list of data. Before, I used an editor to let the user enter the data - but now I would like to put the data static in program code/string list value Folder.
What is the best way to achieve this?
If you already know the values inside array you can crate string array inside strings.xml file which is present under values.
example:
XML file saved at res/values/strings.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="sports_array">
<item>Football</item>
<item>Cricket</item>
<item>Hockey</item>
<item>Tennis</item>
</string-array>
</resources>
This application code retrieves a string array:
Resources res = getResources();
String[] sportlist = res.getStringArray(R.array.sports_array);
so now your sportlist will contain all the items specified in sports_array which is declared inside strings.xml
for more information pls see
http://developer.android.com/guide/topics/resources/string-resource.html

Android get list of string resources from special file

For example, i have my_string.xml file with strings:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="my_string">My string</string>
<string name="another_string">Another string</string>
{...}
</resources>
Is it possible to get this strings to list/hashmap programmatically? Yeh, i know that i can take it by name or something like this. But i need to get it dynamically programmatically, for example, to HashMap<String, String>
Or all string resources will merge together after building and it's not possible to separate it?
If you want to access all the Strings from the strings.xml file you could use reflection on the R.string class.
Field[] fields = R.strings.class.getFields();
String[] allStringsNames = new String[fields.length];
for (int i =0; i < fields.length; i++) {
allStringsNames[i] = fields[i].getName();
}
You can then store them in Hashmap or wherever you want
Put the file in the raw folder. Then you have to open the file
InputStream in = getResources().openRawResource(R.raw.yourfile);
and parse the content manually, for instance save the list as xml or json and parse it and build your desired HashMap or whatever you like. Keep in mind that this may be a blocking operation and should not run on the main UI thread, run it async, but it depends on the length of the file you try to parse, but in general you should run that in an async thread
---- Update
You could do something like this:
int stringRes[] = {R.string.my_string, R.string.another_string}
List<String> myStrings = new ArrayList<String>();
for (int id : stringRes){
String str = getResources().getString(id);
// TODO do some if check if you want to keep that string or whatever you want to ...
myStrings.add(str);
}
you could store them into a HashMap(but getResources().getString() acts already like a HashMap ) or List
The whole point of the XML file is to act as a "hashmap" kind of... you can always get a string by using context and the R.string reference. I'm assuming you are aware of this, so then you must be trying to create a simplified reference to this?
Creating a HashMap requires either static references (which are not available for XML) or a runtime creation of the list. You can create the list in the Application class, but I would caution against that. You may have trouble referencing the context but again, you can use the Application constructor to make sure you have a reference to context.
Beyond that, you should check into the StringArray resource. It does not allow you to reference a string using another string because it is an array. Here are the docs:
http://developer.android.com/guide/topics/resources/string-resource.html#StringArray
If it's super-important to use a HashMap then you should probably not use XML and should just create a static class. The XML resource files are primarily used for centralized data (to ease modifications to static strings) and, more so, multi-lingual purposes. Static HashMaps are not the proper use-case.

Load resources with variables?

I am loading XML file resource like this,
getResources().getXml(R.xml.fiel1);
Now, the scenario is that depending on factors there may be many xml files to choose from. How do I do that?
In this case the filename is similar in the fact that all starts with file only ends with different numbers like
file1, file2,file3 etc., So I can just form a String variable with the file name and add a suffix as per requirement to form a filename like file1 (file+1).
Problem is I keep getting various errors (NullPointerEx, ResourceId Not found etc) in whatever way I try to pass the filename variable to the method.
What is the correct way of accomplishing this?
You could use getIdentifier() but the docs mention:
use of this function is discouraged.
It is much more efficient to retrieve
resources by identifier than by name.
So it's better to use an array which references the xml files. You can declare it as an integer array resource. Eg, in res/values/arrays.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<integer-array name="xml_files">
<item>#xml/file1</item>
<item>#xml/file2</item>
etc...
</integer-array>
</resources>
And then in Java:
private XmlResourceParser getXmlByIndex(int index) {
Resources res = getResources();
return res.getXml(res.getIntArray(R.array.xml_files)[index - 1]);
}
Of course, you'll need to update the array whenever you add a new xml file.
You can use the getIdentifier method of Resources to find the id.
Resources res = getResources();
for(/* loop */) {
int id = res.getIdentifier("file" + i, "xml", "my.package.name");
res.getXml(id);
}
An alternative to the getIdentifier suggestions, assuming the number of resources is fixed at compile time, would be to create a static mapping between an identifier and the resource.
So for example you could use the suffixed numerical ID:
class Whatever {
static final int[] resources = new int[] {
R.xml.file1, R.xml.file2, R.xml.file3
}
}
This would allow you retrieve the resource with a simple index operation.
getResources().getXml(resources[i]);
Alternatively, if you needed a more descriptive mapping you can use any one of java's Map-based classes.
class Whatever {
static final Map<String, Integer> resources = new HashMap<String, Integer>();
static {
resources.put("file1", R.xml.file1);
resources.put("file2", R.xml.file2);
resources.put("file3", R.xml.file3);
resources.put("something_else", R.xml.something_else);
}
}
With this you would then get(String) the value by its name.

Categories

Resources