I have trouble finding a pattern to create constants that point to a collection of resource values.
Let's say I have four TextViews, in each corner of the layout. I then have four different sets of constant content to randomly assign to these four TextViews. That content comes with a text and a background color for the TextView. Those values are defined in the strings.xml and colors.xml. Let's say the strings.xml looks like this:
<resources>
<string name="A">Text for A</string>
<string name="B">Text for B</string>
<string name="C">Text for C</string>
<string name="D">Text for D</string>
</resources>
and my colors.xml like this:
<resources>
<color name="A">#AAAAAA</color>
<color name="B">#BBBBBB</color>
<color name="C">#CCCCCC</color>
<color name="D">#DDDDDD</color>
</resources>
In the Activity class I then want to write a method to assign these values randomly to the TextViews. I could do this by creating lists for each type of value, then picking a random TextView out of these four, remove the first value out of each list and assign it to the TextView:
List<Integer> colors = Arrays.asList(R.color.A,
R.color.B,
R.color.C,
R.color.D);
List<String> strings = Arrays.asList(R.string.A,
R.string.B,
R.string.C,
R.string.D);
for (int i = 4; i > 0; i--) {
int randomNumber = // get a random number between 0 and i
TextView tv = // get text view based on i (by switch case)
tv.setText(string.remove(0));
tv.setBackgroundColor(getResources().getColor(colors.remove(0));
}
This solution doesn't seem good to me because the relationship between the string and the color values is not obvious at first sight. Also it is a lot of code to write.
I then thought of an enum, where each enum-value has a reference to its associated resources.
enum TextViewContent {
A(R.string.A, R.color.A),
B(R.string.B, R.color.B),
C(R.string.C, R.color.C),
D(R.string.D, R.color.D);
public final String string;
public final int color;
private TextViewContent(String string, int color) {
this.string = string;
this.color = color;
}
}
This solution looked fine to me until I saw this page https://android.jlelse.eu/android-performance-avoid-using-enum-on-android-326be0794dc3 where they recommend to avoid using enums in android code. In the examples of that page the enums to avoid were all replacable by a set of constants of a primitive type. I am not sure if using an enum is still a good idea. On the other hand I am running out of ideas how to solve this problem.
Is the use of an enum the best solution in this case? If not: What is the best solution here?
Prepare your resources in such a way that can be used as arrays:
<string-array name="texts">
<item>Text for A</item>
<item>Text for B</item>
<item>Text for C</item>
<item>Text for D</item>
</string-array>
<color name="A">#AAAAAA</color>
<color name="B">#BBBBBB</color>
<color name="C">#CCCCCC</color>
<color name="D">#DDDDDD</color>
<integer-array name="colors">
<item>#color/A</item>
<item>#color/B</item>
<item>#color/C</item>
<item>#color/D</item>
</integer-array>
Then all you have to do to retrieve them is:
String[] strings = getResources().getStringArray(R.array.texts);
int[] colors = getResources().getIntArray(R.array.colors);
It is not a lot of coding.
It also is easy to maintain because if you want to change the texts or colors, or to add new items, or delete items you only have to work in the resources.
As for the relationship between the string and the color values it's more than obvious.
Related
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]
Basically what I'm trying to achieve is to access from code two related resources.
Consider this example, the best solution I can think of to my problem:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="black">⬛</string><color name="black_c">#000000</color>
<string name="white">⬜</string><color name="white_c">#ffffff</color>
</resources>
Given a string N in my code I can access both the second string associated to it (⬛ or ⬜) or the color by adding "_c" to the end of the N string.
So, if N="black" I can use N to retrieve both ⬛ and #000000 (with N + "_c")
Is there a better way to do this? My solution feels a bit hacky. Hope I managed to explain what I'm trying to achieve, thanks!
I have another proposal. I hope it will help you.
If you have a colors.xml and a strings.xml (within the values directory)
<!-- colors.xml -->
<resources>
<color name="black">#000000</color >
</resources>
<!-- strings.xml -->
<resources>
<string name="black">Some black string</string>
</resources>
Using the same name you can access both of them if you are able to get the different id (ie R.string.black or R.color.black). The getIdentifier()` method can do it. So you can try (not tested)
String name = "black;
String choice = "color"; //or "string" dependending on if you want the color or the string
int resID = getResources().getIdentifier(name, choice, getPackageName());
Resources resources = getResources();
//Then access using
//If choice=="color"
int color = resources.getColor(resId);
//If choice=="string"
String text = resources.getString(resId);
Ya it sounds a bit hacky. You could use styles to group all your resources (as attributes to that style) and then read those styles. More info here: How to retrieve style attributes programmatically from styles.xml
But this again sounds hacky. What's your actual requirement? The way you suggested sounds OK. You can go ahead with that implementation since from a performance standpoint, it doesn't take any extra over head. Just make sure you write a neat API to fetch data from your xml.
I want a drawable id array of integer values which I can store like an integer-array in res/values/XXX.xml by using integer-array tag. Below is integer-array declared in strings.xml
<integer-array name="icons">
<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
</integer-array>
But I want to store drawable image ids like #drawable/someImage as an integer array in xml.
OR Is there any alternatives to store drawable integer ids as an integer array in xml.
I think TypedArray is what you are looking for. I have samples using it. If you are interested, take a look at codes below:
First, integer-array in res/values/arrays.xml:
<integer-array name="frag_home_ids">
<item>#drawable/frag_home_credit_return_money</item>
<item>#drawable/frag_home_transfer</item>
<item>#drawable/frag_home_balance</item>
<item>#drawable/frag_home_charge</item>
<item>#drawable/frag_home_finance_cdd</item>
<item>#drawable/frag_home_finance_ybjr</item>
<item>#drawable/frag_home_more</item>
</integer-array>
Second, get resource integer values programmatically:
TypedArray tArray = getResources().obtainTypedArray(
R.array.frag_home_ids);
int count = tArray.length();
int[] ids = new int[count];
for (int i = 0; i < ids.length; i++) {
ids[i] = tArray.getResourceId(i, 0);
}
//Recycles the TypedArray, to be re-used by a later caller.
//After calling this function you must not ever touch the typed array again.
tArray.recycle();
Third, call the integer values like this:
holder.iv.setImageResource(ids[position]);
Of course, you can get integer values of string, color, integer, layout, menu...in this way.
I hope these codes will inspire you.
Take a look at documentation, specifically More Resource Types article. Quote:
Typed Array
A TypedArray defined in XML. You can use this to create an array of other resources, such as drawables.
EXAMPLE:
XML file saved at res/values/arrays.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<array name="icons">
<item>#drawable/home</item>
<item>#drawable/settings</item>
<item>#drawable/logout</item>
</array>
<array name="colors">
<item>#FFFF0000</item>
<item>#FF00FF00</item>
<item>#FF0000FF</item>
</array>
</resources>
You can use a string array.
Extract:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="media_names">
<item>Big Buck Bunny</item>
<item>Elephants Dream</item>
<item>Sintel</item>
<item>Tears of Steel</item>
</string-array>
<string-array name="media_uris">
<item>http://archive.org/download/BigBuckBunny_328/BigBuckBunny_512kb.mp4</item>
<item>http://archive.org/download/ElephantsDream_277/elephant_dreams_640_512kb.mp4</item>
<item>http://archive.org/download/Sintel/sintel-2048-stereo_512kb.mp4</item>
<item>http://archive.org/download/Tears-of-Steel/tears_of_steel_720p.mp4</item>
</string-array>
</resources>
What is it that you want to achieve, I cannot 100% tell you if this is the best choice for you.
I have the following problem:
I created a Char Sequence and was able to name 4 units. I would however rather use strings from my XML file for localization purposes. Is there any way to achieve that?
final CharSequence[] choices =
//want to add strings here i.e. R.strings.lemonade
{"Coke", "Pepsi" , "Sprite" , "Seven Up" };
builderType.setSingleChoiceItems( choices, selected, new OnClickListener()
{.......
Error message:
Type mismatch: cannot convert from int to CharSequence
There's another overload of AlertDialog.Builder.setSingleChoiceItems() that takes in an int resource id for a string array of items. Put the following in an xml in res/values e.g. strings.xml:
<string-array name="choices">
<item>Coke</item>
<item>Pepsi</item>
<item>Sprite</item>
<item>Seven Up</item>
</string-array>
Then you can use it as:
builderType.setSingleChoiceItems(R.array.choices, selected, new OnClickListener(), ...
For generic cases, you can also load string array resources with Resources.getStringArray() as suggested by #Egor.
Create a string-array in strings.xml
<string-array name="choices">
<item>Coke</item>
<item>Pepsi</item>
<item>Sprite</item>
<item>Seven Up</item>
</string-array>
Then fetch it from resources
String[] choices = context.getResources().getStringArray(R.array.choices);
Then use it in setSingleChoiceItems() as is, since String implements CharSequence.
In my android list page/activity I have a 2 text fields a main and subsection one above each other, but when it coems to creating the array string for it I only see examples with the one section of text.
<resources>
<string name="hello">Hello!</string>
</resources>
To then create what I want I would do a if statement to match the title then if so add the subtitle, but I would like to have it so I can read my title and subtitle strings something like below:
<resources>
<string name="hello">
<item>Hello!</item>
<item>my subtitle </item>
</string>
<string name="hello">
<item>Hello!</item>
<item>my subtitle </item>
</string>
</resources>
But I cannot find an example of how to read this to a list item etc, so I do not need to do a long if statement within my java to match the subtitle to the title.
Many Thanks
Si
I usually delimit the text with a pipe | and split it when displaying. Its a bit ugly, but it works.
<item>item1|item2</item>
then when I call it in getView(...)
String[] r = c.getResources().getStringArray(R.array.arraylist).split("\\|");
then I have defines for the index:
private final int VIEW_HEADING_TITLE = 0;
private final int VIEW_HEADING_SUB = 1;