You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android充电连接时MediaPlayer重复播放声音问题求助

解决Android充电提示音重复播放的问题

嘿,我来帮你搞定这个重复播放的问题~ 你的代码里主要有两个核心问题:一是ACTION_BATTERY_CHANGED广播会被系统频繁触发(不止插拔充电线时,电量变化、状态微调都会发),二是你的状态标记逻辑和MediaPlayer管理不够严谨。下面是具体的解决方案:

问题根源分析

  • ACTION_BATTERY_CHANGED是粘性广播,系统会在很多场景下发送它(比如电池从99%到100%、充电状态从快充切换到普通充),这会导致你的onCharge()/onDisconnect()被多次调用。
  • 你现在的playedOnceOn是在播放完成后才设为true,如果广播在播放过程中再次触发,就会重复播放。
  • MediaPlayer每次都重新创建,没有及时释放,不仅浪费资源,也可能导致多个实例同时播放。

修正后的代码方案

package com.mccharginggimmick;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.MediaPlayer;
import android.os.BatteryManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;

public class MainActivity extends AppCompatActivity {
    IntentFilter intentFilter;
    BroadcastReceiver broadcastReceiver;
    MediaPlayer mediaPlayer; // 统一用一个MediaPlayer实例,避免重复创建
    boolean lastChargingState = false; // 记录上一次的充电状态,用来判断状态是否变化
    ImageView imageView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        View decorView = getWindow().getDecorView();
        int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN;
        decorView.setSystemUiVisibility(uiOptions);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        imageView = findViewById(R.id.imageView);

        intentFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
        broadcastReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
                boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING || status == BatteryManager.BATTERY_STATUS_FULL;
                
                // 只有当充电状态发生变化时,才执行对应的操作
                if (isCharging != lastChargingState) {
                    lastChargingState = isCharging;
                    if (isCharging) {
                        playChargeSound();
                    } else {
                        playDisconnectSound();
                    }
                }
            }
        };
        registerReceiver(broadcastReceiver, intentFilter);
    }

    private void playChargeSound() {
        // 先释放之前的MediaPlayer资源
        releaseMediaPlayer();
        imageView.setVisibility(View.INVISIBLE);
        mediaPlayer = MediaPlayer.create(this, R.raw.btnon);
        mediaPlayer.start();
        mediaPlayer.setOnCompletionListener(mp -> releaseMediaPlayer());
    }

    private void playDisconnectSound() {
        // 先释放之前的MediaPlayer资源
        releaseMediaPlayer();
        imageView.setVisibility(View.VISIBLE);
        mediaPlayer = MediaPlayer.create(this, R.raw.btnoff);
        mediaPlayer.start();
        mediaPlayer.setOnCompletionListener(mp -> releaseMediaPlayer());
    }

    // 统一的MediaPlayer释放方法,避免内存泄漏和重复播放
    private void releaseMediaPlayer() {
        if (mediaPlayer != null) {
            if (mediaPlayer.isPlaying()) {
                mediaPlayer.stop();
            }
            mediaPlayer.release();
            mediaPlayer = null;
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 页面销毁时记得注销广播和释放MediaPlayer
        if (broadcastReceiver != null) {
            unregisterReceiver(broadcastReceiver);
        }
        releaseMediaPlayer();
    }
}

关键优化点说明

  • 状态变化判断:新增lastChargingState变量,只有当当前充电状态和上一次不同时才触发播放,彻底避免重复触发。
  • MediaPlayer统一管理:只用一个MediaPlayer实例,每次播放前先释放旧资源,防止多个实例同时播放,也减少内存占用。
  • 生命周期完善:在onDestroy()里注销广播和释放MediaPlayer,避免内存泄漏。
  • 移除冗余标记:不再需要playedOnceOn/playedOnceOff,因为状态变化判断已经保证了只有状态切换时才播放。

这样修改后,不管是首次连接充电线还是快速插拔,都只会播放一次提示音啦~

内容的提问来源于stack exchange,提问作者Paul E

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:31:21