First of all, I know this issue is common on SO and elsewhere but I have spent hours trying to understand but cannot because the code is either not all there, the answer is too specific to the asker's implementation or they use another kind of adapter.
I have a custom ArrayAdapter that is attached to a ListView holding an ArrayList of SimplePlaces. SimplePlaces is a class I made that has a boolean with a getter and setter for whether that item is checked in the list. By default this would always be false.
The activity overrides the OnCheckChanged() method for the listener. When this is called I get the SimplePlace item from the list and call its setter, setChecked() to match boolean passed with the listener. Then I call notifyDataSetChanged() on the adapter.
Then in the ArrayAdapter I set the checkbox according to the getter for the SimplePlace item but this makes my app crash which happens on the line that says: int position = mListview.getPositionForView(buttonView);
inside onCheckedChanged() in the activity. The exception is: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.lang.Object.equals(java.lang.Object)' on a null object reference
If I do not try to set the checkbox then the app does not crash but checking an item repeats every 6 places in the listview, something to do with the recycling of views but I don't understand how exactly.
Please can someone explain what is happening here and how I modify my code to get this to work.
Activity to display the list
public class ChoosePlacesActivity extends AppCompatActivity
implements CompoundButton.OnCheckedChangeListener {
private final String LOG_TAG = Utility.APP_TAG +
ChoosePlacesActivity.class.getSimpleName();
ArrayList<SimplePlace> mSimplePlaces;
ListView mListview;
PlaceAdapter mAdapter;
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
Log.d(LOG_TAG, "onCheckedChanged");
int position = mListview.getPositionForView(buttonView);
if (position != ListView.INVALID_POSITION) {
SimplePlace place = mSimplePlaces.get(position);
place.setChecked(isChecked);
mAdapter.notifyDataSetChanged();
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
Log.d(LOG_TAG, "onCreate");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_choose_places);
// Get intent data
Intent intent = getIntent();
mSimplePlaces = (ArrayList<SimplePlace>)
intent.getSerializableExtra(Utility.PLACES_LIST);
// Find the list view and set up the adapter
mListview = (ListView) findViewById(R.id.listview_choose_places);
mAdapter = new PlaceAdapter(this, mSimplePlaces);
mListview.setAdapter(mAdapter);
mAdapter.addAll(mSimplePlaces);
}
}
Custom ArrayAdapter
public class PlaceAdapter extends ArrayAdapter<SimplePlace> {
private final String LOG_TAG = Utility.APP_TAG + PlaceAdapter.class.getSimpleName();
private Context context;
public PlaceAdapter(Context context, List<SimplePlace> places) {
super(context, R.layout.list_item_chooseplaces, places);
Log.d(LOG_TAG, "PlaceAdapter constructor");
this.context = context;
}
// Keep a reference to the view to avoid repeatedly calling findViewById()
private static class SimplePlaceHolder {
TextView name;
TextView type;
TextView distance;
CheckBox checkbox;
}
@NonNull
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Log.d(LOG_TAG, "getView");
SimplePlaceHolder holder = new SimplePlaceHolder();
// Inflate a new view, else recycle existing view
if (convertView == null) {
// Inflate a new view
LayoutInflater inflater = LayoutInflater.from(getContext());
convertView = inflater.inflate(R.layout.list_item_chooseplaces, parent, false);
// Find the views
holder.name = (TextView) convertView.findViewById(R.id.place_name);
holder.type = (TextView) convertView.findViewById(R.id.place_type);
holder.distance = (TextView) convertView.findViewById(R.id.place_distance);
holder.checkbox = (CheckBox) convertView.findViewById(R.id.place_checkbox);
convertView.setTag(holder);
// Click listener for list item
holder.checkbox.setOnCheckedChangeListener((ChoosePlacesActivity) context);
}
else {
// Get recycled ViewHolder object from tag
holder = (SimplePlaceHolder) convertView.getTag();
}
// Get the data item associated with the specified position in the data set
// and populate its values
SimplePlace place = getItem(position);
holder.name.setText(place.getName());
holder.type.setText(place.getType());
holder.distance.setText(String.valueOf(place.getDistance()) );
holder.checkbox.setChecked(place.isChecked() );
return convertView;
}
}
Aucun commentaire:
Enregistrer un commentaire