NumberFormatException при использовании настраиваемых атрибутов

Я создал настраиваемый вид для Android, который отображает два внутренних представления для хранения ключа и значения в двух столбцах. Класс выглядит следующим образом:

public class KeyValueRow extends RelativeLayout {

    protected TextView mLabelTextView;
    protected TextView mValueTextView;

    public KeyValueRow(final Context context) {
        super(context);
        init(context, null, 0);
    }

    public KeyValueRow(final Context context, final AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs, 0);
    }

    public KeyValueRow(final Context context, 
                       final AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context, attrs, defStyle);
    }

    protected void init(final Context context, 
                        final AttributeSet attrs, int defStyle) {
        View layout = ((LayoutInflater) context
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE))
            .inflate(R.layout.key_value_row, this, true); // line 46
        mLabelTextView = (TextView) layout.findViewById(
            R.id.key_value_row_label);
        mValueTextView = (TextView) layout.findViewById(
            R.id.key_value_row_value);
    }

    public void setLabelText(final String text) {
        mLabelTextView.setText(text);
    }

    public void setValueText(final String text) {
        mValueTextView.setText(text);
    }

}

Соответствующий макет файла макета /key _value_row.xml выглядит следующим образом:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:weightSum="1.0">

    <TextView
        android:id="@+id/key_value_row_label"
        style="@style/KeyValueLabel"
        android:layout_weight=".55"
        tools:text="Label"/>

    <TextView
        android:id="@+id/key_value_row_value"
        style="@style/KeyValueValue"
        android:layout_weight=".45"
        tools:text="Value"/>

</LinearLayout>

В макете это можно использовать следующим образом:

<com.example.myapp.customview.KeyValueRow
    android:id="@+id/foobar"
    style="@style/KeyValueRow" />

Пока все работает нормально!

Задача

Теперь я хочу разрешить настраиваемые параметры для атрибутов layout_weight как внутренних TextView s. Поэтому я подготовил атрибуты в значениях /attrs.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="KeyValueRow">
        <attr name="label_layout_weight" format="float" />
        <attr name="value_layout_weight" format="float" />
    </declare-styleable>
</resources>

Первый вопрос: float правильный формат для layout_weight?
Затем я применил бы их в файле макета:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:weightSum="1.0">

    <TextView
        android:id="@+id/key_value_row_label"
        style="@style/KeyValueLabel"
        android:layout_weight="?label_layout_weight"
        tools:text="Label"/>

    <TextView
        android:id="@+id/key_value_row_value"
        style="@style/KeyValueValue"
        android:layout_weight="?value_layout_weight"
        tools:text="Value"/>

</LinearLayout>

Затем они могут быть использованы в примере:

<com.example.myapp.customview.KeyValueRow
    android:id="@+id/foobar"
    style="@style/KeyValueRow"
    custom:label_layout_weight=".25"
    custom:value_layout_weight=".75" />

Когда я запускаю эту реализацию, создается следующее исключение:

Caused by: java.lang.NumberFormatException: Invalid float: "?2130772062"
    at java.lang.StringToReal.invalidReal(StringToReal.java:63)
    at java.lang.StringToReal.parseFloat(StringToReal.java:310)
    at java.lang.Float.parseFloat(Float.java:300)
    at android.content.res.TypedArray.getFloat(TypedArray.java:288)
    at android.widget.LinearLayout$LayoutParams.<init>(LinearLayout.java:1835)
    at android.widget.LinearLayout.generateLayoutParams(LinearLayout.java:1743)
    at android.widget.LinearLayout.generateLayoutParams(LinearLayout.java:58)
    at android.view.LayoutInflater.rInflate(LayoutInflater.java:757)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:492)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:397)
    at com.example.myapp.customview.KeyValueRow.init(KeyValueRow.java:46)
    at com.example.myapp.customview.KeyValueRow.<init>(KeyValueRow.java:28)
    ... 33 more

Ответ 1

Вы можете использовать

private void applyAttributes(Context context, AttributeSet attrs) {
    TypedArray a = context.getTheme().obtainStyledAttributes(
        attrs, R.styleable.KeyValueRow, 0, 0);
    try {
        labelWeight = a.getFloat(
            R.styleable.KeyValueRow_label_layout_weight, 0.55f);
        valueWeight = a.getFloat(
            R.styleable.KeyValueRow_value_layout_weight, 0.45f);
    } finally {
        a.recycle();
    }
}

и после этого вы можете применить это через:

mLabelTextView = (TextView) layout.findViewById(R.id.key_value_row_label);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
    LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, labelWeight);
mLabelTextView.setLayoutParams(layoutParams);

Чтобы запустить его, замените android:layout_weight="?label_layout_weight" некоторым значением по умолчанию, например android:layout_weight="0.5" в layout/key_value_row.xml. Он будет перезаписан.