Search code examples
androidandroid-layoutandroid-spinnerandroid-layout-weight

SetSelection on a spinner crashes when layout_weight is assigned to spinner


I have done a simplified experiment to identify where I am having this problem. It was a long question with a lot of code earlier. Now I have kept a small and simple code:

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.

This is the error:

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)

This error comes because I have set the layout_width=0dp. But at the same time layout_weight = 1. NOTE: The spinner is properly inflated when setSelection(0). So the problem is not with straight forward inflation.

Here is the 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" />

The entire code works perfectly if layout_width = Any non zero dp or match_parent or wrap_content while there is no layout_weight.

But with the same above layout the following code works correctly with no crashes:

    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);

Thus I can conclude that there is some problem with the ProfileSpinnerAdapter class that I have made which conflicts with layout_weight = 1 and width = 0dp

Here is the adapter:

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;
}
}

The cause for the error is in the adapter. It gives no error if spinner width = 100dp and only gives error when layout_weight attribute is put on the spinner


Solution

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

    change to

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

    I also had this question and solved