Android. How does notifyDataSetChanged() method and ListViews work?
Asked Answered
C

4

63

I am trying to understand the ListView concept and how it works and I'm trying to create my own adapter which extends BaseAdapter. For ArrayAdapter for instance, there is the notifyDataSetChanged() method which should be called after you've updated the array list which holds all your data, in order to refresh the ListView.

But I am creating my own subclass of BaseAdapter. That method is not available to me, or is it? How do i implement this method? Basically, what does that method do exactly, maybe I'll understand then.

In case of the ArrayAdapter i'm guessing it looks at what position the ListView is currently displaying and it checks if it's the same one as in the ArrayList after it was updated? Or...

It says that the method:

Notifies the attached observers that the underlying data has been changed and any View reflecting the data set should refresh itself.

But how exactly does it refresh itself?

Can someone explain please?

Copulation answered 1/9, 2012 at 17:21 Comment(0)
C
196

I've figured it out. I couldn't understand how the hell the adapter started and how did it know where to get the data from. When i extended the BaseAdapter class, in the constructor of that class I initialized the list of items that I wanted to see in the ListView. But I couldn't figure out how these values would be used and when.

So here's the thing !!! :

In the BaseAdapter there are some methods that need to be overridden. Among these, there is getCount().

When the ListView is created and whatnot, it calls getCount(). If this returns a value different than 0 (I returned the size of the ArrayList which I've previously initialized in the constructor), then it calls getView() enough times to fill the screen with items. For instance, I initialized the ArrayList with 20 items. Because only 8 items initially fit on the screen, getView() was called 8 times, each time asking for the position it required for me to return (more precisely it wanted to know how the row would look like in the list on that specific position, what data it needed to contain). If I scroll down the list, getView() gets called over and over again, 'til I hit the end of the list, in my case 20 items / rows.

What notifyDataSetChanged() does is ... when called, it looks at what items are displayed on the screen at the moment of its call (more precisely which row indexes ) and calls getView() with those positions.

i.e. if you're displaying the first 8 items in the list (so those are the ones visible on the screen) and you add another item between the 2nd and 3rd item in the list and you call notifyDataSetChanged() then getView() is called 8 times, with positions starting from 0 and ending with 7, and because in the getView() method you're getting data from the ArrayList then it will automatically return the new item inserted in the list alongside 7 out of the previous 8 (7 and not 8 because the last item went one position down, so it is not visible anymore), and the ListView will redraw, or whatever, with these items.

Also, important to specify is that if you've implemented getView() correctly, you'll end up recycling the items (the objects) already displayed (instead of creating new ones). See this video at around 12:00 minutes to see the correct way to implement getView()

I've figured all this out by placing calls to LogCat in every method and following what was going on.

P.S. This example also helped me a lot to understand.

UPDATE

Nowadays ListViews are not really used anymore. Android came out with the RecyclerView which does the recycling of the views for you, but knowing the basics of a ListView helps with understanding the RecyclerView.

Here's a link for reference: https://developer.android.com/guide/topics/ui/layout/recyclerview

Copulation answered 2/9, 2012 at 8:34 Comment(3)
Well, it's a good explanation. But we thought that you know how ListView works.Ureter
Because only 8 items initially fit on the screen, getView() was called 8 times. That is not always true as the adapter can call some additional getViews for measuring.Jeanene
How do I link the adapter to the ListView? I had a very similar question, that I have been stuck on for the last 3 hours! https://mcmap.net/q/119178/-how-to-update-the-listview-according-to-arraylist/…Maraud
U
13

BaseAdapter can be "observed" by other classes. When you're calling method of ListView setAdapter() it's calls registerDataSetObserver of adapter. So, adapter knows who are interested in new data.

You can check the source of BaseAdapter here. It's pretty small.

notifyDataSetChanged is available for you and you're basically shouldn't override it (because it's not doing anything special, so you can just reuse it in your own class).

Ureter answered 1/9, 2012 at 17:52 Comment(1)
How do I link my adapter to my arraylist?Maraud
S
10

Suppose your ListView displays some data stored in an ArrayList.

After you change the contents of the ArrayList, you need to tell the list that the source of the data had changed and it needs to redraw itself to show the new data.

So, that is where notifyDatasetChanged() comes in. It tells the ListView that the data has been modified; and to show the new data, the ListView must be redrawn.

Shrader answered 1/9, 2012 at 17:33 Comment(5)
Well, that's what i'm not getting. Where do i tell the adapter that I'm using a certain ArrayList to store the data? When I use the ArrayAdapter yes, i send the reference to an ArrayList when I link the adapter to the ListView, but how about when i extend the BaseAdapter? How does it know to take the values from my ArrayList?Copulation
So, when notifyDatasetChanged() is called i force the ListView to call the getView() method for the current items displayed in the screen?Copulation
Oh. So when notifyDatasetChanged() is called, it doesn't call getView() for the current position displayed in the ListView, thus refreshing the currrent items displayed in case we've modified exactly those ?Copulation
Erm, are you referring to me ? I dont think I made any previous comments on this post and deleted them. Anyway, try grabbing a tutorial from the web about custom listView and see the steps they have followed there ?Shrader
And when you call notifyDatasetChanged() , it redraws the whole list once again and not just any particular view. Actually, invalidate() also does something similar to this.Shrader
E
0

As you are extending BaseAdapter for your own for creating a subclass, you will get notifyDataSetChanged() method as well.

Elenaelenchus answered 8/12, 2016 at 9:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.