29

I came across code at

HelloGallery Example

ImageAdapter.java - http://developer.android.com/resources/tutorials/views/hello-gallery.html

TypedArray a = obtainStyledAttributes(R.styleable.HelloGallery);
mGalleryItemBackground = a.getResourceId(
        R.styleable.HelloGallery_android_galleryItemBackground, 0);
a.recycle();

attrs.xml - http://developer.android.com/resources/tutorials/views/hello-gallery.html

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="HelloGallery">
        <attr name="android:galleryItemBackground" />
    </declare-styleable>
</resources>

and also code at :

Snake Game Example

TileView.java - http://developer.android.com/resources/samples/Snake/src/com/example/android/snake/TileView.html

TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TileView);
mTileSize = a.getInt(R.styleable.TileView_tileSize, 12);
a.recycle();

attrs.html - http://developer.android.com/resources/samples/Snake/res/values/attrs.html

<resources>
  <declare-styleable name="TileView">
    <attr name="tileSize" format="integer" />
  </declare-styleable>
</resources>

  1. May I know why they need to get the integer value from XML? Why don't they just code mGalleryItemBackground = 0; and mTileSize = 12;? My guess is that, they want to able to change something without touching Java code. But, I do not see any value being specified explicitly in the XML file itself. A code example to demonstrate the purpose of TypedArray and context.obtainStyledAttributes is very much appreicated.
  2. Both are trying to read an integer. Why one of the example is using getResourceId technique, another is using getInt technique?
  3. I refer to TypedArray JavaDoc, but I can hardly understand what recycle does?

Give back a previously retrieved StyledAttributes, for later re-use.

2 Answers 2

27
+100
  1. May I know why they need to get the integer value from XML? Why don't they just code mGalleryItemBackground = 0; and mTileSize = 12;?

I think it's mainly to demonstrate the technique of reading XML attributes from the View constructor, rather than to meet an absolute requirement. If you wanted to re-use your custom view elsewhere (not terribly likely for something as specific as Snake I'll admit) then this is a fantastically useful thing to be able to do... to change the backgound colour etc without having to touch the Java code.

For the tile size in particular, that might be useful to read from XML in case there are different layouts for different device types... you might want different size tiles for different density+size combinations.

  1. Both are trying to read an integer. Why one of the example is using getResourceId technique, another is using getInt technique?

Because the gallery background isn't an integer... it's expected to be a resource identifier (such as @drawable/foo). Yes it is still an integer, but an integer whose value isn't known until runtime. The tile size, by contrast, is a constant value and doesn't require any kind of runtime resolving.

  1. I refer to TypedArray JavaDoc, but I can hardly understand what recycle does?

If in doubt, look at the source. It's basically an optimization to avoid the LayoutInflater having to allocate one of these for every view it inflates.

Sign up to request clarification or add additional context in comments.

7 Comments

I still don't get it. I don't see any exact value (like 0 and 12) being specified explicitly into XML file itself. developer.android.com/resources/samples/Snake/res/values/…, how is it possible that I can change something without touching the Java code.
Hi @Yan, the link in your above comment merely declares that an attribute named tileSize can exist, and is of integer type. The actual declaration (or 'use' or 'instance') of an attribute named tileSize is in the layout XML (the files that are used at runtime to create UI). It's all XML but they have very different purposes.
Hi @Reuben, Nope. I didn't see tileSize in developer.android.com/resources/samples/Snake/res/layout/… (the files that are used at runtime to create UI). Also, can you justify, how can you change tileSize without touching the Java code, as there is no value being specified into developer.android.com/resources/samples/Snake/res/values/…
declare-styleable merely declares that the attribute can be used in layout, on a particular view type (in this case, that's "SnakeView"). If you didn't have that declare-styleable somewhere in the resources folder, the resource compiler would throw an "Unknown attribute" type error when it found tileSize="24".
Reuben is correct: 1) The Java code gets the values of any XML attributes set in the Layout file. 2) It is the attrs.xml file that defines what possible attributes each view can have -- you cannot just make up attributes as you go a long, you have to specify them first
|
12

About styleable attributes

In addition to being able to change that value without touching Java code, it allows them to apply different styles to their app depending on device configuration. Instead of declaring in XML:

<com.example.android.snake.SnakeView
    android:id="@+id/snake"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tileSize="24" />

they can declare these values in res/values/styles.xml:

<style name="Control.SnakeViewStyle">
    <item name="android:layout_width">match_parent</item>
    <item name="android:layout_height">match_parent</item>
    <item name="tileSize">24</item>
</style>

and then refer to that style:

<com.example.android.snake.SnakeView
    android:id="@+id/snake"
    style="@styles/SnakeViewStyle" />

After separating styles like this they can provide different styles.xml file for each device configuration. For example, there might be one res/values/styles.xml for portrait mode and one res/values-land/styles.xml for landscape mode.

About resources and integers

If a styleable attribute is declared as "reference" instead of "integer", you would (1) get IDE content assist when writing XML for that attribute and (2) compiler would check that you haven't provided a reference to non-existing resource. Consequently, to get it you need to use getResourceId, because it may do some additional resolving to get actual resource id.

About recycle

I'm not really sure, but judging by the code of TypedArray, it seems that there's some caching mechanism inside it, and recycle() makes it work.

3 Comments

I still cannot get it. The XML example res/values/styles.xml given by you, is completely different from developer.android.com/resources/samples/Snake/res/values/…. There are not "12" value being specified exactly into that file.
If I am using your styles.xml, how am I suppose to initialize mTileSize? I can no longer using a.getInt(R.styleable.TileView_tileSize, 12);
Yan Cheng, this file: developer.android.com/resources/samples/Snake/res/values/… - is not styles.xml, but attrs.xml. It defines what attributes a custom view class may have. In this particular case, a TileView may have an attribute tileSize of type integer. This means that we can set value for this attribute in layout XML file or in styles.xml fole.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.