7

I need to populate a long ListView with data from the network, say 2-3 seconds for the entire data collection. I don't want the user to see a loading Dialog and wait for the entire list download. Instead I want to update the ListView as each item becomes available.

  • How can I do this?
  • I presume by adding to the ArrayAdapter from an AsyncTask with OnProgressUpdate?
  • Do I have to issue a notifyDatasetChanged() after each added row?
  • Is the Fragment/Loader approach better?
  • Is there a tutorial or API demo reference implementation for a case like this?

It's not important that the data be fetched entirely before the Activity dies (ie Service is unnecessary)

Jeff Axelrod
  • 27,676
  • 31
  • 147
  • 246
  • use a ListFragment from support library, look at samples, cache your data in a private field then call notifyDatasetChanged when a new element is ready – sherpya Aug 16 '12 at 21:24
  • Define "slowly". Are you fetching at a large interval or is it a large download itself? – telkins Aug 16 '12 at 21:24

3 Answers3

3

The best approach I've seen so far is from CommonsWare. It was found in this related answer.

Apparently there is nothing wrong with calling add without notifyDatasetChanged().

public class AsyncDemo extends ListActivity {
  private static final String[] items={"lorem", "ipsum", "dolor",
                                      "sit", "amet", "consectetuer",
                                      "adipiscing", "elit", "morbi",
                                      "vel", "ligula", "vitae",
                                      "arcu", "aliquet", "mollis",
                                      "etiam", "vel", "erat",
                                      "placerat", "ante",
                                      "porttitor", "sodales",
                                      "pellentesque", "augue",
                                      "purus"};
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    setListAdapter(new ArrayAdapter<String>(this,
                        android.R.layout.simple_list_item_1,
                        new ArrayList<String>()));

    new AddStringTask().execute();
  }

  class AddStringTask extends AsyncTask<Void, String, Void> {
    @Override
    protected Void doInBackground(Void... unused) {
      for (String item : items) {
        publishProgress(item);
        SystemClock.sleep(200);
      }

      return(null);
    }

    @Override
    protected void onProgressUpdate(String... item) {
      ((ArrayAdapter<String>)getListAdapter()).add(item[0]);
    }

    @Override
    protected void onPostExecute(Void unused) {
      Toast
        .makeText(AsyncDemo.this, "Done!", Toast.LENGTH_SHORT)
        .show();
    }
  }
}
Community
  • 1
  • 1
Jeff Axelrod
  • 27,676
  • 31
  • 147
  • 246
0

I think you can start here: http://www.vogella.com/articles/AndroidPerformance/article.html

So, You need to make an asynchronous call to a server for data. Or you could run a background task for that.

You can Google for AsyncTask or search here on stackoverflow that. Here is example: AsyncTask Android example

Community
  • 1
  • 1
Guntis
  • 496
  • 1
  • 5
  • 19
  • Which of these two links shows how to add individual rows asynchronously, as opposed waiting until all rows have been populated? I don't see anything about either of these links that answers the question. – Jeff Axelrod Aug 17 '12 at 02:04
  • In links is information, how to do a job in background thread. And there is some info, how to update GUI. You cannot update GUI elements from background thread. In second link is example with TextView. – Guntis Aug 17 '12 at 06:14
0

Just to make sure, ListView's adapter nor its underlying data can't be updated from thread other than the UI thread. Updates must be executed on the main application thread. Non-UI threads can use post() or runOnUiThread(), etc. to invoke an update.

Calling notifyDatasetChanged() just like that is rather not good practice, it should be called by the Adapter itself or the object changing the data.

As network operation is slow, consider if it woudn't be desirable to store downloaded data in database. Than you end with implementing some sort of CursorAdapter, best with the use of Loader, so that when you update database in your working thread, ListView will be notified automatically about the changes.

biegleux
  • 13,179
  • 11
  • 45
  • 52
  • I'm asking specifically about displaying the data and updating the `ListView` as it becomes available, not gathering it upfront and storing it. – Jeff Axelrod Aug 17 '12 at 02:07
  • When your item becomes available you insert it into `database` and `ListView` will be notified about the change, in this case that the mentioned item was added, unless you are not inserting all items in one transaction. – biegleux Aug 17 '12 at 04:09