1

I am using the attached class in viewholder patern to instantiate and reuse my item views each time i try to work woth adapters

anyways whenever am trying to set the view text to certain value it crashes giving that the view is null

public class SpinnerServicesAdapter extends ArrayAdapter<MyService> {
private LayoutInflater inflater;
private Context mContext;
private ArrayList<MyService> services;
private String headerTxt;

public SpinnerServicesAdapter(Context mContext, int textViewResourceId, ArrayList services, String headerTxt) {
    super(mContext, textViewResourceId, services);
    this.mContext = mContext;
    this.services = services;
    this.headerTxt = headerTxt;
    inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}

@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
    return getCustomView(position, convertView, parent);
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    return getCustomView(position, convertView, parent);
}
public View getCustomView(int position, View convertView, ViewGroup parent) {
    SpinnerViewHolder spinnerViewHolder;

    if (convertView == null) {
        if (position == 0) {
            convertView = inflater.inflate(R.layout.spinner_header_item_two, parent, false);
        } else {
            convertView = inflater.inflate(R.layout.spinner_item_two, parent, false);
        }
        spinnerViewHolder = new SpinnerViewHolder(convertView);
        convertView.setTag(spinnerViewHolder);
    } else {
        spinnerViewHolder = (SpinnerViewHolder) convertView.getTag();
    }

    if (position == 0) {
        spinnerViewHolder.txtVue.setText(headerTxt);
    } else {
        spinnerViewHolder.txtVue.setText(services.get(position).getName_en());
    }

    return convertView;
}

class SpinnerViewHolder {
    TextView txtVue;
    public SpinnerViewHolder(View v) {
        txtVue = (TextView) v.findViewById(R.id.spinner_item_two);
    }
}

}

java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference
    at com.infovas.hanger.adapters.SpinnerServicesAdapter.getCustomView(SpinnerServicesAdapter.java:60)
    at com.infovas.hanger.adapters.SpinnerServicesAdapter.getView(SpinnerServicesAdapter.java:42)
    at android.widget.AbsSpinner.onMeasure(AbsSpinner.java:197)
    at android.widget.Spinner.onMeasure(Spinner.java:507)
    at android.support.v7.widget.AppCompatSpinner.onMeasure(AppCompatSpinner.java:416)
    at android.view.View.measure(View.java:17548)
    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5478)
    at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1436)
    at android.widget.LinearLayout.measureHorizontal(LinearLayout.java:1083)
    at android.widget.LinearLayout.onMeasure(LinearLayout.java:615)
    at android.view.View.measure(View.java:17548)
    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5478)
    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:17548)
    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5478)
    at android.widget.FrameLayout.onMeasure(FrameLayout.java:430)
    at android.support.v7.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:139)
    at android.view.View.measure(View.java:17548)
    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5478)
    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:17548)
    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5478)
    at android.widget.FrameLayout.onMeasure(FrameLayout.java:430)
    at android.view.View.measure(View.java:17548)
    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5478)
    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:17548)
    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5478)
    at android.widget.FrameLayout.onMeasure(FrameLayout.java:430)
    at com.android.internal.policy.impl.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2632)
    at android.view.View.measure(View.java:17548)
    at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2125)
    at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1238)
    at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1455)
    at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1126)
    at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6041)
    at android.view.Choreographer$CallbackRecord.run(Choreographer.java:792)
    at android.view.Choreographer.doCallbacks(Choreographer.java:596)
    at android.view.Choreographer.doFrame(Choreographer.java:557)
    at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:778)
    at android.os.Handler.handleCallback(Handler.java:739)
    at android.os.Handler.dispatchMessage(Handler.java:95)
Guillaume Barré
  • 4,168
  • 2
  • 27
  • 50
aya salama
  • 903
  • 1
  • 10
  • 29
  • I guess you trying to create a `listview` with multiple rows views, if yes then this implementation is wrong, take a look at this [question](http://stackoverflow.com/questions/4777272/android-listview-with-different-layouts-for-each-row). Also I would suggest you to use `RecyclerView` instead of `listview`. – Atef Hares Feb 28 '17 at 08:33
  • Since you are using two different layouts, make sure to have the same view with same id `R.id.spinner_item_two` in two layouts. Hope this will help! – ArbenMaloku Feb 28 '17 at 08:34
  • Please check my answer below – blueware Feb 28 '17 at 08:48

3 Answers3

1

First, the issue is that (TextView) v.findViewById(R.id.spinner_item_two) return null (== don't find the view with id R.id.spinner_item_two in v). You have to check that this ID is correct in your XML layout.

Secondly, you inflate different view by the position. The problem is that the framework will reuse it without distinction. You have to override getItemViewType(int position) for returning two int, one for each type of view.

Finally, the framework give us a more beautiful method to do with RecyclerView. If you have time, check it.

Kevin Robatel
  • 8,025
  • 3
  • 44
  • 57
1

You are using one ViewHolder for two different adapter layouts, this what produces nullable views, alternatively, you may override getItemViewType method in your Adapter to determine Header Item and Normal Item like this:

1- Define those constants in your adapter class:

private final int TYPE_HEADER = 0;
private final int TYPE_ITEM = 1;

2- Override the getItemViewType(int position) method in your adapter:

@Override
public int getItemViewType(int position) {
    if (isPositionHeader(position))
        return TYPE_HEADER;

    return TYPE_ITEM;
}

private boolean isPositionHeader(int position) {
    return position == 0;
}

3- Create a ViewHolder class for Header Items:

class SpinnerHeaderViewHolder {
    TextView txtHeader;
    public SpinnerHeaderViewHolder(View v) {
        txtHeader= (TextView) v.findViewById(R.id.spinner_header_item_text_view);
    }
}

Don't forget to refer the 'txtHeader' to the correct id in your (header layout)

4- Now in your getCustomView(int position, View convertView, @NonNull ViewGroup parent) method, do this:

public View getCustomView(int position, View convertView, ViewGroup parent) {
    final ViewHolder viewHolder;

    final int itemType = getItemViewType(position);

    if (convertView == null) {
        if (itemType == TYPE_HEADER) {
            convertView = inflater.inflate(R.layout.spinner_header_item_two, parent, false);
            viewHolder = new SpinnerHeaderViewHolder(convertView);
        } else {
            convertView = inflater.inflate(R.layout.spinner_item_two, parent, false);
            viewHolder = new SpinnerViewHolder(convertView);
        }
        convertView.setTag(viewHolder);

    } else {
        viewHolder = (ViewHolder) convertView.getTag();
    }

    if (position == 0) {
        ((SpinnerHeaderViewHolder) viewHolder).txtHeader.setText(headerTxt);
    } else {
        ((SpinnerViewHolder) viewHolder).txtVue.setText(services.get(position).getName_en());
    }

    return convertView;
}

Hope this will help.

blueware
  • 5,205
  • 1
  • 40
  • 60
  • I did updated my adapters and used getViewType function, but still facing the same issue, ids are correct and separated the viewholders for headers and normal items – aya salama Feb 28 '17 at 09:24
  • Why you are using `getCustomView` method while you can diretly implement your code inside the `getView` method ? – blueware Feb 28 '17 at 09:28
  • am using an ArrayAdapter to custom spinners adapter not a baseAdapter – aya salama Feb 28 '17 at 09:34
  • You may use the default `getView` method for customizing your adapters, could you try without the `getCustomView` one ? – blueware Feb 28 '17 at 09:52
0

Are you sure that the textview having as id "spinner_item_two" exists in both files "spinner_header_item_two.xml" and "spinner_item_two.xml ?