服务已泄漏Android中的IntentReceiver [英] Service has leaked IntentReceiver in android

查看:62
本文介绍了服务已泄漏Android中的IntentReceiver的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在制作一个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 unregisterReceiverbefore 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆