Search code examples
androidbroadcastreceiverandroid-servicealarmmanagerandroid-pendingintent

How to stop my service after passing fixed amount of time?


At point A in my application I start my service and expect the service get closed from point B. However, there might be few scenarios that point B doesn't ask service to get closed. In this case I want the service close itself after fixed amount of time.

I have written following code into my Service class and expect the service gets closed after 10 seconds from launch time (It will be 45min in the future but I don't want to stay that long for test).

public class ChatService extends Service implements ITCPConnection
{
    private static final int SERVICE_LIFE_TIME = 10 * 1000; // In millis

    private AlarmReceiver mAlarmReceiver;
    private AlarmManager alarmMgr;
    private PendingIntent alarmIntent;

    @Override
    public void onCreate()
    {
        super.onCreate();

        //
        mAlarmReceiver = new AlarmReceiver();
        registerReceiver(mAlarmReceiver, new IntentFilter());

        //
        Intent intent = new Intent(this, AlarmReceiver.class);
        alarmIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
        alarmMgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        alarmMgr.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + SERVICE_LIFE_TIME, alarmIntent);
    }

    @Override
    public void onDestroy()
    {
        super.onDestroy();
        Log.e(TAG, "onDestroy()");

        // Unregister receiver
        if (mAlarmReceiver != null)
        {
            unregisterReceiver(mAlarmReceiver);
        }

        disconnect();
    }

    public void disconnect()
    {
        // If the alarm has been set, cancel it.
        if (alarmMgr!= null)
        {
            alarmMgr.cancel(alarmIntent);
        }

        ...

        Log.e(TAG, "disconnect()");
    }


    /*****************
     * Alarm Receiver
     *****************/
    private static class AlarmReceiver extends BroadcastReceiver
    {
        @Override
        public void onReceive(Context context, Intent intent)
        {
            Log.e(TAG, "Stop service from AlarmReceiver");
            context.stopService(intent);
        }
    }
}

My problem is AlarmReceiver.onReceive() never gets called and therefore my service will be alive indefinitely.


Solution

  • What you are trying to do is to targeting a broadcast receiver explicitly.

    According to this, it cannot be done over a dinamically created (i.e. not declared into the manifest) broadcast receiver, because the os would not know how to resolve it. To check if this is the root of the problem, you can go with the implicit way and set an action inside the intent and by filtering it in the IntentFilter.

    Anyway, using the post delayed can be seen as a valid alternative, since you expect the service to be shut down naturally or still be around to intercept the delayed event.

    Another (unrelated) thing is that you are calling

                context.stopService(intent);
    

    by using the broadcast intent and not the intent that started the service. You could simply call stopSelf().