BaseAdapter.notifyDatasetChanged() not updating the ListView

Go To StackoverFlow.com

10

why does my listview not update when I call notifyDatasetChanged() ? the only way I can make it display the data is, to call setAdatper() on the ListView again... i also tried to call it via runOnUIThread() which did not change anything

The Adapter

/**
 * Adapter to provide the data for the online scores
 * 
 * @author soh#zolex
 *
 */
public class OnlineScoresAdapter extends BaseAdapter {

    private Context context;
    private List<ScoreItem> scores = new ArrayList<ScoreItem>();

    /**
     * Constructor
     * 
     * @param Context context
     */
    public OnlineScoresAdapter(Context context) {

        this.context = context;
    }

    /**
     * Add an item to the adapter
     * 
     * @param item
     */
    public void addItem(ScoreItem item) {

        this.scores.add(item);
    }

    /**
     * Get the number of scores
     * 
     * @return int
     */
    public int getCount() {

        return this.scores.size();
    }

    /**
     * Get a score item
     * 
     * @param int pos
     * @return Object
     */
    public Object getItem(int pos) {

        return this.scores.get(pos);
    }

    /**
     * Get the id of a score
     * 
     * @param in pos
     * @retrn long
     */
    public long getItemId(int pos) {

        return 0;
    }

    /**
     * Get the type of an item view
     * 
     * @param int pos
     * @return int
     */
    public int getItemViewType(int arg0) {

        return arg0;
    }

    /**
     * Create the view for a single list item.
     * Load it from an xml layout.
     * 
     * @param int pos
     * @param View view
     * @param ViewGroup viewGroup
     * @return View
     */
    public View getView(int pos, View view, ViewGroup group) {

        LinearLayout layout;
        if (view == null) {

            layout = (LinearLayout)View.inflate(this.context, R.layout.scoreitem, null);

        } else {

            layout = (LinearLayout)view;
        }

        TextView position = (TextView)layout.findViewById(R.id.pos);
        TextView time = (TextView)layout.findViewById(R.id.time);
        TextView player = (TextView)layout.findViewById(R.id.player);
        TextView createdAt = (TextView)layout.findViewById(R.id.created_at);

        ScoreItem item = (ScoreItem)getItem(pos);
        player.setText(item.player);
        position.setText(String.valueOf(new Integer(item.position)) + ".");
        time.setText(String.format("%.4f", item.time));
        createdAt.setText(item.created_at);

        return layout;
    }

    /**
     * Get the number of different views
     * 
     * @return int
     */
    public int getViewTypeCount() {

        return 1;
    }

    /**
     * Return wheather the items have stable IDs or not
     * 
     * @return boolean
     */
    public boolean hasStableIds() {

        return false;
    }

    /**
     * Return wheather the list is empty or not
     * 
     * @return boolean
     */
    public boolean isEmpty() {

        return this.scores.size() == 0;
    }

    /**
     * No need of a data observer
     * 
     * @param DataSetObserver arg0
     * @return void
     */
    public void registerDataSetObserver(DataSetObserver arg0) {

    }

    /**
     * No need of a data observer
     * 
     * @param DataSetObserver arg0
     * @return void
     */
    public void unregisterDataSetObserver(DataSetObserver arg0) {

    }

    /**
     * No item should be selectable
     * 
     * @return boolean
     */
    public boolean areAllItemsEnabled() {

        return false;
    }

    /**
     * No item should be selectable
     * 
     * @param int pos
     * @return boolean
     */
    public boolean isEnabled(int arg0) {

        return false;
    }
}

The Activity

The XMLLoaderThread works fine, it's just notifyDatasetChanged seems to do nothing...

/**
 * Obtain and display the online scores
 * 
 * @author soh#zolex
 *
 */
public class OnlineScoresDetails extends ListActivity {

    WakeLock wakeLock;
    OnlineScoresAdapter adapter;
    boolean isLoading = false;
    int chunkLimit = 50;
    int chunkOffset = 0;

    @Override
    /**
     * Load the scores and initialize the pager and adapter
     * 
     * @param Bundle savedInstanceState
     */
    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
        this.wakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, "racesow");

        adapter = new OnlineScoresAdapter(this);
        setListAdapter(adapter);
        this.loadData();

        setContentView(R.layout.listview);
        getListView().setOnScrollListener(new OnScrollListener() {

            public void onScrollStateChanged(AbsListView view, int scrollState) {

            }

            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

                if (totalItemCount > 0 && visibleItemCount > 0 && firstVisibleItem + visibleItemCount >= totalItemCount) {

                    if (!isLoading) {

                        loadData();
                    }
                }
            }
        });
    }

    public void loadData() {

        final ProgressDialog pd = new ProgressDialog(OnlineScoresDetails.this);
        pd.setProgressStyle(ProgressDialog.STYLE_SPINNER);
        pd.setMessage("Obtaining scores...");
        pd.setCancelable(false);
        pd.show();

        isLoading = true;
        String mapName = getIntent().getStringExtra("map");
        XMLLoaderThread t = new XMLLoaderThread("http://racesow2d.warsow-race.net/map_positions.php?name=" + mapName + "&offset=" + this.chunkOffset + "&limit=" + this.chunkLimit, new Handler() {

            @Override
            public void handleMessage(Message msg) {

                switch (msg.what) {

                    // network error
                    case 0:
                        new AlertDialog.Builder(OnlineScoresDetails.this)
                            .setMessage("Could not obtain the maplist.\nCheck your network connection and try again.")
                            .setNeutralButton("OK", new OnClickListener() {

                                public void onClick(DialogInterface arg0, int arg1) {

                                    finish();
                                    overridePendingTransition(0, 0);
                                }
                            })
                            .show();
                        break;

                    // maplist received
                    case 1:
                        pd.dismiss();
                        InputStream xmlStream;
                        try {

                            xmlStream = new ByteArrayInputStream(msg.getData().getString("xml").getBytes("UTF-8"));
                            XMLParser parser = new XMLParser();
                            parser.read(xmlStream);

                            NodeList positions = parser.doc.getElementsByTagName("position");
                            int numPositions = positions.getLength();
                            for (int i = 0; i < numPositions; i++) {

                                Element position = (Element)positions.item(i);

                                ScoreItem score = new ScoreItem();
                                score.position = Integer.parseInt(parser.getValue(position, "no"));
                                score.player = parser.getValue(position, "player");
                                score.time = Float.parseFloat(parser.getValue(position, "time"));
                                score.created_at = parser.getValue(position, "created_at");

                                adapter.addItem(score);
                            }

                            adapter.notifyDataSetChanged();


                            chunkOffset += chunkLimit;
                            isLoading = false;

                        } catch (UnsupportedEncodingException e) {

                            new AlertDialog.Builder(OnlineScoresDetails.this)
                                .setMessage("Internal error: " + e.getMessage())
                                .setNeutralButton("OK", null)
                                .show();
                        }

                        break;
                }

                pd.dismiss();
            }
        });

        t.start();
    }

    /**
     * Acquire the wakelock on resume
     */
    public void onResume() {

        super.onResume();
        this.wakeLock.acquire();
    }

    /**
     * Release the wakelock when leaving the activity
     */
    public void onDestroy() {

        super.onDestroy();
        this.wakeLock.release();
    }

    /**
     * Disable animations when leaving the activity
     */
    public void onBackPressed() {

        this.finish();
        this.overridePendingTransition(0, 0);
    }
}
2012-04-05 15:28
by Andreas Linden
are you gettin an error message? also, did you check the value of numPositions before the for loop - Mark Pazon 2012-04-05 15:54
as i said, when i call setListAdapter() instead of notifiyDataSetChanged() the data appears... but then the list starts at the top and not where the user has scrolled to. so the data is there but the view is not update - Andreas Linden 2012-04-05 16:07
also tried it with an AsyncTask now, same result, no update of the view, only if i call setAdapter() agai - Andreas Linden 2012-04-05 16:07
Try to put adapter.notifyDataSetChanged(); line in loop - SweetWisher ツ 2013-10-23 08:12


6

A bit late but the answer is you should not implement

public void registerDataSetObserver(DataSetObserver arg0) {

}

public void unregisterDataSetObserver(DataSetObserver arg0) {

}

I just had a simple BaseAdapter working as intended, who stop working after adding those two methods. I asume that "someone" need to observe data changes and such :)

2013-04-30 20:24
by Asincrono


1

I am not really sure if your implementation of Custom BaseAdapter is correct.

Try changing

public long getItemId(int pos) {
    return 0;
}

to

 public long getItemId(int pos) {
    return pos;
 }

I also found this simple tutorial that might be helpful on how to implement BaseAdapter. After you got this down, you can try notifyDataSetChanged() again.

2012-04-06 02:19
by Mark Pazon
that did not hel - Andreas Linden 2012-04-14 10:37
this is what worked for me. I did a bit of research, and it looks like without providing valid itemId, BaseAdapter wont have a DataSetObserver without which, obviously, your adapter will not be notified of data changes - Sergey Maslov 2015-10-21 11:40


0

You should call adapter.notifyDataSetChanged() after every manipulation of your dataset. If you're adding items in a batch (e.g. a for-loop), this means you have to put .notifyDataSetChanged in your loop, like so:

for(int i = 0; i < numPositions; i++) {
    ....
    adapter.addItem(score);
    adapter.notifyDataSetChanged();
}

Make sure you call adapter.notifyDataSetChanged() from your UI-thread.

If you rather update your adapter once, store your ScoreItems in an ArrayList and after the loop call:

adapter.addAll(scoreList);
adapter.notifyDataSetChanged();

But then again, as far as I'm aware there's really no reason to do that.

2012-04-05 16:15
by Reinier
I also tried to call notify in the loop but it didnt change anything - Andreas Linden 2012-04-05 16:28
It looks like you're not calling it from the UI Thread. Make sure to call .notifyDataSetChanged() from your UI-thread e.g. by using runOnuiThread(new Runnable() { ... }) - Reinier 2012-04-05 17:00
also doesn't change anythin - Andreas Linden 2012-04-14 10:42
I also see this from time to time and the only way os to set the adapter again. This may cause a flicker of the view but at least it works - slott 2013-04-23 09:16
In that case the cause is most likely you didn't implement getItemId(int position) properly; getItemId(int) should return the ID of the item at position in your dataset. If the return value of getItemId(int) doesn't change while a new item has taken an old position in your dataset (e.g. because you set getItemId(int) to return position), the system won't see that your dataset has changed (because all the ID's are still in the same order as previously). Update getItemId(int) to return your item's unique identifier and it should work - Reinier 2013-05-15 08:39
Ads