I have a foreground service which plays an alarm for one minute and then closes by itself. I am using Handler for closing the service after one minute by posting a delayed message.
The Handler class uses singleton approach (for a reason which is not relevant to this post).
Although the code works fine, the problem is that the service doesn't get garbage collected even after its onDestroy() method is called.
Following is the code:-
AlarmService.java:-
public class AlarmService extends Service {
private MediaPlayer alarm;
private AlarmHandler alarmHandler;
private static final int DELAY = 60 * 1000;
//onBind method
@Override
public void onCreate() {
super.onCreate();
alarmHandler = AlarmHandler.getInstance();
alarmHandler.attachService(this);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
clearPreviousAlarms(); //if any
alarm = MediaPlayer.create(this, R.raw.kalimba);
startForeground(1, NotificationUtil.buildNotification(this));
alarm.start();
alarmHandler.sendEmptyMessageDelayed(1, DELAY);
return START_NOT_STICKY;
}
private void clearPreviousAlarms() {
if (alarm != null) {
alarm.release();
}
if (alarmHandler.hasMessages(1)) {
alarmHandler.removeMessages(1);
}
}
@Override
public void onDestroy() {
super.onDestroy();
MyApp.refWatcher.watch(this); //using leakCanary for detecting the memory leak
alarm.release();
if (alarmHandler.hasMessages(1))
alarmHandler.removeMessages(1);
}
}
AlarmHandler.java:-
class AlarmHandler extends Handler {
private static AlarmHandler alarmHandler;
private WeakReference<AlarmService> alarmService;
private AlarmHandler() {
}
public void attachService(AlarmService alarmService) {
this.alarmService = new WeakReference<AlarmService>(alarmService);
}
public static AlarmHandler getInstance() {
if (alarmHandler == null) {
alarmHandler = new AlarmHandler();
}
return alarmHandler;
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1: {
alarmService.get().stopSelf();
}
break;
}
}
}
NOTE:-
As you can see above, memory leak is still being caused despite of WeakReference being used.
I am using LeakCanary for memory leak detection.