Service has leaked IntentReceiver in android

android, java

Solution

Make sure you call `unregisterReceiver`before the `onDestroy` finishes. After `onDestroy` the Service's context is invalid, so all registered intent receivers will stop operating. Android warns you with the "Leaked intent receiver" exception that your app is misbehaving.

The music does not stop because the receiver is not called any more. You should ensure that mMediaPlayer.stop is called before the return from onDestroy. I suggest you extracting all this functionality into separate methods, thus it will be much easier to compose your application.

private void startMusic(int level);
private void stopMusic();

Also, be careful not to leak the mMusicPlayer if due to error you receive two plugged == 2 intents in a row. It is always better to write your code in a defensive way, rather than relying on the invoker's additional knowledge.

The exception handling is also quite dangerous in your code. If the music starting failed, it may happen that you get a null pointer exception when you want to stop the music.

Hope this helps.

Problem

I am making an android app. I am making a service that runs in the background all the time when user checks a `checkbox` and it should stop when user `unckeck` it. So it does work when I check the box and it also shows "Service start" Toast but when I `uncheck` the `checkbox` then it shows the Toast that says "Service stopped" but it does not stop playing the sound which started when the service was started. The only way to stop that sound is to turn off my mobile and then turn it on. Here is my java code for starting and stopping service ``` public int onStartCommand(Intent intent, int flags, int startId) { Toast.makeText(this, "Service Started", Toast.LENGTH_LONG).show(); this.registerReceiver(this.batteryInfoReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); return START_STICKY; } public void onDestroy() { super.onDestroy(); Toast.makeText(this, "Service Stopped", Toast.LENGTH_LONG).show(); } ``` Here is my xml file ``` <CheckBoxPreference android:title="Enable/Disable Alarm" android:defaultValue="true" android:key="cbAlarm" android:summary="Enable or disable alarm" /> ``` and here is my logcat ``` 05-06 09:13:53.230: D/dalvikvm(5351): GC_EXTERNAL_ALLOC freed 39K, 50% free 2725K/5379K, external 0K/0K, paused 124ms 05-06 09:13:53.355: D/dalvikvm(5351): GC_EXTERNAL_ALLOC freed 21K, 49% free 2779K/5379K, external 504K/518K, paused 18ms 05-06 09:13:53.420: D/CLIPBOARD(5351): Hide Clipboard dialog at Starting input: finished by someone else... ! 05-06 09:13:57.975: I/MediaPlayer(5351): uri is:content://media/internal/audio/media/44 05-06 09:13:57.975: I/MediaPlayer(5351): inside getAudioFilePath: content://media/internal/audio/media/44 05-06 09:13:57.980: I/MediaPlayer(5351): The actual path is:/system/media/audio/ringtones/S_A_cricket_chirps.ogg 05-06 09:13:57.980: I/MediaPlayer(5351): path is: /system/media/audio/ringtones/S_A_cricket_chirps.ogg 05-06 09:13:57.980: I/MediaPlayer(5351): file path found for DRM file:path is: /system/media/audio/ringtones/S_A_cricket_chirps.ogg 05-06 09:13:57.980: E/MediaPlayer-JNI(5351): setDataSource: outside path in JNI is ?x@ 05-06 09:14:20.525: E/ActivityThread(5351): Service com.zafar.test.BatteryService has leaked IntentReceiver com.zafar.test.BatteryService$1@40536548 that was originally registered here. Are you missing a call to unregisterReceiver()? 05-06 09:14:20.525: E/ActivityThread(5351): android.app.IntentReceiverLeaked: Service com.zafar.test.BatteryService has leaked IntentReceiver com.zafar.test.BatteryService$1@40536548 that was originally registered here. Are you missing a call to unregisterReceiver()? 05-06 09:14:20.525: E/ActivityThread(5351): at android.app.LoadedApk$ReceiverDispatcher.<init>(LoadedApk.java:756) 05-06 09:14:20.525: E/ActivityThread(5351): at android.app.LoadedApk.getReceiverDispatcher(LoadedApk.java:551) 05-06 09:14:20.525: E/ActivityThread(5351): at android.app.ContextImpl.registerReceiverInternal(ContextImpl.java:866) 05-06 09:14:20.525: E/ActivityThread(5351): at android.app.ContextImpl.registerReceiver(ContextImpl.java:853) 05-06 09:14:20.525: E/ActivityThread(5351): at android.app.ContextImpl.registerReceiver(ContextImpl.java:847) 05-06 09:14:20.525: E/ActivityThread(5351): at android.content.ContextWrapper.registerReceiver(ContextWrapper.java:318) 05-06 09:14:20.525: E/ActivityThread(5351): at com.zafar.test.BatteryService.onStartCommand(BatteryService.java:35) 05-06 09:14:20.525: E/ActivityThread(5351): at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2043) 05-06 09:14:20.525: E/ActivityThread(5351): at android.app.ActivityThread.access$2800(ActivityThread.java:117) 05-06 09:14:20.525: E/ActivityThread(5351): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:998) 05-06 09:14:20.525: E/ActivityThread(5351): at android.os.Handler.dispatchMessage(Handler.java:99) 05-06 09:14:20.525: E/ActivityThread(5351): at android.os.Looper.loop(Looper.java:130) 05-06 09:14:20.525: E/ActivityThread(5351): at android.app.ActivityThread.main(ActivityThread.java:3691) 05-06 09:14:20.525: E/ActivityThread(5351): at java.lang.reflect.Method.invokeNative(Native Method) 05-06 09:14:20.525: E/ActivityThread(5351): at java.lang.reflect.Method.invoke(Method.java:507) 05-06 09:14:20.525: E/ActivityThread(5351): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:907) 05-06 09:14:20.525: E/ActivityThread(5351): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:665) 05-06 09:14:20.525: E/ActivityThread(5351): at dalvik.system.NativeStart.main(Native Method) 05-06 09:14:37.810: D/CLIPBOARD(5351): Hide Clipboard dialog at Starting input: finished by someone else... ! ``` Help please. Where am I making mistake. Edit ``` private BroadcastReceiver batteryInfoReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0); int plugged = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0); if(plugged == 2) { SharedPreferences getAlarms = PreferenceManager.getDefaultSharedPreferences(getBaseContext()); String alarms = getAlarms.getString("ringtone", "default ringtone"); //getting uri from MediaStore via filepath i.e. content://media/internal/audio/media/29 Uri uri = Uri.parse(alarms); mMediaPlayer = new MediaPlayer(); try { mMediaPlayer.setDataSource(context, uri); final AudioManager audioManager = (AudioManager) context .getSystemService(Context.AUDIO_SERVICE); if (audioManager.getStreamVolume(AudioManager.STREAM_ALARM) != 0) { mMediaPlayer.setAudioStreamType(AudioManager.STREAM_ALARM); mMediaPlayer.prepare(); mMediaPlayer.start(); } } catch (IOException e) { //System.out.println("OOPS"); e.getStackTrace(); } } else if(plugged == 0) { mMediaPlayer.stop(); } } }; ```

Original source