turtleboy
turtleboy

Reputation: 7572

ArrayList not populated correctly from AsyncTask

I've an app that populates an ArrayList from a webservice. The webservice is called from an AsyncTask. The ArrayList is populated when i test it in the onPostExecute. The ArrayList is defined as an instance variable. Why when AsyncTask finishes is the arrayList populated but when i test the instance variable itself after, it's null. It seems like Async is not setting the values properly.

Once Async has finished i am passing the ArrayList to an arrayAdapter, but my listView is empty.

Tests: in onPostExecute

 Log.e(TAG, "array from WS = " + array.size());  // returns 4

tests: in onCreate

 Log.e(TAG, "checking to see if array is null " + array.size()); // returns 0



 package com.carefreegroup;

 public class GetRotaDetails extends NfcBaseActivity implements OnItemClickListener
 {
ArrayList<ArrayList<String>> array;
MySimpleArrayAdapter arrayAdapter;
Intent intent;
private static final String TAG = GetRotaDetails.class.getSimpleName();
ListView listView;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    array = new  ArrayList<ArrayList<String>>();
    nfcscannerapplication = (NfcScannerApplication) getApplication();
    intent = this.getIntent();
    setContentView(R.layout.getrotadetailslayout);
    listView = (ListView) findViewById(R.id.getrotadetailslistview);

    //set titlebar to carer's name
    Cursor cursorCarerName = nfcscannerapplication.loginValidate.queryAllFromCarer();
    cursorCarerName.moveToLast();
    String carerTitleName = cursorCarerName.getString(cursorCarerName
            .getColumnIndex(LoginValidate.C_CARER_NAME));
    setTitle(carerTitleName + " is currently logged in");

    callID = intent.getStringExtra("callIDExtra");
    Log.e(TAG, "callID = " + callID);
    String[] params = { callID };
    AsyncGetRotaDetails agrd = new AsyncGetRotaDetails();
    agrd.execute(params);

    Log.e(TAG, "checking to see if array is null " + array.size());
    if (arrayAdapter == null){
        MySimpleArrayAdapter arrayAdapter = new MySimpleArrayAdapter(this, array);
        listView.setAdapter(arrayAdapter);
    }
    listView.setAdapter(arrayAdapter);
    listView.setOnItemClickListener(this);


}// end of onCreate

@Override
protected void onResume() {


    super.onResume();
}


private class AsyncGetRotaDetails extends AsyncTask<String, Void, String> {

    ProgressDialog progressDialog;
    String rotaDetails = null;

    @Override
    protected void onPreExecute() {
        progressDialog = ProgressDialog
                .show(GetRotaDetails.this, "Connecting to Server",
                        " retrieving rota details...", true);

    };

    @Override
    protected String doInBackground(String... params) { 

        try {
            Log.e(TAG, "inside doInBackground");

            rotaDetails = nfcscannerapplication.loginWebservice.getRotaDetail(params[0]);

        } catch (Exception e) {

            e.printStackTrace();

        }
        return rotaDetails;

    }

    @Override
    protected void onPostExecute(String xmlResult) {
        super.onPostExecute(xmlResult);
        if (progressDialog != null)
            progressDialog.dismiss();

        if (rotaDetails != null) {



            RetrieveExtraDetails red = new RetrieveExtraDetails();
           array = red.getExtraDetails(xmlResult);
            Log.e(TAG, "array from WS = " + array.size());

        } else {

            AlertDialog alertDialog = new AlertDialog.Builder(
                    GetRotaDetails.this).create();
            alertDialog.setTitle("Signal/Server Test");
            alertDialog.setMessage("No Phone Signal or Server Problem");

            alertDialog.setButton("OK",
                    new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog,
                                int which) {

                            onStart();
                        }
                    });

            alertDialog.show();

        }

    }// end of postExecute

}//end of Async

private class MySimpleArrayAdapter extends ArrayAdapter<String> {



    private final Context context;
    private final ArrayList<?> list;

    public MySimpleArrayAdapter(Context context, ArrayList<?> list) {

        super(context, R.layout.getrotadetailsrow);
        Log.e(TAG, "inside adapter constructor");
        this.context = context;
        this.list = list;


    }// end of constructor

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        LayoutInflater inflater = (LayoutInflater) context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        View rowView = inflater.inflate(R.layout.getrotadetailsrow, parent,
                false);

        TextView recTypeID = (TextView) rowView
                .findViewById(R.id.rectypeid);

        TextView recType = (TextView) rowView
                .findViewById(R.id.rectype);

        TextView name = (TextView) rowView
                .findViewById(R.id.name);

        TextView relationship = (TextView) rowView
                .findViewById(R.id.relationship);

        TextView address = (TextView) rowView
                .findViewById(R.id.address);

        TextView postCode = (TextView) rowView
                .findViewById(R.id.postcode);

        TextView telNo = (TextView) rowView
                .findViewById(R.id.telno);

        TextView keySafe = (TextView) rowView
                .findViewById(R.id.keysafe);

        TextView notes = (TextView) rowView
                .findViewById(R.id.notes);

        TextView meds = (TextView) rowView
                .findViewById(R.id.meds);

        String record = list.get(position).toString();

        Log.e(TAG, "record = " + record);
        recTypeID.setText(record);
        return super.getView(position, convertView, parent);
    }

}

@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    // TODO Auto-generated method stub

}

}

Upvotes: 0

Views: 1192

Answers (2)

Archie.bpgc
Archie.bpgc

Reputation: 24012

Make your ListView a field in the class and

Use

listView.setAdapter(arrayAdapter);
listView.setOnItemClickListener(this);

in onPostExecute(String result) method

but what i recommend is:

Use a loading spinner until the data is fetched and adapter is set, otherwise the behavior is the Activity shows up as empty and after 3-5 secs suddenly the whole list appears, which is a bad UX.

Usually we use Async Tasks without any loading spinner when the data being fetched is a small part of the UI, not a ListView which is a major component of the UI.

and don't check the length of the Array in onCreate(). It will always be 0. Because the code flow will be :

1. Create Array

2. Check its length in onCreate //0 as nothing is added yet

3. Add data to the Array in background

4. Check its length in onPostExecute(String result) //actual length

Upvotes: 0

Hassan Jawed
Hassan Jawed

Reputation: 1650

Actually, AsyncTask runs asynchronously it is not a blocking call (like execute() method returns, after the execution of onPostExecute() ). So you need to notify adapter in onPostExecute() when your data is downloaded. Its a multi-thread related problem,when execute() line executed a thread is created for AsyncTask and onCreate()'s execution move to next line, so simultaneously, doInBackground() and onCreate() will be executing in AsyncTask thread and UI thread respectively.

Upvotes: 2

Related Questions