Basem Emara

Mobile Architect / iOS Jedi

  • About
  • Portfolio
  • Contact

Connect

  • GitHub
  • LinkedIn
  • Twitter

Multidimensional Typed Arrays in Android Resources

July 27, 2015 By Basem Emara 3 Comments

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:

XHTML
1
2
3
4
5
6
<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:

XHTML
1
2
3
4
5
6
7
<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:

XHTML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<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:

Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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:

Java
1
2
3
4
5
6
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

 

Filed Under: Mobile Tagged With: android, java

Subscribe and stay tuned!

The launch of this blog was inspired from uncovering the joys, pains, and realities of Swift mobile development. Many of the posts dissect open-source apps and other real-world projects. Thank you for coming along for the journey; I hope you find it as fun and exciting as I do!

Comments

  1. Sergio says

    February 9, 2017 at 1:38 pm

    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

    Reply
  2. mysecondname says

    April 25, 2017 at 12:35 am

    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]

    Reply
  3. Darren says

    March 5, 2019 at 9:19 am

    “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?

    Reply

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

My Life Philosophy

Simplicity is the key to elegance.

Post Series

  • Building a Scalable iOS App
  • Swift Utility Belt

Popular Posts

  • Creating Thread-Safe Arrays in Swift
  • Creating Cross-Platform Swift Frameworks for iOS, watchOS, and tvOS via Carthage and CocoaPods
  • Memory Leaks and Resource Management in Swift and iOS
  • So Swift, So Clean Architecture for iOS
  • Reading values from any plist file or bundle in Swift

Mobile App

Download the Basem Emara Blog app

Find It