1

The first step of my app is working: when a button is clicked it makes an http request, does a JSON parse of the result and displays and stores the data. I now want to be able to schedule events so that the same thing happens regularly in the background - and I can't get it to work. I've looked at a couple of tutorials on creating broadcastreceivers and alarms (http://justcallmebrian.com/?p=129 and http://mobile.tutsplus.com/tutorials/android/android-fundamentals-scheduling-recurring-tasks/) and have replicated in a separate app the simple version that just produces a toast message when the scheduled event occurs. But when I try to combine the 2 things (schedule an event to make the http request) the complexity is defeating me. If anyone can give me some guidance I would appreciate it.

The first step (that works) starts with a button click that runs a method that has just 2 lines.

urlStr = "http://data_service_site?parm=1";     
new AsyncNetworkConnection().execute(urlStr);

The main activity then has this inline class.

class AsyncNetworkConnection extends AsyncTask<String, String, String>
{
    @Override
    protected void onPostExecute(String result) {
        //working JSON code here
        //working code to display & store data here
    }

    @Override
    protected String doInBackground(String... arg0) {
        String results = null;
        try {
            results = fetchHTML(arg0[0]);
        } catch (ClientProtocolException e) {
            String msg = getResources().getString(R.string.str_html_error, e.getMessage());
            Log.e(TAG, "Http error", e);
        } catch (Exception e) {
            String msg = getResources().getString(R.string.str_html_error, e.getMessage());
            Log.e(TAG, "Http connection error", e);
        } 
        return results;
    }

    private String fetchHTML(String urlStr) throws URISyntaxException, ClientProtocolException, IOException, Exception
    {
        DefaultHttpClient httpclient = null;
        URI serviceUri = new URI(urlStr);           
        String result;
        try {
            HttpGet getRequest = new HttpGet(serviceUri);
            ResponseHandler<String> handler = new BasicResponseHandler();
            httpclient = new DefaultHttpClient(); 
            result = httpclient.execute(getRequest, handler);   
            Log.i(TAG, "Put to Service. Result: " + result);                
        } catch (Exception e) {
            throw e;
        } finally {
            if(null != httpclient){
                httpclient.getConnectionManager().shutdown();           
            }
        }
        return result;
    }
}

The above works; what follows doesn't. To try a simple method of scheduling the same task, I've added another button which runs this method.

public void setOneOffAlarm(View v) {
     Calendar cal = Calendar.getInstance();
     cal.add(Calendar.MINUTE, 2);
     Intent intent = new Intent(this, AlarmReceiver.class);
     PendingIntent sender = PendingIntent.getBroadcast(this, 192837, intent, PendingIntent.FLAG_UPDATE_CURRENT);
     AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
     am.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), sender);
}

And I have this alarmreceiver class. I had problems creating it as a separate class file so have it as an inline class in the same activity. I first had it trying to do the http request then tried simplifying it to just display a toast message - neither work.

public class AlarmReceiver extends BroadcastReceiver {
    private static final String DEBUG_TAG = "AlarmReceiver";
    @Override
    public void onReceive(Context context, Intent intent) {
        Intent downloader = new Intent(context, AsyncNetworkConnection.class);
            //downloader.setData(Uri
                //.parse("http://data_service_site?parm=1"));
         //Try just showing toast:
         String message = ("alarm_message");
         Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
        context.startService(downloader);
    }
}

Any help appreciated.

David Walton
  • 283
  • 1
  • 4
  • 12
  • Have you considered running this as [service](http://developer.android.com/reference/android/app/Service.html), here's a fairly comprehensive example: http://www.vogella.com/articles/AndroidServices/article.html – HeatfanJohn May 03 '13 at 14:59

1 Answers1

0

A broadcast receiver can be run when a broadcast intent is sent. It is possible to do this with the alarm service but not necessary. The Alarm service can send any intent you want it to. This intent can start an activity or a service (which is probably what you need, since you want it to happen in the background).

It seems that you're sending an intent to start a broadcast receiver like you would start an activity or a service. As far as I know this is not the right way to use a broadcast receiver.

Change your AlarmReceiver to be a service (and implement the needed service methods) and you should be ok.

selalerer
  • 3,766
  • 2
  • 23
  • 33
  • Thanks selalerer. So you're saying the alarm service should send an intent, which should start a service, and the alarmreceiver should changed to be be that service. Is that right? – David Walton May 03 '13 at 15:30
  • I think that will do it. You may find this useful: http://stackoverflow.com/questions/8321443/how-to-start-service-using-alarm-manager-in-android – selalerer May 03 '13 at 15:38
  • I now have it working as a service, just displaying a toast message at the scheduled time, but I haven't yet been able to task I want (running AsyncNetworkConnection). – David Walton May 04 '13 at 08:18
  • My original coding to do the http request in response to a button click has AsyncNetworkConnection (that extends AsyncTask) as an inline class. My alarm service now works ok displaying toast but I can't a way to get it to run the inline class and I haven't been able to re-create AsyncNetworkConnection as a normal (not inline) class. Any suggestions as to how to do that? – David Walton May 04 '13 at 08:55
  • @DavidWalton It is usually a good idea to separate "business" code from framework code. In your case you can take the content of doInBackground() and onPostExecute() and put them in a new object with meaningful names. E.g. mySiteHandler with methods downLoadPage() and processPage(). Then you can call both from your AsyncTask and from your service. – selalerer May 04 '13 at 08:59
  • So are you saying that when doing the httprequest from a button it needs to be an asynctask so it's not in the UI thread - but when running from alarm service asynctask isn't necessary, so can call the methods (downLoadPage & processPage) directly? So I should have mySiteHandler as separate class, downLoadPage & processPage inside it and they are called by asynctask or by alarm service? – David Walton May 04 '13 at 09:39
  • Your message got me thinking, does the service run on the UI thread? Turns out, by default, it does. In that case you should use the AsyncTask in your service too in order to keep the UI thread free and your app responsive. – selalerer May 04 '13 at 09:57
  • So if button and alarm service both need to call those methods in AsyncTask, does that mean the AsyncTask (with those methods inside) should be not inline, so it is available to both? Or is there a way for the service to call the inline class? – David Walton May 04 '13 at 13:45
  • 1
    I don't have it working yet but this has shown me part of the way so I've marked it as the answer. Thanks selalerer. – David Walton May 08 '13 at 14:14