1

I'm new in Android. It's been a few weeks since I started working in this project. Reading the code already made I see a lot of private async tasks doing basically the same (call an API) So I wonder if there is a better solution, my idea would be create a public async task called ApiCaller which will return a JSONObject and the responsible for parsing the JSON would be the class calling the ApiCaller:

public class ApiCaller extends AsyncTask<String, String, JSONObject> {
    private static final String TAG = "ApiCall";
    private final String apiVersion = "v1";
    private final String baseURL = "http://my.api.com/";
    private String URL = null;

    /**
     * Generates the URL to call the API.
     *
     * @param params List with the params to call the API.
     */
    public ApiCaller(ArrayList<NameValuePair> params){
        String apiURL = this.baseURL + this.apiVersion + "/?";
        String paramsList = URLEncodedUtils.format(params, "utf-8");
        this.URL = apiURL + paramsList;
    }

    @Override
    protected JSONObject doInBackground(String ... params) {
        Log.i(TAG, "API:");
        Log.i(TAG, this.URL);
        JSONManager jParser = new JSONManager();
        JSONObject jsonObject = jParser.getJSONFromUrl(this.URL);
        return jsonObject;
}

Is there a way to return that JSONObject outside of the class so I can do something like:

JSONObject js = apiCaller.execute();

Or any other solution to avoid creating new asynctasks every time I need to call the API? With my current code I can't get it but I don't know what is missing? maybe returning it in onPostExecute?

Howli
  • 12,291
  • 19
  • 47
  • 72
dan87
  • 333
  • 3
  • 16

4 Answers4

1

Some time ago I've asked a similar question

One AsyncTask for multiple Activities

and the solution I found was answered in another question:

Common class for AsyncTask in Android?

Basically, what you need is an interface.

I've going to explain the basics, although you should check the original answer by @SirDarius.

You could create an interface like this:

interface AsyncTaskCompleteListener<T> {
   public void onTaskComplete(T result);
}

And implements that interface in all classes you need to use the AsynTask, then, in your generic Asynstask you need to have a callback AsyncTaskCompleteListener and call it from your onPostExecute

class B implements AsyncTaskCompleteListener<JSONObject> {

    public void onTaskComplete(JSONObject result) {
        // do whatever you need
    }

    public void launchTask(String url) {
        ApiCaller a = new ApiCaller(context, ArrayList<NameValuePair> params, this);
        ApiCaller.execute(url);
    }
}


class ApiCaller extends AsyncTask<String, Void, String> {
    private AsyncTaskCompleteListener<String> callback;

    public ApiCaller(Context context, ArrayList<NameValuePair> params, AsyncTaskCompleteListener<String> cb) {
        this.context = context;
        this.callback = cb;
    }

    protected void onPostExecute(String result) {
       finalResult = result;
       progressDialog.dismiss();
       System.out.println("on Post execute called");
       callback.onTaskComplete(result);
   }  
}
Community
  • 1
  • 1
Alejandro Alcalde
  • 5,990
  • 6
  • 39
  • 79
  • You already have onPostExecute() which is called on the UI thread, and whose parameter is generic, adding another interface to it has no further use. – ElDuderino May 26 '14 at 10:07
  • What he wants is generalize one Asyntask that is called from many Activities into one. Check http://stackoverflow.com/questions/3291490/common-class-for-asynctask-in-android/3291713#3291713 It makes sense have the interface – Alejandro Alcalde May 26 '14 at 10:10
  • But is there a way to get it from there? As far as I can see onPostExecute doesn't return anything – dan87 May 26 '14 at 10:17
  • It does not return anything, but because your call will be implementing the interface, you must have a method `public void onTaskComplete(T result)` in that class, where you will be receiving the result. I've updated my answer with an example. – Alejandro Alcalde May 26 '14 at 10:19
  • Of course onPostExecutes returns something, namely the exact same value like your Interface, in the same manner like an interface, as a callback. So yeah, you can either add an interface to the AsyncTask, or you override onPostExecute ... but both...why? – ElDuderino May 26 '14 at 14:05
1

because the asynchronous AsyncTask you can not call a method and obtain the return value;

you could use a AsyncTask on your inline code and get on postExecute your JSON object:

   new AsyncTask<String, String, JSONObject>(){
        @Override
        protected Void doInBackground(String... params) {

            //...
        }
        @Override
        protected void onPostExecute(JSONObject result) {

            // ...
        }
    }.execute(...);
0

You should implement a listener that you will pass to the async task. When the asynctask finishes, it will call the listener's method:

First, make a listener in a new java file:

public interface onTaskDoneListener{
    void onTaskDone(JSONObject result);
}

Pass it to your AsyncTask:

private onTaskDoneListner donelistner;

public ApiCaller(ArrayList<NameValuePair> params,onTaskDoneListener donelistener){
    String apiURL = this.baseURL + this.apiVersion + "/?";
    String paramsList = URLEncodedUtils.format(params, "utf-8");
    this.URL = apiURL + paramsList;
this.donelistener = donelistener;
}

Then, inside the onPostExecute method of your AsyncTask

this.donelistener.onTaskDone(result)

Usage:

new ApiCaller(params,new onTaskDoneListener() {
        @Override
        public void onTaskDone(JSONObject result) {
                   //This will be called when the asynctask finishes

                   //Do something with the result
});
0

Step 1 : Define an Interface.

public interface WebServiceListener {

        public void onLoginActionComplete (ArrayList<String> arrayList);
}

Step 2: Implement the WebServiceListener in your activity class.

public class LoginActivity extends Activity implements  WebServiceListener  {

@Override
        public void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.login);

   /* Calling the AsyncTask here,you could call in Login Button Click...   */

          WebServiceClient httpclient = new WebServiceClient(this);
                        httpclient.execute(ssoURLStr);

}



        @Override
        public void onLoginActionComplete  (ArrayList<String> arrayList) {
                // TODO Auto-generated method stub

         /*      Read the response     */
              String Response = arrayList.get(0);


        }


}

Step 3 : Your AsynTask class code here.

public class WebServiceClient extends
                AsyncTask<String, Integer, ArrayList<String>> {

 WebServiceListener listener = null;

/*  Constructor added  WebServiceListener here         */
public WebServiceClient ( WebServiceListener listener)
{
  this.listener  =  listener;
}


@Override
        protected ArrayList<String> doInBackground(String... params) {
                // TODO Auto-generated method stub

               ArrayList<String> arrayList = null;

            " write  your  http code here and get the response and update the    
            arrayList <String> here"

                return arrayList;
        }


@Override
        protected void onPostExecute(ArrayList<String> arrayList) {
                // Returns the contents of the HTML page

                      listener.onLoginActionComplete (arrayList);
 }


}

I have also asked this question. Maybe this link will help

Community
  • 1
  • 1
Zar E Ahmer
  • 33,936
  • 20
  • 234
  • 300