0

I am using Android Studio to create an app using java but I am fairly new to it, most of my experience is in Visual Studio with C# and Winforms.

Currently I have a ListView with CheckBoxes inside of it and I'm using an ArrayAdapter to sync the list.

    ArrayList<String> items = new ArrayList<>();
    items.add("Alpha");
    items.add("Bravo");
    items.add("Charlie");
    items.add("Delta");

    ArrayAdapter<String> adapter = new ArrayAdapter<>(this, R.layout.row_layout, R.id.chkText, items);
    lv.setAdapter(adapter);

    // Test
    Toast.makeText(getApplicationContext(), "Count " + lv.getAdapter().getCount(), Toast.LENGTH_LONG).show();
    for (int j = 1; j < lv.getAdapter().getCount(); j++)
    {
        CheckBox cb = (CheckBox) lv.getAdapter().getItem(j);
        cb.setChecked(true);
    }

The getCount() does return the proper value but the app crashes when it tries to check the boxes. All the answers I found online seem way overcomplicated for such a simple task. Is there nice and easy way I can check boxes "Bravo" and "Delta" when the app loads for example?

1 Answers1

1

The true way to get at that one Checkbox requires you to dig into the ListView children, not the adapter itself.

android - listview get item view by position

Basically, the adapter only stores the data and "binds" the data to the view. The Adapter doesn't actually hold the view information itself.

  • lv.getAdapter() returns you a generic, untyped Adapter<?>

  • When you do lv.getAdapter().getItem(j), that returns you an Object, which can only be cast as a String because you have used an ArrayAdapter<String>.


The better way to approach this problem is if you make a custom class that extends ArrayAdapter<String>, and then you would be able to write your own fields to store a boolean list called mChecked here, for example, and a method to update that list.

In more detail, here's the idea

private List<Boolean> mChecked = new ArrayList<>();

public void setChecked(int position, boolean checked) {
  mChecked.set(position, checked); // Might throw out of bounds exception! 
  notifyDataSetChanged(); // Need to refresh the adapter
}

public boolean isChecked(int position) {
  return mChecked.get(position);
}

@Override
public void getView( ... ) {
    ...

    View rowView = ... ;

    TextView tv = (TextView) rowView.findViewById(R.id.chkText);
    tv.setText(getItem(position));
    Checkbox cb = (Checkbox) rowView.findViewById(R.id.checkbox);
    cb.setChecked(isChecked(position));
}

The getView() method of that adapter class would control when you've checked a box or not via checkBox.setChecked(isChecked(position));

In the end, you won't be setting the boxes when the app loads, but rather when you initialize the adapter.

OneCricketeer
  • 126,858
  • 14
  • 92
  • 185
  • I think I'm getting confused on what the View is for. In your first approach, that's awesome if I can get a View but what do I do with it? I can't seem to spot a getChild() or getItem() method. With the second approach, say I did create a custom class, how could I get setChecked() to work if I cannot do so with the current adapter? Sorry, I am rather new to a lot of this. Everything seems backwards. – Walter Bishop Aug 24 '17 at 21:34
  • 1
    `lv.getChild()`. You would get some `View` object which you then must `findViewById` for whatever checkbox ID you set within `row_layout.xml`. For the second option, see this for an example https://guides.codepath.com/android/Using-an-ArrayAdapter-with-ListView – OneCricketeer Aug 24 '17 at 22:06