Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get multiple style attributes with obtainStyledAttributes

I am trying to obtain several of the style attributes of the android namespace from my code. Here I enclose the relevant extract. AttributeSet attrs is the parameter that is passed in to any custom TextView.

private static final int[] ATTRS = new int[] { android.R.attr.textSize,
   android.R.attr.text, android.R.attr.textColor,
   android.R.attr.gravity };

private void processAndroidAttributes(final Context context,
   final AttributeSet attrs) {
   final TypedArray a = context.obtainStyledAttributes(attrs, ATTRS);
   try {

       final String text = a.getString(1);
       myTextView.setText(text);
       final float textSize = a.getDimensionPixelSize(0, DEFAULT_TEXT_SIZE);
       myTextView.setTextSize(textSize);
}

My issue is that I want to read 4 attributes, described in the int[] ATTRS. As you see I have put textSize as first element of this array. The reason for that is simple - if I swapped it for second place in the array its value is not read correctly (instead the provided default value is loaded). On the other hand the text loads correctly on whichever position in the array of ATTRS I place it. I do not dare experimenting with the position preferences of the gravity and the textColor, but with this permutation they do not work.

Can somebody explain why the ustable behavior of obtaining the attrbutes?

like image 742
Boris Strandjev Avatar asked Sep 26 '13 17:09

Boris Strandjev


3 Answers

It seems this is a bug in the API. I did tests for 4 attributes: gravity, text, textSize and textColor. Here is the code I used:

private void processAndroidAttributes(final Context context, final AttributeSet attrs) {
    ATTRS = new Integer[] {
               android.R.attr.textSize, android.R.attr.text,
               android.R.attr.textColor, android.R.attr.gravity };
    Arrays.sort(ATTRS);
    do {
        printPermutation(ATTRS);
        tryApplyingStyles(context, attrs, ATTRS);
        ATTRS = nextPermutation(ATTRS);
    } while ((ATTRS = nextPermutation(ATTRS)) != null);
}

The method processAndroidAttributes tries applying all the listed attributes and checks if they were applied or defaults were used. For each iteration I print the array ATTRS contents and whether the real value was used (flagged with 1) or default was used (flagged with 0). Here is what I get after I run the above code (every iteration prints couple of lines):

[16842901,16842904,16842927,16843087]
1111
[16842901,16842904,16843087,16842927]
1110
[16842901,16842927,16842904,16843087]
1101
[16842901,16842927,16843087,16842904]
1101
[16842901,16843087,16842904,16842927]
1100
[16842901,16843087,16842927,16842904]
1100
[16842904,16842901,16842927,16843087]
1011
[16842904,16842901,16843087,16842927]
1010
[16842904,16842927,16842901,16843087]
1011
[16842904,16842927,16843087,16842901]
1011
[16842904,16843087,16842901,16842927]
1010
[16842904,16843087,16842927,16842901]
1010
[16842927,16842901,16842904,16843087]
1001
[16842927,16842901,16843087,16842904]
1001
[16842927,16842904,16842901,16843087]
1001
[16842927,16842904,16843087,16842901]
1001
[16842927,16843087,16842901,16842904]
1001
[16842927,16843087,16842904,16842901]
1001
[16843087,16842901,16842904,16842927]
1000
[16843087,16842901,16842927,16842904]
1000
[16843087,16842904,16842901,16842927]
1000
[16843087,16842904,16842927,16842901]
1000
[16843087,16842927,16842901,16842904]
1000
[16843087,16842927,16842904,16842901]
1000

As you see this is almost as if expecting the array to be sorted, with only several outliers. I think it is a bug in the Android API as the documentation of obtainStyledAttributes, does not specify to expect any ordering of the attribute ids.

like image 121
Boris Strandjev Avatar answered Oct 29 '22 01:10

Boris Strandjev


I have the same problem while trying to get 4 attributes with 3 different types. Always only one type of attribute pass to the array and this was always first of them. For example if you declare attributes like {int, String, Color}:

private static final int[] ATTRS = new int[] { android.R.attr.textSize,
   android.R.attr.text, android.R.attr.textColor }

Method obtainStyledAttributes will pass to your TypedArray only the int attributes, the rest will be null.

If you change order to {String, Color, int}:

private static final int[] ATTRS = new int[] {android.R.attr.text, android.R.attr.textColor, android.R.attr.textSize }

You will get only String attributes to your TypedArray, rest will be null.

It looks like the TypedArray can hold only one Type in it so you need to declare more TypeArrays - one for each type of attribute.

Like this:

private static final int[] stringAttrs = new int[] {android.R.attr.text};
private static final int[] intAttrs = new int[] {android.R.attr.textSize};
private static final int[] colorAttrs = new int[] {android.R.attr.textColor, android.R.attr.background};

    private void processAndroidAttributes(final Context context,
       final AttributeSet attrs) {
       final TypedArray stringA = context.obtainStyledAttributes(attrs, stringAttrs);
       final TypedArray intA = context.obtainStyledAttributes(attrs, intAttrs);
       final TypedArray colorA = context.obtainStyledAttributes(attrs, colorAttrs);

       myTextView.setText(stringA.getString(0));
       myTextView.setTextSize(intA.getDimensionPixelSize(0, DEFAULT_TEXT_SIZE));
       myTextView.setTextColor(colorA.getColor(0, Color.WHITE));
       myTextView.setBackgroundColor(colorA.getColor(1, Color.WHITE));

       stringA.recycle();
       intA.recycle();
       colorA.recycle();

    }
like image 23
Warcello Avatar answered Oct 29 '22 01:10

Warcello


I'm surprised someone just had same conclusion with me. I've decided to use one only item array for obtainStyledAttributes so that I don't have to worry about order.

http://androidxref.com/2.2.3/xref/frameworks/base/core/jni/android_util_AssetManager.cpp#911 I didn't look at this source closely but I guess android iterates the AttributeSet only one time in ascending order for efficiency.

like image 34
NoraBora Avatar answered Oct 29 '22 01:10

NoraBora