当 layout_weight 分配给微调器时微调器上的 SetSelection 崩溃

SetSelection on a spinner crashes when layout_weight is assigned to spinner

我做了一个简化的实验来确定我在哪里遇到这个问题。这是一个很长的问题,前面有很多代码。现在我保留了一个小而简单的代码:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_spinner_test);

    Spinner spin1 = (Spinner) findViewById(R.id.spin1);
    spin1.setAdapter(new ProfileSpinnerAdapter(this, R.array.feet));
    spin1.setSelection(0);  //does not crash
    spin1.setSelection(getResources().getStringArray(R.array.feet).length - 1);  //it crashes
   //it crashes for any value greater than 0 and less than array length.

这是错误:

java.lang.NullPointerException: Attempt to read from field 'int android.view.ViewGroup$LayoutParams.width' on a null object reference
    at android.widget.TextView.checkForRelayout(TextView.java:6830)
    at android.widget.TextView.onRtlPropertiesChanged(TextView.java:8948)
    at android.view.View.resolveRtlPropertiesIfNeeded(View.java:13118)
    at android.view.View.measure(View.java:17557)
    at android.widget.Spinner.setUpChild(Spinner.java:657)
    at android.widget.Spinner.makeView(Spinner.java:610)
    at android.widget.Spinner.getBaseline(Spinner.java:456)
    at android.widget.LinearLayout.measureHorizontal(LinearLayout.java:1294)
    at android.widget.LinearLayout.onMeasure(LinearLayout.java:615)
    at android.view.View.measure(View.java:17562)
    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5536)
    at android.widget.FrameLayout.onMeasure(FrameLayout.java:436)
    at android.view.View.measure(View.java:17562)
    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5536)
    at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1436)
    at android.widget.LinearLayout.measureVertical(LinearLayout.java:722)
    at android.widget.LinearLayout.onMeasure(LinearLayout.java:613)
    at android.view.View.measure(View.java:17562)
    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5536)
    at android.widget.FrameLayout.onMeasure(FrameLayout.java:436)
    at com.android.internal.policy.impl.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2871) 
    at android.view.View.measure(View.java:17562)
    at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2015)
    at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1173)
    at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1379)
    at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1061)
    at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5891)
    at android.view.Choreographer$CallbackRecord.run(Choreographer.java:767)
    at android.view.Choreographer.doCallbacks(Choreographer.java:580)
    at android.view.Choreographer.doFrame(Choreographer.java:550)
    at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:753)
    at android.os.Handler.handleCallback(Handler.java:739)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:135)
    at android.app.ActivityThread.main(ActivityThread.java:5294)
    at java.lang.reflect.Method.invoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:372)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:904)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:699)

出现这个错误是因为我设置了layout_width=0dp。但同时 layout_weight = 1。 注意:微调器在设置选择(0)时正确充气。所以问题不在于直接 inflation.

这里是 xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
tools:context="in.jiyofit.the_app.SpinnerTestActivity">

<Spinner
    android:id="@+id/spin1"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_weight="1" />

如果 layout_width = 任何非零 dp 或 match_parent 或 wrap_content ,则整个代码 完美运行 不是layout_weight.

但是使用上面相同的布局,下面的代码可以正常工作,没有崩溃:

    Spinner spin1 = (Spinner) findViewById(R.id.spin1);
    ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this,
            R.array.feet, android.R.layout.simple_spinner_item);
    adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    spin1.setAdapter(adapter);
    spin1.setSelection(getResources().getStringArray(R.array.feet).length - 1);

因此我可以得出结论,我制作的 ProfileSpinnerAdapter class 存在一些问题,它与 layout_weight = 1 和 width = 0dp

冲突

这是适配器:

public class ProfileSpinnerAdapter extends BaseAdapter {
String[] array;
Context ctx;

public ProfileSpinnerAdapter(Context context, int arrayID) {
    this.ctx = context;
    this.array = ctx.getResources().getStringArray(arrayID);
}

@Override
public int getCount() {
    return array.length;
}

@Override
public Object getItem(int position) {
    return array[position];
}

@Override
public long getItemId(int position) {
    return 0;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    TextView textView = new TextView(ctx);
    textView.setText(array[position]);
    textView.setTextSize(16);
    if(array[position].length() > 6){
        Typeface hindiFont = Typeface.createFromAsset(ctx.getAssets(),"fonts/mfdev010.ttf");
        textView.setTextSize(22);
        textView.setTypeface(hindiFont);
    }
    if(position == 0){
        textView.setTextColor(ContextCompat.getColor(ctx, R.color.primaryText));
    }
    return textView;
}

@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
    TextView textView = new TextView(ctx);
    textView.setText(array[position]);
    textView.setTextSize(16);
    textView.setPadding(0, 5, 0, 0);
    if(array[position].length() > 6){
        Typeface hindiFont = Typeface.createFromAsset(ctx.getAssets(),"fonts/mfdev010.ttf");
        textView.setTextSize(22);
        textView.setTypeface(hindiFont);
        textView.setPadding(10,5,10,5);
    }
    textView.setBackgroundColor(ContextCompat.getColor(ctx, R.color.white));
    textView.setTextColor(ContextCompat.getColor(ctx, R.color.primaryText));
    textView.setGravity(Gravity.CENTER);
    /*
    the adapter fills the number of elements based in the getCount
    so either getCount returns value conditionally for an array of different size in getDropDownView
    or the requisite value at position is hidden
    */
    if(position == 0){
        textView.setVisibility(View.GONE);
        textView.setHeight(0);
    }
    return textView;
}
}

错误的原因在适配器中。 如果 spinner width = 100dp 则不会报错,只有当 layout_weight 属性放在 spinner

时才会报错

android:layout_width="0dp" 设置为 TextView 并根据您的要求为其提供 layout_weight

我认为发生这种情况是因为您为此线性布局使用了权重并且还设置了 TextView 宽度

android:layout_width="80dp"

设置TextView宽度为0dp并赋予权重。

android:layout_width="0dp"

android:layout_weight="0.25" //according to total weight

您必须为此线性布局的所有子视图分别赋予权重,并为所有子视图设置宽度 0dp。

希望这对你有用...

作为变通方法,我使用了 percentrelativelayout 而不是 layout_weight。可以通过将 compile 'com.android.support:percent:23.2.0' 添加到 build.gradle.

中的依赖项来包含该库

下面是我的使用方法。它完全按照我的意愿工作。 *我删除了不必要的 xml 属性。

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <TextView
            android:layout_width="80dp"
            android:layout_height="wrap_content"
            android:text="@string/aprofile_height" />

        <android.support.percent.PercentRelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <Spinner
                android:id="@+id/aprofile_dd_feet"
                app:layout_widthPercent="50%"
                android:layout_height="wrap_content" />

            <Spinner
                android:id="@+id/aprofile_dd_inches"
                app:layout_widthPercent="50%"
                android:layout_height="wrap_content"
                android:layout_alignParentEnd="true"
                android:layout_alignParentRight="true"/>

        </android.support.percent.PercentRelativeLayout>

    </LinearLayout>

我已经解决了以编程方式将 TextView 放入布局组的问题:

@Override
public View getView(int position, View arg1, ViewGroup arg2){

    ...

    // without this rtl the app crashes on lollipop devices with shawnlin number-picker
    RelativeLayout rtlContainer = new RelativeLayout(mContext);
    rtlContainer.addView(textView);
    return rtlContainer;
}

同样有趣的是,崩溃发生在我将 this numberpicker 库添加到我的项目之后。我不知道库和崩溃之间的连贯性是什么,但是如果我排除它,崩溃又消失了。

我还找到了一个相关的android issue。提供的原因是:由于 TextView 未包装在 ViewGroup 中,与视图的任何交互都会导致应用程序崩溃并出现空指针异常。 TextView 正在尝试测量一些 ViewGroup.LayoutParams.

spin1.setSelection(0);  //does not crash
spin1.setSelection(getResources().getStringArray(R.array.feet).length - 1); 

改为

spin1.setSelection(0, true); 
spin1.setSelection(getResources().getStringArray(R.array.feet).length - 1, true); 

我也有这个问题并解决了

也许是晚了,但这就是我处理问题的方式。当我想将屏幕分成两个相等的部分并且一个部分是微调器时,我遇到了这个错误。因此我使用了

android:layout_weight="1"
android:layout_width="0dp"

组合。它在某些设备上运行良好,但某些设备会抛出该异常。然后我给父布局 android:weightSum="2" 。那么问题就解决了