1

I am trying to execute AsyncTask on SmsReceiver Broadcast. The problem with my code is that if no internet connection is available when SMS broadcast receiver triggers, the AsyncTask does not execute. If no internet connection is available I want to schedule AsyncTask to run 5 times at the interval of 4 minutes for the next 20 minutes. If at any execution AsyncTask get response from server then cancel next executions & update UI. I can update UI in onPostExecute(). I earlier asked this question here but could not get any code help. A lot of posts are available on ScheduledExecutorService to schedule AsyncTask to run at interval of x minutes, but I could not find any to post mentioning AsyncTask to run for x minutes at the interval of x minutes. Only on the official Android website a Beeper example is available but I could not understand how to manipulate my code to work. I will be obliged if someone can help me is getting this code work.

SmsReceiver.java

public class SmsReceiver extends BroadcastReceiver {

static boolean flagAlarmSet;
static int count;

public void onReceive(Context context, Intent intent) {
    final String ACTION_SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED";
    String action = intent.getAction();
    if (action.equals(ACTION_SMS_RECEIVED) || action.equals("ActionRetry")) {

        Log.d("SmsReceiver Broadcast triggered", "OK");
        ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();

        if (networkInfo != null && networkInfo.isConnected()) {
            Log.d("Internet is connected", "flagAlarmSet to: " + flagAlarmSet);

            //if (flagAlarmSet) { //Removed
            count = 0;
            flagAlarmSet = false;
            CancelAlarm(context);
            Log.d("Alarm cancelled", "Alarm");
            //} //Removed

            //start AsyncTask even if flag was not set, you could have internet the first time in
            try {
                Log.d("Executing TheTask()", "OK");
                new TheTask().execute("http://somedomain.tld/index.php?userId=12345678");
            } catch (Exception e) {
                Log.d("TheTask Execution Error", "FAIL");
                e.printStackTrace();
            }
        }

        if (networkInfo == null) {
            if (!flagAlarmSet){
                Log.d("Internet is NOT connected.", "Schedule Retry");
                flagAlarmSet = true;
                SetAlarm(context);
                Log.d("Alarm Set", "Alarm");
            }
            else{
                count++;
                if (count >= 5){
                    Log.d("Internet is NOT connected.", "Max Tries Reached, Cancel Alarm");
                    count = 0;
                    flagAlarmSet = false;
                    CancelAlarm(context);
                }
            }
        }
    }
}

class TheTask extends AsyncTask<String, Void, String> {
    @Override
    protected String doInBackground(String... arg0) {
        String text = null;
        try {

            HttpClient httpclient = new DefaultHttpClient();
            HttpPost httppost = new HttpPost(arg0[0]);
            HttpResponse resp = httpclient.execute(httppost);
            HttpEntity ent = resp.getEntity();
            text = EntityUtils.toString(ent);

        } catch (Exception e) {
            e.printStackTrace();
        }

        return text;
    }

    @Override
    protected void onPreExecute() {
        Log.d("Test onPreExecute.", "OK");
    }

    @Override
    protected void onPostExecute(String result) {
        super.onPostExecute(result);

        Log.d("Result from server", result);

    }
}


public void SetAlarm(Context context)
{
    AlarmManager am=(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
    Intent i = new Intent(context, SmsReceiver.class);
    i.setAction("ActionRetry");
    PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
    am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 1000 * 60 * 4, 1000 * 60 * 4, pi); // Millisec * Second * Minute
}


public void CancelAlarm(Context context)
{
    Intent intent = new Intent(context, SmsReceiver.class);
    intent.setAction("ActionRetry");
    PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, 0);
    AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    alarmManager.cancel(sender);
}

}

EDIT: 1

Updated the code, but still if no internet connection is available, SetAlarm is not being triggered. I am coming from PHP background. In PHP it is easy to set repeating tasks using cron jobs. But it is the first time when I am writing Java codes. Till now the AsyncTask is working perfectly, But I really don't have any idea where to increment count do all this stuff ?

Edit: 2

Updated Code.

Edit: 3

Updated code. Its working now.

Community
  • 1
  • 1
Amandeep Singh
  • 276
  • 2
  • 13

1 Answers1

3

One approach to solve this would be to use a PendingIntent and AlarmManager to re-schedule if no internet is available.

Something like this (you will need to update your flagAlarmSet and count where appropriate):

if (networkInfo != null && networkInfo.isConnected()) {
    Log.d("Network is connected. Executing TheTask()", "OK");

    if (flagAlarmSet == true){
       flagAlarmSet = false;
       CancelAlarm(context);
    }

    new TheTask().execute("http://somedomain.tld/index.php?userId=12345678");

}

if (networkInfo == null) {
   Log.d("Network is NOT connected.", "FAIL");
   if (flagAlarmSet == false){
       Log.d("Network is NOT connected.", "Schedule Retry");
       flagAlarmSet = true;
       SetAlarm(context);
   }
   else{
      if (count > 5){
          Log.d("Network is NOT connected.", "Max Tries Reached, Cancel Alarm");
          flagAlarmSet = false;
          CancelAlarm(context);
      }

   }
}

And something like this for scheduling/canceling alarm:

public void SetAlarm(Context context)
 {
     AlarmManager am=(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
     Intent i = new Intent(context, SmsReceiver.class);
     PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
     am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 1000 * 60 * 4, pi); // Millisec * Second * Minute
 }

 public void CancelAlarm(Context context)
 {
     Intent intent = new Intent(context, SmsReceiver.class);
     PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, 0);
     AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
     alarmManager.cancel(sender);
 }

Reference: Alarm Manager Example

One more thing to note, if you are planning on using the message received, you would need to cache the message somehow for use in the re-scheduled PendingIntent.

See getMessagesFromIntent() documentation:

https://developer.android.com/reference/android/provider/Telephony.Sms.Intents.html#getMessagesFromIntent(android.content.Intent)

Example: Sending and Receiving SMS and MMS in Android (pre Kit Kat Android 4.4)

Edit: re-set your count here:

         else{
            if (count >= 5){
                Log.d("Network is NOT connected.", "Max Tries Reached, Cancel Alarm");
                count = 0;
                flagAlarmSet = false;
                CancelAlarm(context);
            }

Edit 2: Ok, I think I see what the problem is. You will need to add an action to the intent, and look for "ActionRetry" in onReceive().

I just tested this and it works.

Take a look at the updated code below:

    public class SmsReceiver extends BroadcastReceiver {

    static boolean flagAlarmSet;
    static int count;

    public void onReceive(Context context, Intent intent) {
        final String ACTION_SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED";
        String action = intent.getAction();
        if (action.equals(ACTION_SMS_RECEIVED) || action.equals("ActionRetry")) {

            Log.d("SmsReceiver Broadcast triggered", "OK");
            ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();

            if (networkInfo != null && networkInfo.isConnected()) {
                Log.d("Network is connected. Executing TheTask()", "OK");
                Log.d("connected", "flagAlarmSet to: " + flagAlarmSet);

                //if (flagAlarmSet) { //Removed
                    count = 0;
                    flagAlarmSet = false;
                    CancelAlarm(context);
                    Log.d("Alarm cancelled", "Alarm");
                 //} //Removed

                 //start AsyncTask even if flag was not set, you could have internet the first time in  
                 try {
                        Log.d("SmsReceiver Broadcast triggered", "OK");
                        new TheTask().execute("http://somedomain.tld/index.php?userId=12345678");
                    } catch (Exception e) {
                        Log.d("TheTask Execution Error", "FAIL");
                        e.printStackTrace();
                    }

            }

            if (networkInfo == null) {

                Log.d("Network is NOT connected.", "FAIL");
                if (!flagAlarmSet){
                    Log.d("Network is NOT connected.", "Schedule Retry");
                    flagAlarmSet = true;
                    SetAlarm(context);
                    Log.d("Alarm Set", "Alarm");
                }
                else{
                    count++;
                    if (count >= 5){
                        Log.d("Network is NOT connected.", "Max Tries Reached, Cancel Alarm");
                        count = 0;
                        flagAlarmSet = false;
                        CancelAlarm(context);
                    }
                }
            }
        }
    }

    class TheTask extends AsyncTask<String, Void, String> {
        @Override
        protected String doInBackground(String... arg0) {
            String text = null;
            try {

                HttpClient httpclient = new DefaultHttpClient();
                HttpPost httppost = new HttpPost(arg0[0]);
                HttpResponse resp = httpclient.execute(httppost);
                HttpEntity ent = resp.getEntity();
                text = EntityUtils.toString(ent);

            } catch (Exception e) {
                e.printStackTrace();
            }

            return text;
        }

        @Override
        protected void onPreExecute() {
            Log.d("Test onPreExecute.", "OK");
        }

        @Override
        protected void onPostExecute(String result) {
            super.onPostExecute(result);

            Log.d("Result from server", result);

        }
    }


    public void SetAlarm(Context context)
    {
        AlarmManager am=(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
        Intent i = new Intent(context, SmsReceiver.class);
        i.setAction("ActionRetry");
        PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
        am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 1000 * 60 * 4, 1000 * 60 * 4, pi); // Millisec * Second * Minute
    }


    public void CancelAlarm(Context context)
    {
        Intent intent = new Intent(context, SmsReceiver.class);
        intent.setAction("ActionRetry");
        PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, 0);
        AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        alarmManager.cancel(sender);
    }
}
Community
  • 1
  • 1
Daniel Nugent
  • 43,104
  • 15
  • 109
  • 137
  • thank you so much @Daniel Nugent for your detailed answer and giving me the code. If I am not wrong I have to update flagAlarmSet in onPostExecute() if I get response from the server ? – Amandeep Singh Mar 14 '15 at 18:27
  • No problem! You can just update flagAlarmSet every time you set or cancel the alarm, I just updated the answer. Also update the count every time `onReceive()` is called, and I would think re-set the count to zero in `onPostExecute()` – Daniel Nugent Mar 14 '15 at 18:30
  • Is it getting into the `SetAlarm()` function? One more thing, it looks like you should just set the count back to zero (or one) when the max is reached. As your code is now, you're creating a new count variable in `onPostExecute()`. – Daniel Nugent Mar 15 '15 at 16:51
  • Sounds good! Note that I didn't test the network code, just the SMS receive and subsequent re-scheduled broadcasts. – Daniel Nugent Mar 16 '15 at 04:26
  • Hi Daniel, I have tested your updated code on my phone. It's working perfectly when I get SMS when my phone IS NOT connected to Internet. Alarm is being sent & cancelled after max tries. But there are some issues when I switch on Wifi/Mobile Data after first Alarm being set. The code goes into infinite loop. Alarm is not being cancelled. Here is logcat which is perfec [link](https://gist.github.com/anonymous/95549d8cc491cc6d90ff) Will paste another logcat after 30 minutes. – Amandeep Singh Mar 16 '15 at 18:24
  • Now, I turned off Wifi on my phone & sent a test SMS. First AsyncTask failed because Internet was not connected. Then I turned ON wifi & the problem began. [Here](https://gist.github.com/anonymous/a70c5eea92f94d860704) is another logcat – Amandeep Singh Mar 16 '15 at 19:02
  • Looking at the logs now. Can you post your updated code to a gist as well? – Daniel Nugent Mar 16 '15 at 19:05
  • [here](https://gist.github.com/anonymous/427712253dbb833ba7d2) is complete code of **SmsReceiver.java** – Amandeep Singh Mar 16 '15 at 19:11
  • It's hard to say why it's not getting into that case. Try removing the `if (flagAlarmSet)`, take a look at the updated code in the answer. For some reason it's not getting into that case. Also log the value of `flagAlarmSet` when it gets into the internet connected case, just to get a better idea of what is going on. – Daniel Nugent Mar 16 '15 at 19:19
  • 1
    Thanks a lot **Daniel**, You are genius. It works, I really appreciate your efforts. Once again thank you so much. – Amandeep Singh Mar 17 '15 at 16:44