Android开发:按下Home键时如何暂停播放中的音频?
嘿,这个问题我之前做音频相关功能时也碰到过,先说说你用public static MediaPlayer的方式——确实能解决问题,但这种做法其实有不少隐患,咱们先分析下,再给你几个更合理的解决方案:
首先说static的问题:
- Static修饰的对象会一直留在内存里,除非整个App进程被销毁,很容易造成不必要的内存占用,如果忘记释放甚至会导致内存泄漏。
- 如果用户连续打开多个
playAudioDialog,static的mp会被新的实例覆盖,之前的音频控制就完全混乱了,体验很差。
接下来给你几个更靠谱的实现方式:
方案一:让Dialog绑定宿主Activity的生命周期
因为Dialog是依附于Activity存在的,我们可以让playAudio监听Activity的生命周期变化,这样当Activity进入后台(按Home键触发onPause)时,自动暂停音频:
public class playAudio extends Dialog implements LifecycleObserver { private MediaPlayer mp; private Context mContext; private String mSongPath; public playAudio(Context context, String songPath) { super(context); mContext = context; mSongPath = songPath; // 绑定Activity的生命周期监听 if (context instanceof AppCompatActivity) { ((AppCompatActivity) context).getLifecycle().addObserver(this); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.play_audio); mp = new MediaPlayer(); findViewById(R.id.btnPlay).setOnClickListener(v -> { try { mp.setDataSource(mSongPath); mp.prepare(); mp.start(); } catch (IOException e) { e.printStackTrace(); } }); } // 监听Activity的onPause事件,暂停音频 @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) public void onActivityPause() { if (mp != null && mp.isPlaying()) { mp.pause(); } } // 监听Activity的onResume事件,继续播放 @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) public void onActivityResume() { if (mp != null && !mp.isPlaying()) { mp.start(); } } // 销毁Dialog时记得释放资源和移除监听 @Override public void dismiss() { super.dismiss(); if (mContext instanceof AppCompatActivity) { ((AppCompatActivity) mContext).getLifecycle().removeObserver(this); } if (mp != null) { mp.release(); mp = null; } } }
注意:这个方案需要依赖AndroidX的Lifecycle库,你需要在build.gradle里添加依赖(如果还没加的话):
implementation "androidx.lifecycle:lifecycle-common:2.6.1"
方案二:封装单例音频管理类
把音频播放的逻辑统一放到一个单例类里,不管是Dialog还是Activity都通过这个类来控制音频,这样就不需要传递MediaPlayer对象了:
首先写音频管理类:
public class AudioPlayerManager { private static AudioPlayerManager sInstance; private MediaPlayer mMediaPlayer; private AudioPlayerManager() {} // 获取单例实例 public static synchronized AudioPlayerManager getInstance() { if (sInstance == null) { sInstance = new AudioPlayerManager(); } return sInstance; } // 播放指定路径的音频 public void play(String songPath) { try { // 先释放之前的资源 if (mMediaPlayer != null) { mMediaPlayer.release(); } mMediaPlayer = new MediaPlayer(); mMediaPlayer.setDataSource(songPath); mMediaPlayer.prepare(); mMediaPlayer.start(); } catch (IOException e) { e.printStackTrace(); } } // 暂停音频 public void pause() { if (mMediaPlayer != null && mMediaPlayer.isPlaying()) { mMediaPlayer.pause(); } } // 继续播放 public void resume() { if (mMediaPlayer != null && !mMediaPlayer.isPlaying()) { mMediaPlayer.start(); } } // 释放资源 public void release() { if (mMediaPlayer != null) { mMediaPlayer.release(); mMediaPlayer = null; } } }
然后修改MainActivity的生命周期方法:
@Override protected void onPause() { AudioPlayerManager.getInstance().pause(); super.onPause(); } @Override protected void onResume() { super.onResume(); AudioPlayerManager.getInstance().resume(); }
最后修改playAudio Dialog的点击事件:
btnPlay.setOnClickListener(v -> { AudioPlayerManager.getInstance().play(songPath); });
这个方案的好处是统一管理所有音频播放逻辑,不管后续扩展其他播放场景(比如通知栏控制)都很方便,而且避免了static对象的内存问题。
方案三:监听Dialog自身的窗口可见性
如果不想依赖Activity的生命周期,也可以直接监听Dialog的窗口状态,当窗口不可见时暂停音频:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.play_audio); mp = new MediaPlayer(); // 监听窗口可见性变化 getWindow().getDecorView().getViewTreeObserver().addOnWindowVisibilityChangeListener(visibility -> { if (visibility == View.INVISIBLE) { // 窗口不可见(按Home键时会触发),暂停音频 if (mp != null && mp.isPlaying()) { mp.pause(); } } else if (visibility == View.VISIBLE) { // 窗口重新可见,继续播放 if (mp != null && !mp.isPlaying()) { mp.start(); } } }); btnPlay.setOnClickListener(v -> { try { mp.setDataSource(songPath); mp.prepare(); mp.start(); } catch (IOException e) { e.printStackTrace(); } }); }
这个方案更轻量化,不需要额外依赖,只针对Dialog自身的状态做处理,适合简单的场景。
总结一下,如果你只是简单的Dialog播放音频,方案三或者方案一都可以;如果后续有更多音频相关的功能,推荐方案二,扩展性更强。
内容的提问来源于stack exchange,提问作者Saba
相关产品推荐
相关产品推荐

