2

I've been reading lots of questions and answers on Stckoverflow. But still can't find when do I actually use adapter.notifyDataSetChanged.

Previously, after adding all items into an ArrayList, I did

adapter = new ListViewAdapter(MainActivity.this, menuItems); lv.setAdapter(adapter); adapter.notifyDataSetChanged();

It had no crashes AT ALL on my phone, emulators and only a minority had this crash.

Then, I did.

adapter = new ListViewAdapter(MainActivity.this, menuItems); adapter.notifyDataSetChanged(); lv.setAdapter(adapter);

Same result as above.

But I hate crashes. I hate that people downloading my apps have FCs. And then I tried this, knowing that maybe the adapter have to refresh, THEN I can set a new one.

adapter.notifyDataSetChanged(); adapter = new ListViewAdapter(MainActivity.this, menuItems); lv.setAdapter(adapter);

And the result is that after scrolling down a few pages [never-ending listview], it crashes on my phone.

Maybe it's me who don't understand. But when do we ACTUALLY use adapter.notifyDataSetChanged?

And if it helps, this is my full code.

`

private class firstLoad extends AsyncTask<Void, Void, Void> {
        @Override
        protected void onPreExecute() {
            setSupportProgressBarIndeterminateVisibility(true);
            if (lv.getVisibility() == View.VISIBLE) {
                lv.setVisibility(View.GONE);
            }
        }

    protected Void doInBackground(Void... unused) {
        try {
                xml = parser.getXmlFromUrl(getURLFromXML + "main.php");
            doc = parser.getDomElement(xml);
            NodeList nl = doc.getElementsByTagName(Consts.KEY_ITEM);
            for (int i = 0; i < nl.getLength(); i++) {
                HashMap<String, String> map = new HashMap<String, String>();
                Element e = (Element) nl.item(i);
                map.put(Consts.KEY_NAME,
                        parser.getValue(e, Consts.KEY_NAME));
                map.put(Consts.KEY_DATE,
                        parser.getValue(e, Consts.KEY_DATE));
                menuItems.add(map);
            }
        } catch (Exception e) {
            Log.e(TAG, "Error loading first page", e);
        }
        return (null);
    }

    protected void onPostExecute(Void unused) {
        setSupportProgressBarIndeterminateVisibility(false);
        MainActivity.this.runOnUiThread(new Runnable() {
            public void run() {
                    //adapter.notifyDataSetChanged();
                    adapter = new ListViewAdapter(MainActivity.this,
                            menuItems);
                    lv.setAdapter(adapter);
                    lv.setVisibility(View.VISIBLE);
                    loadingMore = false;
                    lv.setSelectionFromTop(0, 0);
                    lv.setOnScrollListener(new OnScrollListener() {

                        public void onScrollStateChanged(AbsListView view,
                                int scrollState) {
                        }

                        public void onScroll(AbsListView view,
                                int firstVisibleItem, int visibleItemCount,
                                int totalItemCount) {
                            int lastInScreen = firstVisibleItem
                                    + visibleItemCount;
                            if ((lastInScreen == totalItemCount)
                                    && !(loadingMore)) {
                                new loadMoreListView().execute();
                            }
                        }
                    });

            }
        });

    }
}`

Thanks in advance.

TNR
  • 5,839
  • 3
  • 33
  • 62
MrYanDao
  • 1,253
  • 1
  • 15
  • 27
  • This answer may help you http://stackoverflow.com/questions/12229817/android-how-does-notifydatasetchanged-method-and-listviews-work – CodeShadow Feb 05 '15 at 07:58

3 Answers3

5

But when do we ACTUALLY use adapter.notifyDataSetChanged?

Use this method when your data has changed. Such as adding or deleting items from your Array or wherever your adapter is getting the data. When the Adapter is created you don't need/want to call this as the data has not been changed and will give you trouble. So you only want to call it when data has been added/deleted/modified and you haven't made any other calls that would redraw the ListView

codeMagic
  • 44,549
  • 13
  • 77
  • 93
  • My application is a never-ending listview. When I FIRST call my adapter, I did not set `lv.noitifyDataSetChanged();`, but what about when I scroll down? I have a similar Asynctask that adds data to the ArrayList and setting the adapter again. And that's where the problem occurs. Where and when do I set notifyDataSetChanged? – MrYanDao May 12 '13 at 03:50
  • I don't understand why you need to call an `AsyncTask` when you scroll. When the `Actviity` is first created, you should load your `list` and set your `adapter`. `ListView` will take care of loading the data in `getView()` as long as you have it set up correctly – codeMagic May 12 '13 at 03:53
  • Because it's a never-ending listview? When I scroll down TILL the END of the FIRST data in the adapter, it loads data from the internet in AsyncTask and set a new adapter? I'm talking about loading like Page 2 onwards. Take for example Twitter app. After scrolling down to the bottom, it grabs data from the internet and set a new adapter. And from there, where and when do I `notifyDataSetChanged`? Hope you understand. – MrYanDao May 12 '13 at 03:56
  • Ok, I see what you are saying. But you still shouldn't have to call it unless data on the page you are currently viewing is changed which it probably wouldn't be unless you have it set up to automatically refresh or allow the user to refresh the "page". I hope that makes sense. – codeMagic May 12 '13 at 04:05
  • Yes. I've set up a `setOnScrollListener` on the ListView so when the user reached to the bottom of the listview. It loads more data. So when do I actually call `notifyDataSetChanged()`? After setting adapter or? Thanks again. – MrYanDao May 12 '13 at 04:11
  • Right, and you shouldn't have to when you call `setAdapter()`. Are you having any problems after you call that if you don't call `notifyDataSetChanged()`? – codeMagic May 12 '13 at 04:14
  • But I have to `setAdapter()` when I append more values into the ArrayList and set the adapter again right? Or do I have to just `notifyDataSetChanged()` when loading more items? – MrYanDao May 12 '13 at 04:26
  • 1
    Once you set the `Adapter` to the list then you should be able to just call `notifyDataSetChanged()` and not have to call `setAdapter()` – codeMagic May 12 '13 at 04:31
  • Woah! I just tried that and it works! Is it supposed to work like this? So I have to just `setAdapter()` ONCE when load? And when it loads more I just have to `notifyDataSetChanged()` that's all? – MrYanDao May 12 '13 at 04:34
  • That is correct. There may be cases where you need to call `setAdapter()` again such as using a different `Array` or such but this is probably rare and I've never had to – codeMagic May 12 '13 at 04:36
1

When you set your adapter, you don't explicitly have to call adapter.notifyDataSetChanged(). It does it on its own. The only place you need to call is when the data actually changes but your adapter is not changing.

Hope this helps.

Aswin Rajendiran
  • 3,399
  • 1
  • 21
  • 18
  • My application is a never-ending listview. When I FIRST call my adapter, I did not set `lv.noitifyDataSetChanged();`, but what about when I scroll down? I have a similar Asynctask that adds data to the ArrayList and setting the adapter again. And that's where the problem occurs. Where and when do I set notifyDataSetChanged? – MrYanDao May 12 '13 at 03:50
  • If you set the adapter again, then you don't have to call notifyDataSetChanged again. – Aswin Rajendiran May 12 '13 at 05:14
0

Try to use TabHost wit fragment, and use tabs at the place of Buttons. It may be solve your problem.

Amit Jayaswal
  • 1,725
  • 2
  • 19
  • 36