简体   繁体   中英

Android - Listview with section header causing error

When I am adding section header in my listview I got nullpointerexception error when I am scrolling a listview.

E/AndroidRuntime: FATAL EXCEPTION: main
                  Process: com.arrayadapter, PID: 20681
                  java.lang.NullPointerException: Attempt to read from field 'android.widget.TextView com.arrayadapter.ABCArrayAdapter$ViewHolderHeader.header' on a null object reference
                      at com.arrayadapter.ABCArrayAdapter.getView(ABCArrayAdapter.java:185)
                      at android.widget.AbsListView.obtainView(AbsListView.java:2929)
                      at android.widget.ListView.makeAndAddView(ListView.java:1945)
                      at android.widget.ListView.fillDown(ListView.java:719)
                      at android.widget.ListView.fillGap(ListView.java:683)
                      at android.widget.AbsListView.trackMotionScroll(AbsListView.java:7293)
                      at android.widget.AbsListView.scrollIfNeeded(AbsListView.java:4391)
                      at android.widget.AbsListView.onTouchMove(AbsListView.java:5782)
                      at android.widget.AbsListView.onTouchEvent(AbsListView.java:5610)
                      at android.view.View.dispatchTouchEvent(View.java:9993)
                      at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2830)
                      at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2501)
                      at android.widget.AbsListView.dispatchTouchEvent(AbsListView.java:5547)
                      at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2841)
                      at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2516)
                      at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2841)
                      at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2516)
                      at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2841)
                      at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2516)
                      at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2841)
                      at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2516)
                      at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2841)
                      at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2516)
                      at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2841)
                      at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2516)
                      at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2841)
                      at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2516)
                      at com.android.internal.policy.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2831)
                      at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1863)
                      at android.app.Activity.dispatchTouchEvent(Activity.java:3046)
                      at android.support.v7.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:67)
                      at android.support.v7.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:67)
                      at com.android.internal.policy.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2792)
                      at android.view.View.dispatchPointerEvent(View.java:10228)
                      at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:5345)
                      at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:5181)
                      at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4621)
                      at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4674)
                      at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4640)
                      at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:4782)
                      at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4648)
                      at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:4839)
                      at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4621)
                      at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4674)
                      at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4640)
                      at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4648)
                      at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4621)
                      at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:7307)
                      at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:7185)
                      at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:7146)
                    at android.view.ViewRootImpl$Wind

Here is my arrayadapter class code.(updated after @RachitSolanki's suggestions)

public class ABCArrayAdapter extends ArrayAdapter<ABCModel> {

Context context;
ArrayList<ABCModel> selectedlocation;
public ArrayList<String> locationid = new ArrayList<String>();
public String primarylocation = "null";
int clickedRadioButtonPosition = -1;
ViewHolder viewHolder = null;
ViewHolderHeader viewHolderHeader = null;

public ABCArrayAdapter(Context context, int resourceId, ArrayList<ABCModel> selectedlocation) {
    super(context, resourceId, selectedlocation);
    this.context = context;
    this.selectedlocation = new ArrayList<ABCModel>();
    this.selectedlocation.addAll(selectedlocation);
}

public int getCount() {
    return this.selectedlocation.size();
}

public ABCModel getItem(int position) {
    return this.selectedlocation.get(position);
}

public long getItemId(int position) {
    return this.selectedlocation.get(position).hashCode();
}

// View lookup cache
private static class ViewHolder {
    TextView name;
    TextView home;
    CheckBox chk_locationlist;
    RadioButton rbt_primarylocation;

}

private static class ViewHolderHeader {

    TextView txt_header;
}

public int getViewTypeCount() {
    return 2;
}

@Override
public int getItemViewType(int position) {

    if (getItem(position).isSectionHeader()) {
        return 0;
    } else {
        return 1;
    }
}

@Override
public View getView(final int position, View convertView, ViewGroup parent) {

    LayoutInflater mInflater = (LayoutInflater) context
            .getSystemService(Activity.LAYOUT_INFLATER_SERVICE);

    int type = getItemViewType(position);

    if (type == 0) {
        if (convertView == null) {
            convertView = mInflater.inflate(R.layout.section_header, null);

            viewHolderHeader = new ViewHolderHeader();
            viewHolderHeader.txt_header = (TextView) convertView.findViewById(R.id.section_header);
            convertView.setTag(viewHolderHeader);
            viewHolder = null;
        } else {
            viewHolderHeader = (ViewHolderHeader) convertView.getTag(R.layout.section_header);
            viewHolder = null;
        }

    } else if (type == 1) {
        if (convertView == null) {

            // If there's no view to re-use, inflate a brand new view for row
            convertView = mInflater.inflate(R.layout.ABC_list_item_name, null);
            viewHolder = new ViewHolder();

            viewHolder.name = (TextView) convertView.findViewById(R.id.txt_ha_name);
            viewHolder.home = (TextView) convertView.findViewById(R.id.txt_ha_town);
            viewHolder.chk_locationlist = (CheckBox) convertView.findViewById(R.id.chk_box_ha_list);
            viewHolder.rbt_primarylocation = (RadioButton) convertView.findViewById(R.id.rbtn_pl);
            viewHolder.rbt_primarylocation.setPaintFlags(viewHolder.rbt_primarylocation.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);

            viewHolder.chk_locationlist.setOnClickListener(new View.OnClickListener() {
                public void onClick(View v) {
                    CheckBox cb = (CheckBox) v;
                    View finalConvertView = (View) v.getParent();
                    RadioButton rbt_primarylocation = (RadioButton) finalConvertView.findViewById(R.id.rbtn_pl);
                    int pos = (Integer) v.getTag();
                    ABCModel _state = (ABCModel) selectedlocation.get(pos);

                    if (cb.isChecked()) {
                        _state.setSelected(cb.isChecked());
                        // Update ArrayList
                        selectedlocation.remove(pos);
                        selectedlocation.add(pos, _state);

                        locationid.add(_state.getId().toString());
                        rbt_primarylocation.setVisibility(View.VISIBLE);

                        if (locationid.size() == 1) {
                            rbt_primarylocation.setChecked(true);
                            primarylocation = _state.getId().toString();
                            rbt_primarylocation.setText("This is my primary location.");
                            rbt_primarylocation.setPaintFlags(0);
                            System.out.println("Primary Location---" + primarylocation);
                        }

                    } else {
                        _state.setSelected(false);
                        locationid.remove(_state.getId().toString());

                        // When unchecked the one with radio button selected
                        if (rbt_primarylocation.isChecked()) {
                            if (locationid.size() > 0) {
                                //rbt_primarylocation.setChecked(true);
                                rbt_primarylocation.setText("Make this my primary location.");
                                rbt_primarylocation.setPaintFlags(rbt_primarylocation.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);

                                primarylocation = "null";
                                Toast.makeText(
                                        v.getContext(),
                                        "Please select a Primary Location", Toast.LENGTH_LONG).show();
                            }
                        }

                        rbt_primarylocation.setVisibility(View.INVISIBLE);

                    }
                }
            });
            viewHolder.rbt_primarylocation.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    clickedRadioButtonPosition = (Integer) v.getTag();
                    ABCModel _state = (ABCModel) selectedlocation.get(clickedRadioButtonPosition);
                    primarylocation = _state.getId().toString();
                    viewHolder.rbt_primarylocation.setText("This is my primary location.");
                    viewHolder.rbt_primarylocation.setPaintFlags(0);
                    System.out.println("Primary Location---" + primarylocation);
                    notifyDataSetChanged();
                }
            });

            // Cache the viewHolder object inside the fresh view
            convertView.setTag(viewHolder);
            viewHolderHeader = null;
        } else {

            // View is being recycled, retrieve the viewHolder object from tag
            viewHolder = (ViewHolder) convertView.getTag(R.layout.search_expand_item);
            viewHolderHeader = null;
        }

    }

    if(type == 0)
    {
        ABCModel state = selectedlocation.get(position);
        viewHolderHeader.txt_header.setText(state.getRegion());
    }else
    {
        ABCModel state = selectedlocation.get(position);
        viewHolder.name.setText(state.getName());
        viewHolder.home.setText(state.getAddress1() + "\r\n" + state.getCity() + ", " + state.getState() + " " + state.getZip());
        viewHolder.chk_locationlist.setChecked(state.isSelected());

        // Set views for view recycling on scrolling
        if (viewHolder.chk_locationlist.isChecked()) {
            viewHolder.rbt_primarylocation.setVisibility(View.VISIBLE);
        } else {
            viewHolder.rbt_primarylocation.setVisibility(View.INVISIBLE);
        }
        if (position == clickedRadioButtonPosition) {
            viewHolder.rbt_primarylocation.setChecked(true);
            viewHolder.rbt_primarylocation.setText("This is my primary location.");
            viewHolder.rbt_primarylocation.setPaintFlags(0);
        } else {
            viewHolder.rbt_primarylocation.setChecked(false);
            viewHolder.rbt_primarylocation.setText("Make this my primary location.");
            viewHolder.rbt_primarylocation.setPaintFlags(viewHolder.rbt_primarylocation.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
        }

        viewHolder.chk_locationlist.setTag(position);
        viewHolder.rbt_primarylocation.setTag(position);
    }

    return convertView;
}

}

When you store the viewHolderHeader in the tag you use this line of code:

 convertView.setTag(viewHolderHeader);

but when you get the viewHolderHeader back, you use a key to return it:

 viewHolderHeader = (ViewHolderHeader) convertView.getTag(R.layout.section_header);

I'm not sure these would match up, you need to use the same key in the first line:

 convertView.setTag(R.layout.section_header, viewHolderHeader);

https://developer.android.com/reference/android/view/View.html#getTag(int)

When the re-cycled view is with wrong type, view is also need to be inflated. Also try to combine the 2 types of ViewHolder into 1.

Try this:

public class ABCArrayAdapter extends ArrayAdapter<ABCModel> {

Context context;
ArrayList<ABCModel> selectedlocation;
public ArrayList<String> locationid = new ArrayList<String>();
public String primarylocation = "null";
int clickedRadioButtonPosition = -1;
//  ViewHolder viewHolder = null;
//  ViewHolderHeader viewHolderHeader = null;

public ABCArrayAdapter(Context context, int resourceId, ArrayList<ABCModel> selectedlocation) {
    super(context, resourceId, selectedlocation);
    this.context = context;
    this.selectedlocation = new ArrayList<ABCModel>();
    this.selectedlocation.addAll(selectedlocation);
}

public int getCount() {
    return this.selectedlocation.size();
}

public ABCModel getItem(int position) {
    return this.selectedlocation.get(position);
}

public long getItemId(int position) {
    return this.selectedlocation.get(position).hashCode();
}

// View lookup cache
private class ViewHolder {
    // For header view, use name as txt_header
    TextView name;

    TextView home;
    CheckBox chk_locationlist;
    RadioButton rbt_primarylocation;
    // save ViewType
    int viewType;
}

//  private static class ViewHolderHeader {
//      TextView txt_header;
//  }

public int getViewTypeCount() {
    return 2;
}

@Override
public int getItemViewType(int position) {
    if (getItem(position).isSectionHeader()) {
        return 0;
    } else {
        return 1;
    }
}

@Override
public View getView(final int position, View convertView, ViewGroup parent) {

    ViewHolder viewHolder;
    LayoutInflater mInflater = (LayoutInflater) context
            .getSystemService(Activity.LAYOUT_INFLATER_SERVICE);

    int type = getItemViewType(position);

    if (type == 0) {
        if (convertView == null) {
            convertView = mInflater.inflate(R.layout.section_header, null);
//              viewHolderHeader = new ViewHolderHeader();
//              viewHolderHeader.txt_header = (TextView) convertView.findViewById(R.id.section_header);
//              convertView.setTag(viewHolderHeader);
//              viewHolder = null;
            viewHolder = new ViewHolder();
            viewHolder.name = (TextView) convertView.findViewById(R.id.section_header);
            convertView.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) convertView.getTag();

            // If the recycled view is of wrong type, inflate new view
            if(viewHolder.viewType == 1){
                convertView = mInflater.inflate(R.layout.section_header, null);
                viewHolder = new ViewHolder();
                viewHolder.name = (TextView) convertView.findViewById(R.id.section_header);
                convertView.setTag(viewHolder);
            }
        }
    } else if (type == 1) {
        if (convertView == null) {

            // If there's no view to re-use, inflate a brand new view for row
            convertView = mInflater.inflate(R.layout.ABC_list_item_name, null);
            viewHolder = new ViewHolder();

            viewHolder.name = (TextView) convertView.findViewById(R.id.txt_ha_name);
            viewHolder.home = (TextView) convertView.findViewById(R.id.txt_ha_town);
            viewHolder.chk_locationlist = (CheckBox) convertView.findViewById(R.id.chk_box_ha_list);
            viewHolder.rbt_primarylocation = (RadioButton) convertView.findViewById(R.id.rbtn_pl);
            viewHolder.rbt_primarylocation.setPaintFlags(viewHolder.rbt_primarylocation.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);

            viewHolder.chk_locationlist.setOnClickListener(new View.OnClickListener() {
                public void onClick(View v) {
                    CheckBox cb = (CheckBox) v;
                    View finalConvertView = (View) v.getParent();
                    RadioButton rbt_primarylocation = (RadioButton) finalConvertView.findViewById(R.id.rbtn_pl);
                    int pos = (Integer) v.getTag();
                    ABCModel _state = (ABCModel) selectedlocation.get(pos);

                    if (cb.isChecked()) {
                        _state.setSelected(cb.isChecked());
                        // Update ArrayList
                        selectedlocation.remove(pos);
                        selectedlocation.add(pos, _state);

                        locationid.add(_state.getId().toString());
                        rbt_primarylocation.setVisibility(View.VISIBLE);

                        if (locationid.size() == 1) {
                            rbt_primarylocation.setChecked(true);
                            primarylocation = _state.getId().toString();
                            rbt_primarylocation.setText("This is my primary location.");
                            rbt_primarylocation.setPaintFlags(0);
                            System.out.println("Primary Location---" + primarylocation);
                        }

                    } else {
                        _state.setSelected(false);
                        locationid.remove(_state.getId().toString());

                        // When unchecked the one with radio button selected
                        if (rbt_primarylocation.isChecked()) {
                            if (locationid.size() > 0) {
                                //rbt_primarylocation.setChecked(true);
                                rbt_primarylocation.setText("Make this my primary location.");
                                rbt_primarylocation.setPaintFlags(rbt_primarylocation.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);

                                primarylocation = "null";
                                Toast.makeText(
                                        v.getContext(),
                                        "Please select a Primary Location", Toast.LENGTH_LONG).show();
                            }
                        }

                        rbt_primarylocation.setVisibility(View.INVISIBLE);

                    }
                }
            });
            viewHolder.rbt_primarylocation.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    clickedRadioButtonPosition = (Integer) v.getTag();
                    ABCModel _state = (ABCModel) selectedlocation.get(clickedRadioButtonPosition);
                    primarylocation = _state.getId().toString();

                    ViewHolder finalViewHolder = (ViewHolder)(((View) v.getParent()).getTag());

                    finalViewHolder.rbt_primarylocation.setText("This is my primary location.");
                    finalViewHolder.rbt_primarylocation.setPaintFlags(0);
                    System.out.println("Primary Location---" + primarylocation);
                    notifyDataSetChanged();
                }
            });

            // Cache the viewHolder object inside the fresh view
            convertView.setTag(viewHolder);
//              viewHolderHeader = null;
        } else {
            // View is being recycled, retrieve the viewHolder object from tag
            viewHolder = (ViewHolder) convertView.getTag(R.layout.search_expand_item);

            // If the recycled view is of wrong type, inflate new view
            if(viewHolder.viewType == 0){
                convertView = mInflater.inflate(R.layout.ABC_list_item_name, null);
                viewHolder = new ViewHolder();

                viewHolder.name = (TextView) convertView.findViewById(R.id.txt_ha_name);
                viewHolder.home = (TextView) convertView.findViewById(R.id.txt_ha_town);
                viewHolder.chk_locationlist = (CheckBox) convertView.findViewById(R.id.chk_box_ha_list);
                viewHolder.rbt_primarylocation = (RadioButton) convertView.findViewById(R.id.rbtn_pl);
                viewHolder.rbt_primarylocation.setPaintFlags(viewHolder.rbt_primarylocation.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);

                viewHolder.chk_locationlist.setOnClickListener(new View.OnClickListener() {
                    public void onClick(View v) {
                        CheckBox cb = (CheckBox) v;
                        View finalConvertView = (View) v.getParent();
                        RadioButton rbt_primarylocation = (RadioButton) finalConvertView.findViewById(R.id.rbtn_pl);
                        int pos = (Integer) v.getTag();
                        ABCModel _state = (ABCModel) selectedlocation.get(pos);

                        if (cb.isChecked()) {
                            _state.setSelected(cb.isChecked());
                            // Update ArrayList
                            selectedlocation.remove(pos);
                            selectedlocation.add(pos, _state);

                            locationid.add(_state.getId().toString());
                            rbt_primarylocation.setVisibility(View.VISIBLE);

                            if (locationid.size() == 1) {
                                rbt_primarylocation.setChecked(true);
                                primarylocation = _state.getId().toString();
                                rbt_primarylocation.setText("This is my primary location.");
                                rbt_primarylocation.setPaintFlags(0);
                                System.out.println("Primary Location---" + primarylocation);
                            }

                        } else {
                            _state.setSelected(false);
                            locationid.remove(_state.getId().toString());

                            // When unchecked the one with radio button selected
                            if (rbt_primarylocation.isChecked()) {
                                if (locationid.size() > 0) {
                                    //rbt_primarylocation.setChecked(true);
                                    rbt_primarylocation.setText("Make this my primary location.");
                                    rbt_primarylocation.setPaintFlags(rbt_primarylocation.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);

                                    primarylocation = "null";
                                    Toast.makeText(
                                            v.getContext(),
                                            "Please select a Primary Location", Toast.LENGTH_LONG).show();
                                }
                            }

                            rbt_primarylocation.setVisibility(View.INVISIBLE);

                        }
                    }
                });
                viewHolder.rbt_primarylocation.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        clickedRadioButtonPosition = (Integer) v.getTag();
                        ABCModel _state = (ABCModel) selectedlocation.get(clickedRadioButtonPosition);
                        primarylocation = _state.getId().toString();

                        ViewHolder finalViewHolder = (ViewHolder)(((View) v.getParent()).getTag());

                        finalViewHolder.rbt_primarylocation.setText("This is my primary location.");
                        finalViewHolder.rbt_primarylocation.setPaintFlags(0);
                        System.out.println("Primary Location---" + primarylocation);
                        notifyDataSetChanged();
                    }
                });

                // Cache the viewHolder object inside the fresh view
                convertView.setTag(viewHolder);
            }
        }

    }

    if(type == 0)
    {
        ABCModel state = selectedlocation.get(position);
//          viewHolderHeader.txt_header.setText(state.getRegion());
        viewHolder.name.setText(state.getRegion());
    }else{
        ABCModel state = selectedlocation.get(position);
        viewHolder.name.setText(state.getName());
        viewHolder.home.setText(state.getAddress1() + "\r\n" + state.getCity() + ", " + state.getState() + " " + state.getZip());
        viewHolder.chk_locationlist.setChecked(state.isSelected());

        // Set views for view recycling on scrolling
        if (viewHolder.chk_locationlist.isChecked()) {
            viewHolder.rbt_primarylocation.setVisibility(View.VISIBLE);
        } else {
            viewHolder.rbt_primarylocation.setVisibility(View.INVISIBLE);
        }
        if (position == clickedRadioButtonPosition) {
            viewHolder.rbt_primarylocation.setChecked(true);
            viewHolder.rbt_primarylocation.setText("This is my primary location.");
            viewHolder.rbt_primarylocation.setPaintFlags(0);
        } else {
            viewHolder.rbt_primarylocation.setChecked(false);
            viewHolder.rbt_primarylocation.setText("Make this my primary location.");
            viewHolder.rbt_primarylocation.setPaintFlags(viewHolder.rbt_primarylocation.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
        }

        viewHolder.chk_locationlist.setTag(position);
        viewHolder.rbt_primarylocation.setTag(position);
    }

    return convertView;
}
}

The code is not tested. Hope this help!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM