Home > Blockchain >  Possible error in the Android docs code example or am I missing something?
Possible error in the Android docs code example or am I missing something?

Time:12-29

I was looking into how to create a multichoice checkbox dialog while working in Android Studio and naturally started by looking at the android developers page and came across this guide. The code example they show is this:

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    selectedItems = new ArrayList();  // Where we track the selected items
    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
    // Set the dialog title
    builder.setTitle(R.string.pick_toppings)
    // Specify the list array, the items to be selected by default (null for none),
    // and the listener through which to receive callbacks when items are selected
           .setMultiChoiceItems(R.array.toppings, null,
                      new DialogInterface.OnMultiChoiceClickListener() {
               @Override
               public void onClick(DialogInterface dialog, int which,
                       boolean isChecked) {
                   if (isChecked) {
                       // If the user checked the item, add it to the selected items
                       selectedItems.add(which);
                   } else if (selectedItems.contains(which)) {
                       // Else, if the item is already in the array, remove it
                       selectedItems.remove(which);
                   }
               }
           })
    // Set the action buttons
           .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
               @Override
               public void onClick(DialogInterface dialog, int id) {
                   // User clicked OK, so save the selectedItems results somewhere
                   // or return them to the component that opened the dialog
                   ...
               }
           })
           .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
               @Override
               public void onClick(DialogInterface dialog, int id) {
                   ...
               }
           });

    return builder.create();
}

Now what Im interested in looking at is this:

.setMultiChoiceItems(R.array.toppings, null,
                      new DialogInterface.OnMultiChoiceClickListener() {
               @Override
               public void onClick(DialogInterface dialog, int which,
                       boolean isChecked) {
                   if (isChecked) {
                       // If the user checked the item, add it to the selected items
                       selectedItems.add(which);
                   } else if (selectedItems.contains(which)) {
                       // Else, if the item is already in the array, remove it
                       selectedItems.remove(which);
                   }
               }
           })

Now I am missing something here or is there a mistake in the code here? What I mean is wouldn't the call to remove() in selectedItems.remove(which) interpret which as an int rather than an Object and thus remove the element at the position specified by the int stored in which rather than removing the actual int from the array? This is what I assumed would happen when I read the code and also what did happen for me when I tried to run the code leading to an IndexOutOfBoundsError.

However as the code comes from a resource that Google itself provides I feel like its likely that it must be me that is missing something. If that is the case what am I missing? If that isn't the case and there is in fact an error in the code then I apologise as the topic no longer seems relevant for stackoverflow.

When it comes to how to solve the issue Im encountering that isn't an issue as I realise that I can simply do something like selectedItems.remove((Integer) which) or selectedItems.remove(Integer.valueOf(which)). I am simply bewildered as to what is happening.

CodePudding user response:

Your diagnosis is correct. Given two overloads List.remove(int) and List.remove(Object) and a call with an int argument, the Java compiler will statically resolve the call to the first overload rather than the second one1. But the semantics of this context require the second overload; i.e. removal by value rather than by position.

It's a bug in the documentation. Report it through the normal channels ...


1 - This is specified in JLS 15.12. This part of the spec is complicated and technical, but the gist is that the compiler first looks for overloads that match the argument types strictly; i.e. without boxing or unboxing. It only considers non-strict matches if there are no strict ones. Informally, int -> int is a "closer match" than int -> Object which involves boxing to Integer followed by reference widening to Object.

  • Related