服务已泄漏Android中的IntentReceiver [英] Service has leaked IntentReceiver in android
问题描述
我正在制作一个Android应用程序.我正在制作一项在用户选中复选框
时始终在后台运行的服务,并且在用户 unckeck
时应停止运行.因此,当我选中该框并显示服务启动" Toast时,它确实起作用,但是当我 uncheck
checkbox
时,它显示了显示"Service stop"的Toast,但是它不会停止播放服务启动时开始的声音.停止发出声音的唯一方法是关闭手机,然后再打开.
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.
这是我用于启动和停止服务的Java代码
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();
}
这是我的xml文件
<CheckBoxPreference
android:title="Enable/Disable Alarm"
android:defaultValue="true"
android:key="cbAlarm"
android:summary="Enable or disable alarm" />
这是我的日志
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.
修改
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();
}
}
};
推荐答案
请确保在 onDestroy
完成之前调用 unregisterReceiver
.在 onDestroy
之后,服务的上下文无效,因此所有已注册的意图接收器将停止运行.Android会向您发出泄漏的意图接收器"警告您的应用程序行为异常.
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.
音乐不会停止,因为不再呼叫接收器.您应该确保在从onDestroy返回之前调用mMediaPlayer.stop.我建议您将所有这些功能提取到单独的方法中,这样组成应用程序会容易得多.
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();
此外,如果由于错误而连续收到两个插入的== 2个Intent,请小心不要泄漏mMusicPlayer.最好以防御性的方式编写代码,而不是依赖于调用者的其他知识.
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.
希望这会有所帮助.
这篇关于服务已泄漏Android中的IntentReceiver的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!