daydreamer
daydreamer

Reputation: 91959

How to update ListView when data fetched from Server

This is how my ListFragment looks

public class TransactionListFragment extends ListFragment {
    private List<Transaction> mTransactions;


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getActivity().setTitle(R.string.transactions);
        mTransactions = Transactions.get(getActivity()).getTransactionsFromServer();

        ArrayAdapter<Transaction> adapter = new ArrayAdapter<>(getActivity(),
                android.R.layout.simple_list_item_1, mTransactions);
        setListAdapter(adapter);
    }
}

and Transactions.get(getActivity()).getTransactionsFromServer(); looks like

private void getTransactionsFromServer() {
        final String url = "myURL";
        RequestQueue queue = Volley.newRequestQueue(mContext);

        JsonObjectRequest request = new JsonObjectRequest(url, null,
                new Response.Listener<JSONObject>() {
                    @Override
                    public void onResponse(JSONObject response) {
                        Log.d("GET /Transactions:", response.toString());
                        generateTransactionCollectionFromResponse(response);
                    }
                }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                // handle error
            }
        }) {

            @Override
            public Map<String, String> getHeaders() throws AuthFailureError {
                HashMap<String, String> headers = new HashMap<>();
                headers.put("BEARER", "55b885274e7912280095ef80ac1cb937:d8922b44-75af-4810-a87e");
                return headers;
            }
        };

        queue.add(request);
    }

    private void generateTransactionCollectionFromResponse(JSONObject response) {
        JSONArray transactionsJson = null;
        try {
            transactionsJson = response.getJSONArray("transactions");
            Log.d("TransactionsJson:", transactionsJson.toString());

            for (int i = 0; i < transactionsJson.length(); i++) {
                JSONObject transactionJson = transactionsJson.getJSONObject(i);
                Transaction transaction = new Transaction(transactionJson.getString("id"), transactionJson.getString("name"));
                mTransactions.add(transaction);
            }

        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

Given that the task will happen asynchronously, the ListView would be empty initially.

Question

How do I indicate from my Transactions that reload the listView once I am done getting the results?

UPDATE
This is how Transaction is constructed

public class Transactions {
    private List<Transaction> mTransactions;
    private static Transactions sTransactions;
    private Context mContext;

    private Transactions(Context appContext) {
        mContext = appContext;
        mTransactions = new ArrayList<>();
    }

Question
How can I get Adapter or ListView?

Upvotes: 0

Views: 353

Answers (3)

Blackbelt
Blackbelt

Reputation: 157437

Quick easy/dirty solution could be to provide the ListView or the Adapter instance to the Transactions' constructor, and when you finish to parse the data, you can just call:

((BaseAdapter)mListView.getAdapter()).notifyDataSetChanged();

be aware that it has to run on the UI Thread.

Or,

Solution using LocalBroadcast

In your Fragment declare a BroadcastReceiver:

public class MyReceiver extends BroadcastReceiver {    
    @Override
    public void onReceive(Context context, Intent intent) {
    }
} 

and an action for the IntentFilter

public static final String DATA_READY_ACTION = "DATA_READY_ACTION";
public MyBrodacastReceiver mReceiver;

you need to register and unregister it. You could use onResume to register it, onPause to unregister it:

LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver, new IntentFilter(DATA_READY_ACTION));

to unregister

LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(mMessageReceiver);

in your Transactions class, when the new data is available, you can BroadCast the event "Data Ready"

  Intent intent = new Intent(TransactionFragment.DATA_READY_ACTION);
  LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);

When onReceive is fired you can update/refresh your ListView.

Solution using an Interface

Let the Activity implement an interface,

public interface DataListener {
    public void onDataReceived(List<Transaction> t);
}

and pass a reference of the class that implements this interface, e.g. your ListFragment, to your Transactions class. After you finish to fill up your data, you can notify through this object, the event. E.g

private final DataListener mListener;
private Transactions(Context appContext, DataListener listener) {
    mContext = appContext;
    mListener = listener;
    mTransactions = new ArrayList<>();           
}

//.. fetch data code
if (mListener != null) {
    mListener.onDataReceived(mTransactions);
} 

Please check for typo

Upvotes: 2

Nickolaus
Nickolaus

Reputation: 4835

You will need to create an AsyncTask which you can call in your on create method, then you can:

  • run Transactions.get(getActivity()).getTransactionsFromServer(); in the doInBackground method
    and
  • create/update your ListAdapter in the onPostExecute method

    Upvotes: 0

  • Matias Elorriaga
    Matias Elorriaga

    Reputation: 9150

    you should use adapter.notifyDataSetChanged(),

    more info: http://developer.android.com/reference/android/widget/BaseAdapter.html#notifyDataSetChanged()

    Upvotes: 0

    Related Questions