mwieczorek
mwieczorek

Reputation: 2252

Creating a callback function using AsyncTask

I've created an AsyncTask class to handle sending and receiving from my server. What I'm trying to do is fire an event or callback when the data is received so I can use said data to manipulate the UI.

AsyncTask class:

public class DataCollectClass extends AsyncTask<Object, Void, JSONObject> {
    private JSONObject collected;

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
    }

    //@Override -Commented out because it doesn't like the override
    protected void onPostExecute() {
        try {
            Log.d("Net", this.collected.getString("message"));
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected JSONObject doInBackground(Object... params) {
        OkHttpClient client = new OkHttpClient();

        // Get Parameters //
        String requestURI = (String) params[0];
        RequestBody formParameters = (RequestBody) params[1];
        Request request = new Request.Builder().url(requestURI).post(formParameters).build();

        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                // DO something on FAIL
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String jsonResponse = response.body().string();
                Log.d("Net", jsonResponse);
                try {
                    DataCollectClass.this.collected = new JSONObject(jsonResponse);
                    Log.d("Net", DataCollectClass.this.collected.getString("message"));
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        });

        return collected;
    }
}

This is working, it prints an expected line of JSON into the log.

It's called from the Activity as:

new DataCollectClass().execute(requestURI, formVars);

I've looked all over, and I can't seem to find a definitive answer on how (and where) to add a callback. Preferably, the callback code itself should be with the DataCollectClass so all related code is reusable in the same place.

Is there a way to create a custom event firing (similar to Javascript libraries) that the program can listen for?

I've been pulling my hair out over this!

UPDATE:

Since AsyncTask is redundant, I've removed it and rewrote the code (in case someone else has this same issue):

public class DataCollectClass { private JSONObject collected;

    public interface OnDataCollectedCallback {
        void onDataCollected(JSONObject data);
    }

    private OnDataCollectedCallback mCallback;

    public DataCollectClass(OnDataCollectedCallback callback, String requestURI, RequestBody formParameters){
        mCallback = callback;
        this.collect(requestURI, formParameters);
    }

    public JSONObject collect(String requestURI, RequestBody formParameters) {
        OkHttpClient client = new OkHttpClient();

        Request request = new Request.Builder().url(requestURI).post(formParameters).build();

        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                //TODO Add what happens when shit fucks up...
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String jsonResponse = response.body().string();
                Log.d("Net", jsonResponse);
                try {
                    DataCollectClass.this.collected = new JSONObject(jsonResponse);

                    if(mCallback != null)
                        mCallback.onDataCollected(DataCollectClass.this.collected);
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        });
        return collected;
    }
}

Called from Activity:

new DataCollectClass(new DataCollectClass.OnDataCollectedCallback() {
    @Override
    public void onDataCollected(JSONObject data) {
        if(data != null) {
            try {
                // Do Something //
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
    }
}, requestURI, formVars);

All working perfectly! Thanks!

Upvotes: 2

Views: 1813

Answers (3)

zgc7009
zgc7009

Reputation: 3389

If you want to utilize a callback for an AsyncTask you can handle it via the following.

Do something like this (modifying your code to add what is below)

public class DataCollectClass extends AsyncTask<Object, Void, JSONObject> {

    public interface OnDataCollectedCallback{
        void onDataCollected(JSONObject data);
    }

    private OnDataCollectedCallback mCallback;

    public DataCollectClass(OnDataCollectedCallback callback){
        mCallback = callback;
    }

    // your code that is already there
    ...

    @Override
    public onPostExecute(JSONObject response){
        if(mCallback != null)
            mCallback.onDataCollected(response);
    }
}

Then to make the magic happen

new DataCollectClass(new OnDataCollectedCallback() {
        @Override
        public void onDataCollected(JSONObject data) {
            if(data != null)
                // DO something with your data
        }
    }).execute(requestURI, formVars);

However, it is worth noting, most networking libraries, including OkHttp, handle background threads internally, and include callbacks to utilize with the requests.

This also implements a custom interface, so others may be able to see how you could use this for any AsyncTask.

Upvotes: 1

Md. Sajedul Karim
Md. Sajedul Karim

Reputation: 7065

Call Webservice using asynctask is an old fashioned. You can use Volley or retrofit. But you can use this process to call Webservice . Here is steps:

  1. Create an Interface and implements it in your Activity/Fragment

    public interface IAsynchronousTask {
            public void showProgressBar();
            public void hideProgressBar();
            public Object doInBackground();
            public void processDataAfterDownload(Object data);
     }
    

Create Class DownloadableAsyncTask . This class is:

import android.os.AsyncTask;
import android.util.Log;

public class DownloadableAsyncTask extends AsyncTask<Void, Void, Object> {

    IAsynchronousTask asynchronousTask;

    public DownloadableAsyncTask(IAsynchronousTask activity) {
        this.asynchronousTask = activity;
    }

    @Override
    protected void onPreExecute() {
        if (asynchronousTask != null)
            asynchronousTask.showProgressBar();
    }

    @Override
    protected Object doInBackground(Void... params) {
        try {
            if (asynchronousTask != null) {
                return asynchronousTask.doInBackground();
            }
        } catch (Exception ex) {
            Log.d("BSS", ex.getMessage()==null?"":ex.getMessage());
        }
        return null;
    }

    @Override
    protected void onPostExecute(Object result) {
        if (asynchronousTask != null) {
            asynchronousTask.hideProgressBar();
            asynchronousTask.processDataAfterDownload(result);
        }
    }

}

Now in your Activity you will find this methods.

DownloadableAsyncTask downloadAsyncTask;
ProgressDialog dialog;
    private void loadInformation() {
            if (downloadAsyncTask != null)
                downloadAsyncTask.cancel(true);
            downloadAsyncTask = new DownloadableAsyncTask(this);
            downloadAsyncTask.execute();

        }

        @Override
        public void showProgressBar() {
            dialog = new ProgressDialog(this, ProgressDialog.THEME_HOLO_LIGHT);
            dialog.setMessage(" Plaese wait...");
            dialog.setCancelable(false);
            dialog.show();

        }

        @Override
        public void hideProgressBar() {
            dialog.dismiss();

        }

        @Override
        public Object doInBackground() {
            // Call your Web service and return value

        }

        @Override
        public void processDataAfterDownload(Object data) {
            if (data != null) {
                // data is here
            }else{
                //"Internal Server Error!!!"
            }

        }

Now just call loadInformation() method then you will get your response on processDataAfterDownload().

Upvotes: 0

OneCricketeer
OneCricketeer

Reputation: 191728

There is a asynchronous get in OkHttp, so you don't need an AsyncTask, but as a learning exercise, you could define your callback as a parameter something like so.

new DataCollectClass(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                // DO something on FAIL
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                JSONObject collected = null;
                String jsonResponse = response.body().string();
                Log.d("Callback - Net", jsonResponse);
                try {
                    collected = new JSONObject(jsonResponse);
                    Log.d("Callback - Net", collected.getString("message"));
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        }).execute(requestURI, formVars);

The AsyncTask

public class DataCollectClass extends AsyncTask<Object, Void, Call> {
    private Callback mCallback;
    private OkHttpClient client;

    public DataCollectClass(Callback callback) {
        this.mCallback = callback;
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        this.client = new OkHttpClient();
    }

    @Override 
    protected void onPostExecute(Call response) {
        if (response != null && this.mCallback != null) {
            response.enqueue(this.mCallback);
        }
    }

    @Override
    protected Call doInBackground(Object... params) {

        // Get Parameters //
        String requestURI = (String) params[0];
        RequestBody formParameters = (RequestBody) params[1];
        Request request = new Request.Builder().url(requestURI).post(formParameters).build();

        return client.newCall(request); // returns to onPostExecute
    }
}

Upvotes: 1

Related Questions