Wednesday, April 20, 2016

Re-Using AsyncTask - Calling from a regular Thread (that is not the UI Thread)

The problem:
You can't call a Class the extends AsyncTask from a thread that is not the UI Thread.

The Solution:

This is a design pattern that will enable your AsyncTask Class methods to be called from a thread.

1. define your operation methods as public static
2. your doInBackground should call one of the operation methods (according to its params).

Here is an example:

public class GCMSender extends AsyncTask<String, Integer, Integer> {
    @Override    protected Integer doInBackground(String... params) {
        Log.i(P.TAG, "GcmSender doInBackground called");

        if (params.length == 2) {
            //// sending GCM            String topic = params[0];
            String pic_name = params[1];
            sendNewDetected(topic, pic_name);
        }
        else  {
            Log.e(P.TAG, "GcmSender cant send GCM params length is not 2");
            return 0;
        }
        return 0;

    }


    // this is the operation method
    public static void sendNewDetected(String topic, String pic_id) {
        Log.i(P.Tag, "GcmSender send called");
        try {
            // Prepare JSON containing the GCM message content. What to send and where to send.            JSONObject jGcmData = new JSONObject();
            JSONObject jData = new JSONObject();

            String fullTopic = "/topics/" + topic;
            Log.i(P.Tag, "jData name: " + pic_id);
            Log.i(P.Tag, "fullTopic: " + fullTopic);

            jData.put("pic_id", pic_id);
            jGcmData.put("to", fullTopic);

            // What to send in GCM message.            jGcmData.put("data", jData);

            // Create connection to send GCM Message request.            URL url = new URL("https://android.googleapis.com/gcm/send");
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestProperty("Authorization", "key=" + API_KEY);
            conn.setRequestProperty("Content-Type", "application/json");
            conn.setRequestMethod("POST");
            conn.setDoOutput(true);

            // Send GCM message content.            OutputStream outputStream = conn.getOutputStream();
            outputStream.write(jGcmData.toString().getBytes());

            // Read GCM response.            InputStream inputStream = conn.getInputStream();
            //String resp = IOUtils.toString(inputStream);            String resp = convertStreamToString(inputStream);

            Log.i(P.Tag, "GCM message sent: " + resp);

        } catch (IOException e) {
            Log.e(P.Tag, "Unable to send GCM message.");
        }
    }

    }


To call from a thread use this:

GCMSender.sendNewDetected(P.getAccount4GCM(getApplicationContext()), fileId);


To call as AsyncTask use this:

new GCMSender().execute(P.getAccount4GCM(getApplicationContext()), fileId);