6

I'm trying to split off some AsyncTask classes into public (separate) functions so that I'm not having to rewrite so much code. I almost have it, except for one very important aspect. The AsyncTask function compiles an ArrayList by making php calls to a server. When this list is complete, I need to update a spinner on the main UI thread. I found a really nice answer here but I'm having a little difficulty making it work.

Here is a scaled down version of what I have: (note that at this point, all I am trying to do is to call a Toast message to prove that the round trip is working)

Here is the calling Activity:

public class MyActivity extends Activity implements OnTaskCompleted {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        sg_list = new ArrayList<String>();
        new GetSuperGroups(UpdateAffiliationsPreferences.this, context, "Retrieving Group List...").execute();
    }

    public void onTaskCompleted(ArrayList<String> list) {
        Toast.makeText(getApplicationContext(), "hello from async", Toast.LENGTH_SHORT).show();
    }

}

This is the interface:

public interface OnTaskCompleted {
    void onTaskCompleted(ArrayList<String> list);
}

And finally, here is the AsyncTask. Note that it is a Public class:

public class GetSuperGroups extends AsyncTask<String, String, ArrayList<String>> {

    private Activity activity;
    private Context context;
    private String progressMsg;
    private ProgressDialog pDialog;
    private ArrayList<String> sg_list;
    private OnTaskCompleted listener;

    public GetSuperGroups(Activity activity, Context context, String progressMsg) {
        this.activity = activity;
        this.context = context;
        this.progressMsg = progressMsg;
    }

    public void setSuperGroupList (OnTaskCompleted listener){
        this.listener = listener;
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        pDialog = new ProgressDialog(context);
        pDialog.setMessage(progressMsg);
        pDialog.setIndeterminate(false);
        pDialog.setCancelable(true);
        pDialog.show();
    }

    @Override
    protected ArrayList<String> doInBackground(String... args) {

        sg_list = new ArrayList<String>();
        //make a php call, compile the ArrayList    
        return sg_list;
    }

    protected void onPostExecute(ArrayList<String> sg_list) {
        pDialog.dismiss();
        //this next line causes a null pointer error
        //note that I am throwing away the array list for now
        //all I want to do is prove that I can call the Toast back in the calling Activity
        listener.onTaskCompleted(new ArrayList<String>());
    }
}
Community
  • 1
  • 1
AndroidDev
  • 20,466
  • 42
  • 148
  • 239

4 Answers4

7

Just add OnTaskCompleted listener parameter in your asyncTask constructor GetSuperGroups. Then pass this when you execute your asyncTask.

public class MyActivity extends Activity implements OnTaskCompleted {

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            sg_list = new ArrayList<String>();
            new GetSuperGroups(UpdateAffiliationsPreferences.this, context, "Retrieving Group List...", this).execute();
        }

        public void onTaskCompleted(ArrayList<String> list) {
            Toast.makeText(getApplicationContext(), "hello from async", Toast.LENGTH_SHORT).show();
        }

    }

and

  public class GetSuperGroups extends AsyncTask<String, String, ArrayList<String>> {

        private Activity activity;
        private Context context;
        private String progressMsg;
        private ProgressDialog pDialog;
        private ArrayList<String> sg_list;
        private OnTaskCompleted listener;

        public GetSuperGroups(Activity activity, Context context, String progressMsg, OnTaskCompleted listener) {
            this.activity = activity;
            this.context = context;
            this.progressMsg = progressMsg;
            this.listener = listener;
        }
Vipul Purohit
  • 9,807
  • 6
  • 53
  • 76
  • I think this is going to leak memory, because you pass the instance of the activity to the task and then if the activity rotates or for some reason has to be destroyed it wont be GCed until the task finishes... – Feras Oct 25 '14 at 04:56
2

You never call setSuperGroupList() so the listener remains null. Better to put listener into the constructor of your task.

Alexander Kulyakhtin
  • 47,782
  • 38
  • 107
  • 158
  • Thanks. My head is spinning. I can't figure out where to call that from. – AndroidDev Aug 28 '13 at 04:37
  • It doesn't really matter because it doesn't start any action. So, adding listener as a constructor parameter seems fine because it guarantees the listener will be set. You may want to consider using android.os.Handler instead of this your own listening interface. – Alexander Kulyakhtin Aug 28 '13 at 05:28
0

you fallowing the right path. But I'm not clear the problem in the onPostExecute(..) method. Is it about null pDialog or null sg_list. If problem in the sg_list please check is the php method working or not? may be problem with the permission in manifest file foe php service.
So my advice to check your method first on UI thread. Then change it to do in background thread.
Also you can put the toast at onPostExecute method to check the sg_list content.

ANjaNA
  • 1,404
  • 2
  • 16
  • 29
  • It's not the sg_list. Note that although I build it and ultimately intend to use it, for now, I'm not even referencing it. It's the listener that is null, but I don't know how to instantiate it. – AndroidDev Aug 28 '13 at 04:58
0

You need to add a function setListener:

public class TaskComplete {
    public OnTaskCompleted onTaskListenerComplete;

    public interface OnTaskCompleted {
        void onTaskCompleted(ArrayList<String> list);
    }

    public void setOnTaskComplete(OnTaskCompleted onTaskListenerComplete){
        this.onTaskListenerComplete = onTaskListenerComplete;
    }
}

And in Activity, define and set it:

public class MyActivity extends Activity implements OnTaskCompleted {
    public TaskComplete task;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        sg_list = new ArrayList<String>();
        task.setOnTaskComplete(this);
        new GetSuperGroups(UpdateAffiliationsPreferences.this, context, "Retrieving Group List...").execute();
    }

    public void onTaskCompleted(ArrayList<String> list) {
        Toast.makeText(getApplicationContext(), "hello from async", Toast.LENGTH_SHORT).show();
    }

}

In AsyncTask:

protected void onPostExecute(ArrayList<String> sg_list) {
    pDialog.dismiss();
    //this next line causes a null pointer error
    //note that I am throwing away the array list for now
    //all I want to do is prove that I can call the Toast back in the calling Activity
    activity.onTaskCompleted(new ArrayList<String>());
}

Hope it useful.

yagi_chan
  • 13
  • 6