【问题标题】:Service has leaked IntentReceiver in android服务在 android 中泄露了 IntentReceiver
【发布时间】:2021-04-06 03:20:13
【问题描述】:

我正在制作一个安卓应用程序。当用户检查checkbox 时,我正在制作一项始终在后台运行的服务,并且当用户unckeck 它时它应该停止。因此,当我选中该框并且它还显示“服务启动”Toast 时它确实有效,但是当我 uncheckcheckbox 然后它显示说“服务停止”的 Toast 但它不会停止播放开始时的声音服务已启动。停止这种声音的唯一方法是关闭我的手机,然后再打开它。

这是我用于启动和停止服务的 java 代码

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... !

请帮忙。我在哪里犯错了。

编辑

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();
        }

    }
};

【问题讨论】:

  • 在我的手机上,即使应用程序完全退出,播放的声音也会继续播放。也许这只是一个Android的东西。您是否尝试过停止服务的声音?
  • Hassan 我没明白你的意思“你试过停止服务的声音吗?”你能详细说明一下吗?
  • 我的意思是,在实际播放声音的代码中,如何暂停/停止声音?你暂停/停止它吗?
  • Hassan 在上面看到我的更新,这就是我开始和停止声音的地方
  • 谁能解决我的问题?请

标签: java android


【解决方案1】:

确保在onDestroy 结束之前致电unregisterReceiver。在onDestroy之后Service的上下文无效,所以所有注册的intent receiver都会停止运行。 Android 会通过“Leaked Intent receiver”异常警告您您的应用行为异常。

音乐不会停止,因为不再调用接收器。您应该确保在从 onDestroy 返回之前调用 mMediaPlayer.stop。我建议您将所有这些功能提取到单独的方法中,这样编写您的应用程序会容易得多。

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

此外,如果由于错误而连续收到两个插入的 == 2 个意图,请注意不要泄漏 mMusicPlayer。以防御的方式编写代码总是比依赖调用者的额外知识更好。

异常处理在您的代码中也非常危险。如果音乐启动失败,当你想停止音乐时,可能会出现空指针异常。

希望这会有所帮助。

【讨论】:

  • 感谢 allprog。这有帮助,您提供了很好的信息。因为我是 android 新手,所以我的代码不像专业人士。你能告诉我我可以在哪里以及如何在我的代码中取消注册我的接收器吗?
  • 我用过这个“this.unregisterReceiver(this.batteryInfoReceiver);”在 onDestroy() 方法中,但它不起作用。
  • 我会说这是 Android 最糟糕的部分。您需要在这里使用的 API 非常模糊,您需要了解 Services 和 BroadcastReceivers 的内部工作原理才能了解它应该如何完成。您是否尝试过在 super.onDestroy() 之前调用 unregisterReceiver?你得到什么错误?
  • 我正在使用通过蓝牙发送意图的外部设备。即使我取消注册接收器,我仍然会收到此异常。这可能是因为在接收方注销后数据到达需要时间。你这边可能也一样。
  • @allprog 我遇到了同样的错误,我在调用 super 之前调用了 unregister。你们解决了这个问题吗??
【解决方案2】:

也许你错过了@Override注解

@Override
public void onDestroy() {
    unregisterReceiver(batteryInfoReceiver);
    super.onDestroy();
}

【讨论】:

    【解决方案3】:

    可能有点晚了,但您似乎必须在调用 onDestroy() 方法之前调用 unregisterReceiver()。这解决了我的问题。

    【讨论】:

      猜你喜欢
      • 2018-11-15
      • 1970-01-01
      • 2012-04-04
      • 2012-07-03
      • 2018-01-26
      • 2017-11-13
      • 2012-10-18
      • 1970-01-01
      相关资源
      最近更新 更多