我有一个ListView和一个BaseAdapter。在适配器中,我显示7种不同类型的视图。
当我运行项目时,所有的ListView和其中的视图都正确加载时,此图像显示。但是当我向下滚动列表视图时,我得到一个错误。
当我运行项目时,一切都很好显示,但是当我向下滚动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中显示的下一个按钮。
答案 0 :(得分:2)
您需要重写getViewTypeCount
来指示不同类型的视图的数量,否则,当它尝试重用视图时,它可能是不同类型的(因此convertView
不为null,但是ViewHolder
的类型错误)。它适用于第一个视图屏幕,因为convertView
对所有视图都是空的。
@Override
public int getViewTypeCount() {
return 6; // question says 7 view types but I counted 6
}
有关更多详细信息,请参见here。