Search code examples
androidbroadcastreceiveralarmmanager

Calling AlarmManager in Service


Context: I am attempting to implement one service call a second service (a subclass of the first) via an AlarmManager. To do this, I needed to create a Broadcast Receiver as an inner class, as recommended here (Service and a BroadCastReceiver). However, it appears that the first service is never successfully calling the second service, or the second service is not receiving the call.

I have looked around SO and found that someone else had a similar problem that was never resolved: AlarmManager from service.

The code in the first service to call the second is simply:

private final long ONE_MINUTE = 60*1000*1;

 Context theContext = getBaseContext(); 
    AlarmManager theService = (AlarmManager) theContext
            .getSystemService(Context.ALARM_SERVICE);

    Intent i = new Intent(theContext, LocalWordSubClass.class);

    PendingIntent thePending = PendingIntent.getBroadcast(theContext, 0, i,
            PendingIntent.FLAG_CANCEL_CURRENT);

    //call this after two minutes 
    theService.set(AlarmManager.RTC_WAKEUP, SystemClock.elapsedRealtime()+TWO_MINUTES, thePending);

My second service is:

public class LocalWordSubClass extends LocalWordService {
BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        if(checkIfGooglePlay() && checkTime()) {
            getPostLocation();
        }
        mLocationClient.disconnect(); //connected in the first service class
        stopSelf();
    }
};  

}

My manifest with second service recognized:

<service
        android:name=".LocalWordSubClass"
        android:label="LocalWordSubClass" >
    </service>

Question: Am I failing to implement a method? Or did I need to add the Broadcast Receiver to the Manifest? I am a bit confused as to why the second class is not being responsive.

**UPDATE: ** Thanks to CommonWare's multiple recommendations, I was able to achieve this one-minute elapse between connecting the LocationClient and getting its last location. However, the service is no longer running on repeat, when called upon by the MainActivity's AlarmManager's setRepeating Method.

This is the code (that is successfully giving the locationClient time to connect)

 if(mLocationClient==null) {
    pm = (PowerManager) getBaseContext().getSystemService(Context.POWER_SERVICE);
    wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "");
    wl.acquire();
        initalizeLocks();
        mLocationClient = new LocationClient(this, this, this);
    mLocationClient.connect();
        Context theContext = getBaseContext();

    AlarmManager theService = (AlarmManager) theContext
            .getSystemService(Context.ALARM_SERVICE);

    Intent i = new Intent(LocalWordService.this, this.getClass());

    PendingIntent thePending = PendingIntent.getService(this, 0, i,
            PendingIntent.FLAG_CANCEL_CURRENT);
    //call this after two minutes 
    theService.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + ONE_MINUTE, thePending);
    } else {
        getPostLocation();
        wl.release();
        mLocationClient = null;
        stopSelf();
    }

The MainActivity's AlarmManager is:

Calendar cal = Calendar.getInstance();

    Intent intent = new Intent(this, LocalWordService.class);
    PendingIntent pintent = PendingIntent.getService(this, 0, intent, 0);
    AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);

    alarm.
    setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), EVERY_TWO_MINUTES, pintent);

Solution

  • Am I failing to implement a method?

    Well, LocalWordSubClass seems to be devoid of methods, other than inherited ones.

    Also, you are attempting to send a broadcast Intent to a Service (via your PendingIntent), which is not going to work.

    And, the BroadcastReceiver you have defined in LocalWordSubClass is unused.

    Next, from your related comment:

    I have the initial service call a new subclass (which has access to the LocationClient) after a two minute period

    Your "new subclass" will have its own mLocationClient, unrelated to any mLocationClient from any other Service in your process.

    You appear to be attempting to implement something I wrote about in the preceding comment:

    @jsc123: "How would you recommend I give my LocationClient a two minute window to connect before polling the location?" -- you could just use AlarmManager, calling set() to get control in two minutes.

    What I meant by that was that you would use set() on AlarmManager with a getService() PendingIntent to deliver control back to your already-running Service with its already-acquired WakeLock, so that it can obtain the location, release the WakeLock, and stopSelf().