setListAdapter not displaying

325 views Asked by At

I am trying to display set of fetch results as a list. Whenever I try to use dummy data, it's displayed correctly but when I change it to the data retrieved from the server nothing happens. I do not get any errors so that's very confusing

import java.util.ArrayList;

import org.json.JSONArray;
import org.json.JSONException;

import android.app.ListFragment;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;

public class BlogFragment extends ListFragment {

    String[] countries = new String[] {
        "India",
        "Pakistan",
        "Sri Lanka",
        "China",
        "Bangladesh",
        "Nepal",
        "Afghanistan",
        "North Korea",
        "South Korea",
        "Japan"
    };

    String [] titles ={};
    ArrayAdapter<String> adapter;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
        /** Creating an array adapter to store the list of countries **/
        new AsyncFetchData().execute();
        adapter = new ArrayAdapter<String>(inflater.getContext(), android.R.layout.simple_list_item_1,titles);

        return super.onCreateView(inflater, container, savedInstanceState);
    }

    private class AsyncFetchData extends AsyncTask
    {

        @Override
        protected Object doInBackground(Object... arg0) {


            JSONArray a = new JSONArray();
            ArrayList<String> aList = new ArrayList<String>();
            a = ServerAPI.getData();
            for (int i = 0; i < a.length(); i++) {
                String title = null;
                String content = null;
                try {
                    title = a.getJSONObject(i).getString("title");
                    content = a.getJSONObject(i).getString("content");
                    aList.add(title);
                } catch (JSONException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println(title);
//              System.out.println(content);
            }
            titles = aList.toArray(new String[aList.size()]);
            /** Setting the list adapter for the ListFragment */


            return null;
        }

        protected void onPostExecute(Object result) {
        // TODO Auto-generated method stub
        ArrayAdapter aa = new ArrayAdapter(getActivity().getBaseContext(), android.R.layout.simple_list_item_1, titles);
        aa.notifyDataSetChanged();  
        setListAdapter(aa); 
    }
    }
}

The string array countries is displayed correctly in the runOnUiThread method while titles does not. I check the data placed in titles string array and it's valid. Any idea why this is happening?

3

There are 3 answers

1
MysticMagicϡ On

The problem is:

Your adapter was already initialized with old set of data. So you are updating the underlying data, but adapter still holds the old data.

You need to update adapter with new data.

For that,

call

adapter.notifyDatasetChanged(); 

just before

setListAdapter(adapter);

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

0
greenapps On

First create a new adapter for the new titles and then set that adapter.

0
Mixaz On

There are few strange things I see in your code:

  1. In onCreateView you start new AsyncFetchData().execute(). It might be useful if wanted to download data for the current list item, for whole list it is made in other way (not inside onCreateView)

  2. I would expect onCreateView to create a new view instead of calling super.onCreateView, to get access to view elements (and fill them with downloaded data)

Standard pattern of ListFragment usage is:

public class MyListFragment extends ListFragment {

  @Override
  public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    String[] values = new String[] { "Android", "iPhone", "WindowsMobile",
        "Blackberry", "WebOS", "Ubuntu", "Windows7", "Max OS X",
        "Linux", "OS/2" };
    ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(),
        android.R.layout.simple_list_item_1, values);
    setListAdapter(adapter);
  }

}

If you want to update the list with downloaded data from AsyncTask, then you should update data in the array which the adapter refers to, without recreating the adapter itself. And call adapter.notifyDataChanged() as soon as the new data ready, on UI thread (like you are trying to do, but usually it is made in AsyncTask.postExecute() which was specially designed for this case.

I guess you do not have any data to show before they will be downloaded. Then you do not need to show the empty list, may be some sort of progress bar. It may be a TextView "Please wait, downloading..." When the download finishes, you'll replace the TextView with ListView (or fragment), may be with an animation. In this way the ListView will be created at once and you do not need to care about its async downloading.

ADDED: About progress bar - it will be better to use standard one:

ProgressDialog progress = new ProgressDialog(this);
progress.setMessage("Please wait, downloading...");
progress.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progress.setIndeterminate(true);

AsyncTask.onPreExecute() is a good place for it. Do not forget to dismiss it in onPostExecute()