Android has a convenient XML-based resources architecture that allows you to define strings, booleans, colors, dimensions, ID’s, integers, integer arrays, and typed arrays. These XML files are stored and merged from `res/values` and look like this:
<resources> <string name="menu_settings">Settings</string> <string name="share">Share</string> <string name="favorite">Favorite</string> <string name="comment">Comment</string> </resources>
Now you can access these throughout your code base using `R.string.menu_settings` or `R.string.share`, etc. And as an added bonus, localizing is simple from here… but we aren’t here to talk about localization. We are here to talk about taking array of types once step further!
What the Hack?
Unfortunately, the array of types fall short in allowing you to store an array of complex types. You can simply store array of primitive types like this:
<resources> <array name="categories"> <item>Food</item> <item>Health</item> <item>Garden</item> </array> </resources>
Ok, although I sincerely do appreciate it, it falls short and many real-world scenarios. For example, what if I wanted to store the ID of the categories above? Now I’m pushed away from using an extremely simple, out-of-the-box solution, to a complex solution that uses XmlResourceParser on nested XML.
Here’s a clever alternative… you can store your complex objects as an array, then suffix the name with an incremental integer. Loop through them and create a list of strongly-typed objects from there if needed.
What?! Show Me the Code!!
Ok here’s what I mean… maintain your XML as so:
<resources> <array name="categories_0"> <item>1</item> <item>Food</item> </array> <array name="categories_1"> <item>2</item> <item>Health</item> </array> <array name="categories_2"> <item>3</item> <item>Garden</item> </array> <resources>
Now each category is an array with a key/value pair for it’s properties. What ties it with other categories is the integer suffix. Now we can use this dandy static method to grab them:
public class ResourceHelper { public static List<TypedArray> getMultiTypedArray(Context context, String key) { List<TypedArray> array = new ArrayList<>(); try { Class<R.array> res = R.array.class; Field field; int counter = 0; do { field = res.getField(key + "_" + counter); array.add(context.getResources().obtainTypedArray(field.getInt(null))); counter++; } while (field != null); } catch (Exception e) { e.printStackTrace(); } finally { return array; } } }
This is dynamically retrieving the resources programmatically, with an incremented counter to find the next object until there isn’t one left. Now this can be consumed throughout your code base like this:
for (TypedArray item : ResourceHelper.getMultiTypedArray(this, "categories")) { Category category = new Category(); category.ID = item.getInt(0, 0); category.title = item.getString(1); mCategories.add(category); }
I’m looping through the array of `TypedArray’s` and binding them to a class, and still maintaining the resources easily from the XML. Enjoy!
HAPPY CODING!!
References:
- Multidimensional resource arrays in Android
- Dynamically Retrieving Resources in Android
- Android: More Resource Types
Hey Basem
Thanks for this, I’m pretty much new to Android coding, and I’m trying to implement something similar to this in a project. I have an array which contains 5 properties each, I’m trying to put some of that Info into a ListView through an adapter. Anyway, my question is, on the for for TypedArray, what are you refering to with the 1 on this sentence: item.getString(1), and also, how would you recommend me to retrieve each item in the resourceHelper class so I can then pass each into an object?
Thanks
can u help me?
my case i get multidimension array from string
String hasilselectnn= “1.__ini tanggal1__ini jam1__ini status1__ini aktivitas1__ini catatan1__ini,koor1@2.__ini tanggal2__ini jam2__ini status2__ini aktivitas2__ini catatan2__ini koor1”;
// hasilselect= “{{1.,ini tanggal1,ini jam1,ini status1,ini aktivitas1,ini catatan1,ini koor1}{2.,ini tanggal2,ini jam2,ini status2,ini aktivitas2,ini catatan2,ini koor1}}”;
String[][] myString={hasilselectnn.split(“[__@]+”)};
System.out.println(“nilai = ” + Arrays.deepToString(myString));
System.out.println(“myString2 line1 =”+myString[0][0]);
System.out.println(“myString2 line1 =”+myString[0][1]);
System.out.println(“myString2 line1 =”+myString[0][2]);
System.out.println(“myString2 line1 =”+myString[0][3]);
System.out.println(“myString2 line1 =”+myString[0][4]);
System.out.println(“myString2 line1 =”+myString[0][5]);
System.out.println(“myString2 line1 =”+myString[0][6]);
System.out.println(“myString2 line2 =”+myString[1][0]); /////errro because this myString[0][7]
“Now this can be consumed throughout your code base like this:”
How?
this -> Wrong 1st argument type. Required ‘android.content.Context’.
Cannot resolve symbol ‘Category’
Within the same class or in another class?