SetSelection on a spinner crashes when layout_weight is assigned to spinner
Asked Answered
R

6

5

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

Richards answered 6/4, 2016 at 9:33 Comment(11)
nullpointer ?? ddFeet.setSelection(3); . same problem for ddFeet.setSelection(2);???Conspecific
yes. When I comment that line. The rest of the code worksRichards
post R.array.feet?Conspecific
put items in your array listTamas
@SushilKumar yes .Problem for positionConspecific
@Richards don't direct put number in the ddFeet.setSelection(3); first check array size is greater than your number .Tamas
I am using a variable in my code, I kept a number like that here to keep it simpleRichards
@Richards okay .mention me which line in your adapter sectionConspecific
@Richards please post your full xml file ....This one is running on my PC. without any error.Tamas
I have added the xml fileRichards
Hi! I have a very similar code and it crashes with the same stracktrace on any android Lollipop device. How did you fix the problem ?Reciprocate
M
6
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

Maestricht answered 11/8, 2016 at 4:17 Comment(3)
Can provide an explanation?Richards
I'm not sure why, but this fixes the problem when having Spinner with weight. Can it be because by setting animate=true it waits until the spinner is fully drawn?Eclosion
had this issue when setEnabled was true, it also needs setselection to have true, works normal if its not setEnabled.Pacifistic
R
3

I have solved the problem with putting the TextView in a layout group programatically:

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

Also interesting, that the crash occurred after I included this numberpicker library to my project. I don't know what is the coherence between the library and the crash, but if I exclude it, the crash disappear again.

Also I found a related android issue. The reason provided is: Since the TextView is not wrapped in a ViewGroup, any interaction with the view causes the application to crash with a null pointer exception. The TextView is trying to measure some ViewGroup.LayoutParams.

Reciprocate answered 5/8, 2016 at 13:26 Comment(2)
Thanks. Spent a lot of time to findout the issue. Just this info, solve my issue on crashing the app. But will need to test for later Android (6, 7) and the lower than 5 to be sure.Mistymisunderstand
I have tested it from Android SDK 18 till SDK 23Reciprocate
C
2

Set android:layout_width="0dp" to TextView and give layout_weight to it as per your requirement.

Cutlet answered 6/4, 2016 at 9:41 Comment(5)
My need is to give the textView a fixed width, which I have given. It is the width of the spinner that is giving the errorRichards
I dont think that is possible as layout_weight doesn't work that way. Look at here linkCutlet
Layout_weight only works on remaining area, not total area. checkout this video youtube.com/watch?v=rMksRBvYG28 .Richards
What I want to say is you cant use layout_weight on single child of parent view group. All children must have layout_weight attribute. You can give your text view a fixed width with appropriate weight.Cutlet
yes you can give width to a child layout as long as it does not have layout_weight. layout_weight overrides any width given. Hence android studio recommends 0dp width be given.Richards
S
0

I think this is happens because as you are using weight for this Linear Layout and also you set the TextView width

android:layout_width="80dp"

set TextView width 0dp and give weight.

android:layout_width="0dp"

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

You have to give separate weight for all sub views of this Linear layout and also set width 0dp for all sub views.

Hope this will work for you...

Skiagraph answered 6/4, 2016 at 10:4 Comment(6)
I need the width to be 25% of the available spaceRichards
I tried it. It didn't work. I tried to put only the spinners in a separate linear layout and then apply weights to them and that too gave the dame errorRichards
invalidate is an android command, I don't know where its code is written. I have included some explanation about what it isRichards
Are you inflate some view somewhere in TextView.java class??Skiagraph
No. It is the default android textview class. I have added new observation. Please see above.Richards
ok...Give an id to this TextView in Xml file..android:id="@+id/textView"Skiagraph
R
0

As a workaround, instead of layout_weight, I have used percentrelativelayout. The library can be included by adding compile 'com.android.support:percent:23.2.0' to the dependencies in build.gradle.

Here is how I used it. It works exactly as I want. *I have removed unnecessary xml attributes.

    <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>
Richards answered 6/4, 2016 at 12:16 Comment(0)
U
0

Maybe it is late, but this is how I handle the problem. I had this error when I want to divide screen two equal parts and one part is spinner. Therefore I have used

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

combination. It works fine on some devices, but some devices throw that exception. Then I give android:weightSum="2" to the parent layout. Then the problem has been solved.

Underquote answered 18/9, 2018 at 9:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.