Attempting to get attribute values ​​in code returns invalid values

I want to extract several attributes from the style resource (only interested in the attributes included in the TextAppearance group)

Style defined as

<style name="Label" parent="@android:style/TextAppearance.Small"> <item name="android:textColor">@color/floatlabel_text</item> <item name="android:textSize">8dp</item> <item name="android:textStyle">bold</item> </style> 

Try first

At first I tried to use TextView (lines 663-731), but then it turned out that we did not have access to com.android.internal.R

Partial solution

This is why I switched to this solution: stack overflow

So, I created textAppearanceAttr to replace com.android.internal.R.styleable.TextAppearance (contains only 10/13 TextAppearance attributes that interest me)

 int[] textAppearanceAttr = new int[]{ android.R.attr.textColor, android.R.attr.textSize, android.R.attr.typeface, android.R.attr.fontFamily, android.R.attr.textStyle, android.R.attr.textAllCaps, android.R.attr.shadowColor, android.R.attr.shadowDx, android.R.attr.shadowDy, android.R.attr.shadowRadius}; 

This is how I used it. I get the style resource identifier (the resource refers to the clTextAppearance attribute)

  int ap = a.getResourceId(R.styleable.CustomLabelLayout_clTextAppearance, android.R.style.TextAppearance_Small); TypedArray appearance = mContext.obtainStyledAttributes(ap, textAppearanceAttr); 

And this is how I get the attributes (still following the answers from the link above):

  mLabelTextColor = appearance.getColorStateList(0); mLabelTextSize = appearance.getDimensionPixelSize(1, 15); mLabelTypeface = appearance.getInt(2, -1); mLabelFontFamily = appearance.getString(3); mLabelTextStyle = appearance.getInt(4, -1); (5 more...) 

Current issue

It seems that only the first attribute is set, each other either sets the default value, or null.

A hack that seems to work

Individual arrays:

 int[] textSizeAttr = new int[] { android.R.attr.textSize}; int[] textStyleAttr = new int[] { android.R.attr.textStyle}; 

And get these attributes

  appearance.recycle(); appearance = mContext.obtainStyledAttributes(ap, textSizeAttr); mLabelTextSize = appearance.getDimensionPixelSize(0, 15); appearance.recycle(); appearance = mContext.obtainStyledAttributes(ap, textStyleAttr); mLabelTextStyle = appearance.getInt(0, -1); appearance.recycle(); 

Now it's such a waste.

Questions

  • I would like to know why getting all attributes at once doesn't work.
  • Is there a solution (where all the extra work is not needed)?

EDIT 1

I found something similar here: https://stackoverflow.com/a/3/9129/ and for some reason this works. Until I add more attributes to the array, everything becomes ker.

Example:

  int[] attrs = {android.R.attr.textColor, android.R.attr.textSize, android.R.attr.background, android.R.attr.textStyle, android.R.attr.textAppearance, android.R.attr.textColorLink, android.R.attr.orientation, android.R.attr.text}; 

If I get text using the specified array, it works.

 String text = ta.getString(7); 

But if I changed the array to below, it did not work (replaced android.R.attr.orientation with android.R.attr.shadowColor)

 int[] attrs = {android.R.attr.textColor, android.R.attr.textSize, android.R.attr.background, android.R.attr.textStyle, android.R.attr.textAppearance, android.R.attr.textColorLink, android.R.attr.shadowColor, android.R.attr.text}; 

Why is this happening? (Question No. 1)

+13
android android-layout
Aug 20 '14 at 10:30
source share
3 answers

I think I have an idea why this is happening. It seems that if the identifiers are not sorted, problems arise. textColor , for example, has the lowest int value, so it starts working by placing itself in the first position in the array.

If you look at R.java for your style, you will see that the Android resource compiler has sorted the identifiers for you. Therefore, it always works if you declare stylable in attrs.xml and cannot work if you manually create identifier arrays.

I believe there is a performance reason for sorting identifiers. If they are sorted, attributes can be read from the AttributeSet using a single walk instead of N walks in the case of N identifiers.

UPDATE: I took a look at the source code, and this proves my idea. Context.obtainStyledAttributes () calls the JNI AssetManager.applyStyle () method. You can find the source here:

https://android.googlesource.com/platform/frameworks/base.git/+/android-4.3_r2.1/core/jni/android_util_AssetManager.cpp

On line 1001, you will find a while loop, where ix (the index in the extracted XML attribute array) always increments and never reset is 0. This means that if textColor is the last index in the array (the "src" variable in the code), then we never get to this attribute.

+10
Nov 27 '14 at 17:11
source share

Thanks to @PrivatMamtora and @igret for learning this! If the problem is that identifiers should be ordered, this should be normal.

 private static final int ATTR_PADDING = android.R.attr.padding; private static final int ATTR_TEXT_COLOR = android.R.attr.textColor; private static final int ATTR_TEXT_SIZE = android.R.attr.textSize; private void loadAttributes(Context context, AttributeSet attrs) { int[] ids = { ATTR_PADDING, ATTR_TEXT_COLOR, ATTR_TEXT_SIZE}; Arrays.sort(ids); // just sort the array TypedArray a = context.obtainStyledAttributes(attrs, ids); try { padding = a.getDimensionPixelSize(indexOf(ATTR_PADDING, ids), padding); textColor = a.getColor(indexOf(ATTR_TEXT_COLOR, ids), textColor); textSize = a.getDimensionPixelSize(indexOf(ATTR_TEXT_SIZE, ids), textSize); } finally { a.recycle(); } } private int indexOf(int id, int[] ids) { for (int i = 0; i < ids.length; i++) { if (ids[i] == id) { return i; } } throw new RuntimeException("id " + id + " not in ids"); } 
+6
Mar 03 '15 at 0:40
source share

Get its action as follows: I defined a new styleable :

 <?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="Label" > <attr name="android:textColor" /> <attr name="android:textSize" /> <attr name="android:textStyle" /> <attr name="android:typeface" /> </declare-styleable> </resources> 

Then here are my styles.xml:

 <resources xmlns:android="http://schemas.android.com/apk/res/android"> <style name="Label" parent="@android:style/TextAppearance.Small"> <item name="android:textColor">#12345678</item> <item name="android:textSize">8dp</item> <item name="android:textStyle">bold</item> <item name="android:typeface">serif</item> </style> </resources> 

And finally, the test:

 public class TextAppearanceTest extends AndroidTestCase { public void test() { TypedArray a = getContext().obtainStyledAttributes(R.style.Label, R.styleable.Label); assertTrue(a.getColor(R.styleable.Label_android_textColor, -1) != -1); assertTrue(a.getDimensionPixelSize(R.styleable.Label_android_textSize, -1) != -1); assertTrue(a.getInt(R.styleable.Label_android_typeface, -1) != -1); } } 
+5
Aug 20 '14 at 1:47
source share



All Articles