Listview显示不同类型的行

时间:2018-07-10 22:49:48

标签: java android listview baseadapter

我有一个ListView和一个BaseAdapter。在适配器中,我显示7种不同类型的视图。

当我运行项目时,所有的ListView和其中的视图都正确加载时,此图像显示。但是当我向下滚动列表视图时,我得到一个错误。 Show all good

当我运行项目时,一切都很好显示,但是当我向下滚动ListView并抛出错误时,问题就解决了:

E/AndroidRuntime: FATAL EXCEPTION: main
                  Process: com.panelapps.mapen, PID: 25969
                  java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference
                      at com.panelapps.uiformcreator.UIFormAdapter.getView(UIFormAdapter.java:234)
                      at android.widget.AbsListView.obtainView(AbsListView.java:2413)
                      at android.widget.ListView.makeAndAddView(ListView.java:1975)
                      at android.widget.ListView.fillDown(ListView.java:709)
                      at android.widget.ListView.fillGap(ListView.java:673)
                      at android.widget.AbsListView.trackMotionScroll(AbsListView.java:5475)
                      at android.widget.ListView.trackMotionScroll(ListView.java:1894)
                      at android.widget.AbsListView.scrollIfNeeded(AbsListView.java:3708)
                      at android.widget.AbsListView.onTouchMove(AbsListView.java:4157)
                      at android.widget.AbsListView.onTouchEvent(AbsListView.java:3964)
                      at android.view.View.dispatchTouchEvent(View.java:9957)
                      at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2705)
                      at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2386)
                      at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2711)
                      at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2400)
                      at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2711)
                      at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2400)
                      at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2711)
                      at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2400)
                      at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2711)
                      at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2400)
                      at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2711)
                      at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2400)
                      at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2711)
                      at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2400)
                      at com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:416)
                      at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1834)
                      at android.app.Activity.dispatchTouchEvent(Activity.java:3154)
                      at android.support.v7.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:68)
                      at com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:378)
                      at android.view.View.dispatchPointerEvent(View.java:10177)
                      at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:4650)
                      at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4518)
                      at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3969)
                      at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4022)
                      at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3988)
                      at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3996)
                      at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3969)
                      at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4022)
                      at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3988)
                      at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:4117)
                      at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3996)
                      at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:4174)
                      at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3969)
                      at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4022)
                      at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3988)
                      at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3996)
                      at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3969)
                      at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:6459)
                      at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:6433)
                      at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:6394)
E/AndroidRuntime:     at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:6593)
                      at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:185)
                      at android.view.InputEventReceiver.nativeConsumeBatchedInputEvents(Native Method)
                      at android.view.InputEventReceiver.consumeBatchedInputEvents(InputEventReceiver.java:176)
                      at android.view.ViewRootImpl.doConsumeBatchedInput(ViewRootImpl.java:6541)
                      at android.view.ViewRootImpl$ConsumeBatchedInputRunnable.run(ViewRootImpl.java:6616)
                      at android.view.Choreographer$CallbackRecord.run(Choreographer.java:871)
                      at android.view.Choreographer.doCallbacks(Choreographer.java:683)
                      at android.view.Choreographer.doFrame(Choreographer.java:613)
                      at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:857)
                      at android.os.Handler.handleCallback(Handler.java:751)
                      at android.os.Handler.dispatchMessage(Handler.java:95)
                      at android.os.Looper.loop(Looper.java:154)
                      at android.app.ActivityThread.main(ActivityThread.java:6316)
                      at java.lang.reflect.Method.invoke(Native Method)
                      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:872)
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:762)

我的BaseAdapter代码是:

public class UIFormAdapter extends BaseAdapter {
    CallbackFormAdapter callback;

    public interface CallbackFormAdapter {
        void getData();
    }

    Context context;
    ArrayList<Form> UIForm = new ArrayList<>();
    private LayoutInflater inflater;

    //functino
    Function function = new Function();

    public UIFormAdapter(Context context, ArrayList<Section> form, CallbackFormAdapter callback) {
        this.context = context;
        this.callback = callback;

        //do the form
        for (int i = 0; i<form.size(); i++){
            //add the separator
            UIForm.add(new Form("", form.get(i).getText(), 0));

            //go over the forms inside
            for (int j = 0; j<form.get(i).getForms().size(); j++){
                UIForm.add(form.get(i).getForms().get(j));
            }
        }
    }

    @Override
    public int getCount() {
        return UIForm.size();
    }

    @Override
    public Object getItem(int position) {
        return UIForm.get(position);
    }

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

    @Override
    public int getItemViewType(int position) {
        return UIForm.get(position).getType();
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        //holder
        Holder viewHolder = null;

        //get the data
        Form data = UIForm.get(position);

        //if inflater inicialize
        if (inflater == null)
            inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        if (convertView == null){
            //get the tipe
            int type = getItemViewType(position);

            //switch type
            switch (type){
                case 0:
                    convertView = inflater.inflate(R.layout.separator, parent, false);
                    //set the holder
                    viewHolder = new Holder(convertView, type);

                    viewHolder.txtSection.setText(data.getText());
                    break;
                case Types.EditText:
                    convertView = inflater.inflate(R.layout.text_edit, parent, false);
                    //set the holder
                    viewHolder = new Holder(convertView, type);

                    viewHolder.etEditText.setHint(data.getText());
                    break;
                case Types.Single_Spinner:
                    convertView = inflater.inflate(R.layout.single_spinner, parent, false);
                    //set the holder
                    viewHolder = new Holder(convertView, type);

                    viewHolder.txtSingleSpinner.setText(data.getText());
                    break;
                case Types.Spinner:
                    convertView = inflater.inflate(R.layout.spinner, parent, false);
                    //set the holder
                    viewHolder = new Holder(convertView, type);

                    viewHolder.spinner.setAdapter(data.getAdapter());
                    viewHolder.spinner.setBackgroundColor(Color.LTGRAY);
                    break;
                case Types.Date:
                    convertView = inflater.inflate(R.layout.button, parent, false);
                    //set the holder
                    viewHolder = new Holder(convertView, type);

                    viewHolder.button.setText(data.getText());
                    viewHolder.button.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            Calendar mcurrentDate = Calendar.getInstance();
                            final int[] mYear = {mcurrentDate.get(Calendar.YEAR)};
                            final int[] mMonth = {mcurrentDate.get(Calendar.MONTH)};
                            final int[] mDay = {mcurrentDate.get(Calendar.DAY_OF_MONTH)};

                            DatePickerDialog mDatePicker = new DatePickerDialog(context, new DatePickerDialog.OnDateSetListener() {
                                public void onDateSet(DatePicker datepicker, int selectedyear, int selectedmonth, int selectedday) {
                                    Calendar myCalendar = Calendar.getInstance();
                                    myCalendar.set(Calendar.YEAR, selectedyear);
                                    myCalendar.set(Calendar.MONTH, selectedmonth);
                                    myCalendar.set(Calendar.DAY_OF_MONTH, selectedday);

                                    //date
                                    String myDate = function.dateToString(myCalendar.getTime(), "dd/MM/yyyy");
                                    //viewHolder.button.setText(myDate);

                                    mDay[0] = selectedday;
                                    mMonth[0] = selectedmonth;
                                    mYear[0] = selectedyear;
                                }
                            }, mYear[0], mMonth[0], mDay[0]);
                            //mDatePicker.setTitle("Select date");
                            mDatePicker.show();
                        }
                    });
                    break;
                case Types.Button:
                    convertView = inflater.inflate(R.layout.button, parent, false);
                    //set the holder
                    viewHolder = new Holder(convertView, type);

                    viewHolder.button.setText(data.getText());
                    viewHolder.button.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            callback.getData();
                        }
                    });
                    break;
            }

            //set the holder
            convertView.setTag(viewHolder);

        }else{ //else customview null

            //get the viewHolder
            viewHolder = (Holder)convertView.getTag();

            //get the tipe
            int type = UIForm.get(position).getType();

            switch (type){
                case 0:
                    viewHolder.txtSection.setText(data.getText());
                    break;
                case Types.EditText:
                    viewHolder.etEditText.setHint(data.getText());
                    break;
                case Types.Single_Spinner:
                    viewHolder.txtSingleSpinner.setText(data.getText());
                    break;
                case Types.Spinner:
                    viewHolder.spinner.setAdapter(data.getAdapter());
                    viewHolder.spinner.setBackgroundColor(Color.LTGRAY);
                    break;
                case Types.Date:
                    viewHolder.button.setText(data.getText());
                    viewHolder.button.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            Calendar mcurrentDate = Calendar.getInstance();
                            final int[] mYear = {mcurrentDate.get(Calendar.YEAR)};
                            final int[] mMonth = {mcurrentDate.get(Calendar.MONTH)};
                            final int[] mDay = {mcurrentDate.get(Calendar.DAY_OF_MONTH)};

                            DatePickerDialog mDatePicker = new DatePickerDialog(context, new DatePickerDialog.OnDateSetListener() {
                                public void onDateSet(DatePicker datepicker, int selectedyear, int selectedmonth, int selectedday) {
                                    Calendar myCalendar = Calendar.getInstance();
                                    myCalendar.set(Calendar.YEAR, selectedyear);
                                    myCalendar.set(Calendar.MONTH, selectedmonth);
                                    myCalendar.set(Calendar.DAY_OF_MONTH, selectedday);

                                    //date
                                    String myDate = function.dateToString(myCalendar.getTime(), "dd/MM/yyyy");
                                    //viewHolder.button.setText(myDate);

                                    mDay[0] = selectedday;
                                    mMonth[0] = selectedmonth;
                                    mYear[0] = selectedyear;
                                }
                            }, mYear[0], mMonth[0], mDay[0]);
                            //mDatePicker.setTitle("Select date");
                            mDatePicker.show();
                        }
                    });
                    break;
                case Types.Button:
                    viewHolder.button.setText(data.getText());
                    viewHolder.button.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            callback.getData();
                        }
                    });
                    break;
            }
        }

        //return the view
        return convertView;
    }

    //CREATE THE HOLDERS
    private class Holder{
        EditText etEditText;
        TextView txtSection;
        MaterialSpinner spinner;
        TextView txtSingleSpinner;
        Button button;
        public Holder(View v, int type) {
            switch (type){
                case Types.EditText:
                    this.etEditText = v.findViewById(R.id.etEditText);
                    break;
                case Types.Single_Spinner:
                    this.txtSingleSpinner = v.findViewById(R.id.txtSingleSpinner);
                    break;
                case 0:
                    this.txtSection = v.findViewById(R.id.txtSeparator);
                    break;
                case Types.Spinner:
                    this.spinner = v.findViewById(R.id.spinner);
                    break;
                case Types.Button:
                    this.button = v.findViewById(R.id.button);
                    break;
                case Types.Date:
                    this.button = v.findViewById(R.id.button);
                    break;
            }

        }
    }
}

错误显示我在下一行(viewHolder.button.setText ...):

case Types.Button:
                    viewHolder.button.setText(data.getText());

此按钮是要在ListView中显示的下一个按钮。

1 个答案:

答案 0 :(得分:2)

您需要重写getViewTypeCount来指示不同类型的视图的数量,否则,当它尝试重用视图时,它可能是不同类型的(因此convertView不为null,但是ViewHolder的类型错误)。它适用于第一个视图屏幕,因为convertView对所有视图都是空的。

@Override
public int getViewTypeCount() {
    return 6; // question says 7 view types but I counted 6
}

有关更多详细信息,请参见here