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?
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.
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();
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With