It is given: a certain ArrayList with several objects of the same type, and an Adapter inherited from the ArrayAdapter, which presents these objects in a ListView.

Required: implement the update of a specific object, and accordingly update the corresponding View in the ArrayAdapter.

I did it like this:

arrayList.get(...).setMyProperty(...); adapter.NotifyDataSetChanged(); 

True, at first for some reason it did not work - View was not updated.

I thought that this is due to the fact that the adapter somehow compares objects, and I don’t have the correct comparison mechanism in them , because it doesn’t detect changes and does not update the corresponding View, and I need to implement something like hashCode in these objects , equals or comparable , then it will work correctly.

But I found the solution easier - just add the following to my ArrayAdapter implementation, such as it is missing:

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

As a result, the element really began to be updated. But after all, I still do not have a comparison mechanism, which means that when updating one element, getView () will be stupidly called for all elements.

I understand correctly that this will be so? (I'll check it later, just for now the element is only 1)

If I understand correctly, is this normal, or is it possible (necessary) to somehow implement a comparison so that getView is called only for views of updated objects?

Also, as I understand it, there is a ViewHolder pattern, which in this case allows you to get rid of inflate () and findViewById () with each update of each element, thereby, though not abandon getView for all elements, but optimize it.
But isn't it better not to call getView at all once again, but only for updated items?

    2 answers 2

    I thought that this is because the adapter somehow compares the objects, and I don’t have the correct comparison mechanism in them

    No, the adapter does not compare objects.

    and you need to implement something like hashCode , equals or comparable in these objects, then it will work correctly

    In order for the adapter to see the changes and update the data, these methods and this interface are not needed.

    But after all, I still do not have a comparison mechanism, which means that when updating one element, getView() will be stupidly called for all elements.

    Yes, it will, and this is not due to the fact that you do not have a comparison mechanism.

    If I understand correctly, is this normal, or is it possible (necessary) to somehow implement a comparison so that getView called only for views of updated objects?

    The comparison is not necessary to implement. You can update certain elements in ListView , but you have to do it manually: check if the element with a given index is visible, if yes, then get the corresponding View and change it manually (as Romain Guy said on Google I / O in 2010, this method is most effective for updating only certain View ).

    But isn't it better not to call getView at all once again, but only for updated items?

    Of course better.

    In general, I advise you to switch from ListView to RecyclerView , since the latter is more flexible, optimized and easier to customize (and ViewHolder use of ViewHolder ).

    In particular, the RecyclerView.Adapter has a method notifyItemChanged(int position) , the call of which entails redrawing only a specific View .

      The adapter's notifyDataSetChenged() method simply re- notifyDataSetChenged() all the data from the array (or another source of the list) and fills the list with this new data. It doesn’t compare anything with anything and doesn’t single out the changes that have taken place. It is not effective for such a simple task.

      The getCount() method is called by the adapter when it needs to know how many items will be displayed in the list. When you make changes, the list may increase (elements added) or decrease (deleted), so when the list is notified, the actual size of the data store is displayed each time for display. At the same time, if the getCount() method is not overridden, then the adapter displays nothing, because it does not know about the new size.

      getView() it possible (necessary) to somehow implement a comparison so that getView() called only for updated objects?

      It is completely unnecessary and even harmful, because in fact it will only slow down the work, and not speed it up. The fact is that the adapter does not store all the representations of the elements, but creates them as needed (only currently visible on the screen) - this is much more efficient than the method you invented, since only a few elements are created each time, instead of calculating the changes for the entire set data, which may be hundreds and thousands of items. In addition, other optimizations are also used to speed up the output - the ViewHolder pattern that stores widget references and ConvertView , which stores the updated layout of one element (for the list it often remains unchanged and there is no need to calculate it each time from XML).
      It is also worth considering the fact that items in the list are constantly re-used and "disappearing" from above appear below (when scrolling down, of course). Thus, the adapter actually works with a unit number of items (up to 8 pieces usually) and substitutes the same ones, making only changes to the content of the widgets, in accordance with the position in the data storage.

      stupidly getView() will be called for all elements.

      Yes, this is true, but for all elements visible on the screen at the moment and no more.

      But isn't it better not to call getView() at all, but only for updated elements?

      It would be better in theory if there was an effective mechanism for determining such elements, but the ListView widget does not have such functionality. Such functionality exists in the more complex and similar RecyclerView widget - methods notifyItemChanged() (updated one item) and notifyItemRangeChanged() (updated range of items), but the person manages these widgets (indicates where the changes occurred happened, usually), not the adapter. Although, by and large, this is done more to apply animation to the updating of elements than for some significant optimization. I repeat, for the adapter this job is absolutely not effective and will slow down its work greatly.