Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

call AsyncTask from Broadcast receiver android

SO currently i have an AsyncTask class that runs and POST's data to my server when I click a button(which works great).

What im trying to do now is handle what happens when the user is not connected to the internet. so i have set up these classes to notify the app when internet has connected so that the data can be sent automatically to the server.

AsyncTask class(inner class)

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

    ProgressDialog dialog = new ProgressDialog(getActivity());
    final AlertDialog finishedDialog = new AlertDialog.Builder(getActivity())
    .setCancelable(false)
    .setPositiveButton(android.R.string.ok, null)
    .create();



    @Override
    protected String doInBackground(String... urls) {
        onProgressUpdate("Uploading Data...");
        return POST(urls[0]);
    }

    @Override
    protected void onPreExecute() {
        this.dialog.show();
        finishedDialog.setOnShowListener(new DialogInterface.OnShowListener(){

            @Override
            public void onShow(DialogInterface dialog) {
                Button b = finishedDialog.getButton(AlertDialog.BUTTON_POSITIVE);
                b.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    // navigate to match summary.....
                    finishedDialog.dismiss();
                }

            });
            }

        });
    }

    protected void onProgressUpdate(String msg) {
        dialog.setMessage(msg);

    }

    // onPostExecute displays the results of the AsyncTask.
    @Override
    protected void onPostExecute(String result) {
        if (result != ""){

            finishedDialog.setTitle("Upload Complete!");
            finishedDialog.setMessage("Data Sent Successfully");
            finishedDialog.show();
            dialog.dismiss();
            editor.clear();
            editor.commit();
            //Toast.makeText(getActivity().getBaseContext(), result, Toast.LENGTH_LONG).show();
        }else
        {
            Handler handler = new Handler();
            handler.postDelayed(new Runnable() {
                public void run() {
                    finishedDialog.setTitle("Upload Failed!");
                    finishedDialog.setMessage("Data Will Automatically Be Uploaded When Internet Connection Is Available");
                    finishedDialog.show();
                    dialog.dismiss();
                }}, 1000);

            setFlag(true);
        }
   }

}


public static boolean getFlag() {
    return flag;
}

public void setFlag(boolean flag) {
    this.flag = flag;
}


public String POST(String url){
    InputStream inputStream = null;
    String result = "";
    try {

        // 1. create HttpClient
        HttpClient httpclient = new DefaultHttpClient();

        // 2. make POST request to the given URL
        HttpPost httpPost = new HttpPost(url);


        if(adapter.updateNeeded()){
            JSONObject main = new JSONObject(exmaplePrefs.getString("jsonString", "cant find json"));
            JSONObject dbUpdates = new JSONObject(exmaplePrefs.getString("ChangesJSON", "cant find Changejson"));
            main.put("Team_Updates", dbUpdates);
            json = main.toString();
        }else{
             json = exmaplePrefs.getString("jsonString", "cant find json");
             // String json = "{\"twitter\":\"test\",\"country\":\"test\",\"name\":\"test\"}";
        }




        // 5. set json to StringEntity
        StringEntity se = new StringEntity(json);
        se.setContentType("application/json;charset=UTF-8");

        // 6. set httpPost Entity
        httpPost.setEntity(se);

        // 7. Set some headers to inform server about the type of the content   
       // httpPost.setHeader("Accept", "application/json");
       // httpPost.setHeader("Content-type", "application/json");
       // httpPost.setHeader("json", json);


        // 8. Execute POST request to the given URL

        HttpResponse httpResponse = httpclient.execute(httpPost);

        // 9. receive response as inputStream
        inputStream = httpResponse.getEntity().getContent();

        String status = httpResponse.getStatusLine().toString();
        // 10. convert inputstream to string
        if (!status.equals("HTTP/1.1 500 Internal Server Error")){
            if(inputStream != null){
                result = convertInputStreamToString(inputStream);   
            }
            else{
                result = "Did not work!";
            }
        }else{
            System.out.println("500 Error");

        }



    } catch (Exception e) {
        Log.d("InputStream", e.getLocalizedMessage());
        System.out.println("eerroorr "+e);
    }

    // 11. return result
    System.out.println(result);
    return result;

}

private static String convertInputStreamToString(InputStream inputStream) throws IOException{
    BufferedReader bufferedReader = new BufferedReader( new InputStreamReader(inputStream));
    String line = "";
    String result = "";
    while((line = bufferedReader.readLine()) != null)
        result += line;

    inputStream.close();
    return result;

}
}

NetworkUtil class

  public class NetworkUtil {

public static int TYPE_WIFI = 1;
public static int TYPE_MOBILE = 2;
public static int TYPE_NOT_CONNECTED = 0;


public static int getConnectivityStatus(Context context) {
    ConnectivityManager cm = (ConnectivityManager) context
            .getSystemService(Context.CONNECTIVITY_SERVICE);

    NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
    if (null != activeNetwork) {
        if(activeNetwork.getType() == ConnectivityManager.TYPE_WIFI)
            return TYPE_WIFI;

        if(activeNetwork.getType() == ConnectivityManager.TYPE_MOBILE)
            return TYPE_MOBILE;
    }
    return TYPE_NOT_CONNECTED;
}

public static String getConnectivityStatusString(Context context) {
    int conn = NetworkUtil.getConnectivityStatus(context);
    String status = null;
    if (conn == NetworkUtil.TYPE_WIFI) {
        status = "Wifi enabled";
    } else if (conn == NetworkUtil.TYPE_MOBILE) {
        status = "Mobile data enabled";
    } else if (conn == NetworkUtil.TYPE_NOT_CONNECTED) {
        status = "Not connected to Internet";
    }
    return status;
}
}

BroadcastReceiver class

public class NetworkChangeReceiver extends BroadcastReceiver {


@Override
public void onReceive(final Context context, final Intent intent) {
     intent.getExtras();
    String status = NetworkUtil.getConnectivityStatusString(context);

    Toast.makeText(context, status, Toast.LENGTH_LONG).show();

    if(MatchFragment.getFlag()){
        //send data
    }
}
}

So in the BroadcastReceiver class I check the flag that gets set to true when the app attempts to send data but there is not internet (onPostExecute in AsyncTask Class).

so what want to do is some how call the POST method. do i have to create a new Async task class? Im a bit stumped here .

Thanks

like image 568
Chris Mowbray Avatar asked Feb 13 '14 02:02

Chris Mowbray


3 Answers

Using AsyncTask in BroadcastReceiver is a bad practice.

You should use Service because Android OS may kill your process or onReceive() may run to completion before asyncTask will return result, so there is no guarantee you will get the expected result.

like image 142
QuokMoon Avatar answered Oct 13 '22 13:10

QuokMoon


You shouldn't use AsyncTask in Broadcast Receiver because the system can kill your process after returning from onReceive method (if there is no any active service or activity). Proof link

Official documentation recommends IntentService for such cases (see paragraph about Broadcast Receivers).

like image 44
renadeen Avatar answered Oct 13 '22 14:10

renadeen


The other answers are not correct according to Google's documentation. The Broadcast Receivers developer guide explicitly calls out that you can use AsyncTasks from BroadcastReceivers if you call goAsync() first and report the status to the pending result in the AsyncTask

For this reason, you should not start long running background threads from a broadcast receiver. After onReceive(), the system can kill the process at any time to reclaim memory, and in doing so, it terminates the spawned thread running in the process. To avoid this, you should either call goAsync() (if you want a little more time to process the broadcast in a background thread) or schedule a JobService from the receiver using the JobScheduler, so the system knows that the process continues to perform active work.

And later it clarifies how much time you actually get:

Calling goAsync() in your receiver's onReceive() method and passing the BroadcastReceiver.PendingResult to a background thread. This keeps the broadcast active after returning from onReceive(). However, even with this approach the system expects you to finish with the broadcast very quickly (under 10 seconds). It does allow you to move work to another thread to avoid glitching the main thread.

public class MyBroadcastReceiver extends BroadcastReceiver {
    private static final String TAG = "MyBroadcastReceiver";

    @Override
    public void onReceive(final Context context, final Intent intent) {
        final PendingResult pendingResult = goAsync();
        AsyncTask<String, Integer, String> asyncTask = new AsyncTask<String, Integer, String>() {
            @Override
            protected String doInBackground(String... params) {
                StringBuilder sb = new StringBuilder();
                sb.append("Action: " + intent.getAction() + "\n");
                sb.append("URI: " + intent.toUri(Intent.URI_INTENT_SCHEME).toString() + "\n");
                Log.d(TAG, log);
                // Must call finish() so the BroadcastReceiver can be recycled.
                pendingResult.finish();
                return data;
            }
        };
        asyncTask.execute();
    }
}
like image 35
Reuben Tanner Avatar answered Oct 13 '22 13:10

Reuben Tanner