Android收音机应用点击返回键后自动关闭,如何修复?
解决Android收音机应用后台运行被强制停止的问题
核心问题分析
你的应用在后台被系统回收,导致MyPlayService的onDestroy()被调用,本质原因是普通后台Service在Android 8.0+系统中优先级极低,容易被系统杀死,同时当前代码没有做前台服务的适配,也存在一些Service逻辑的小问题。
以下是具体修复方案:
一、将Service改为前台服务(关键修复)
Android 8.0(API 26)及以上版本对后台Service有严格限制,必须将播放音频的Service改为前台服务,才能保证后台稳定运行。
修改MyPlayService的onStartCommand方法
添加前台服务通知逻辑:
import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; import android.os.Build; import androidx.core.app.NotificationCompat; @Override public int onStartCommand(Intent intent, int flags, int startId) { System.out.println("onStartCommand"); link = intent.getStringExtra("AudioLink"); mediaPlayer.reset(); musicStoppedListener = (MusicStoppedListener) ApplicationClass.context; // 初始化前台服务通知 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // 创建通知渠道(API26+必须) NotificationChannel channel = new NotificationChannel( "radio_play_channel", "电台播放", NotificationManager.IMPORTANCE_LOW ); NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); manager.createNotificationChannel(channel); Notification notification = new NotificationCompat.Builder(this, "radio_play_channel") .setContentTitle("Yes Radio 正在播放") .setContentText("https://radio.lankayes.lk/8002/stream") .setSmallIcon(R.drawable.ic_notification) // 替换为你的通知图标 .setPriority(NotificationCompat.PRIORITY_LOW) .build(); startForeground(1, notification); } else { // 适配低版本系统 Notification notification = new NotificationCompat.Builder(this) .setContentTitle("Yes Radio 正在播放") .setContentText("https://radio.lankayes.lk/8002/stream") .setSmallIcon(R.drawable.ic_notification) .setPriority(NotificationCompat.PRIORITY_LOW) .build(); startForeground(1, notification); } if (!mediaPlayer.isPlaying()) { try { mediaPlayer.setDataSource(link); mediaPlayer.prepareAsync(); } catch (Exception e) { Toast.makeText(this, "播放错误:" + e.getMessage(), Toast.LENGTH_SHORT).show(); } } return START_STICKY; }
在AndroidManifest.xml中添加权限
<!-- 前台服务权限 --> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <!-- API33+需要的通知权限 --> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
二、优化onBackPressed方法
保留moveTaskToBack(true)即可,不需要额外启动Home页的Intent,避免不必要的操作:
@Override public void onBackPressed(){ System.out.println("onBackPressed"); // 将应用任务移到后台,Activity不会被销毁 moveTaskToBack(true); }
三、修复Service的潜在逻辑问题
- 避免重复重置MediaPlayer
修改onStartCommand,只有当播放链接变化时才重置播放器:
@Override public int onStartCommand(Intent intent, int flags, int startId) { System.out.println("onStartCommand"); String newLink = intent.getStringExtra("AudioLink"); // 仅当链接变化时重置播放器 if (newLink != null && !newLink.equals(link)) { link = newLink; mediaPlayer.reset(); try { mediaPlayer.setDataSource(link); mediaPlayer.prepareAsync(); } catch (Exception e) { Toast.makeText(this, "播放错误:" + e.getMessage(), Toast.LENGTH_SHORT).show(); } } // 前台服务通知代码... return START_STICKY; }
- 处理MediaPlayer错误,防止Service被系统销毁
在onError方法中返回true,表示自行处理错误,避免系统终止Service:
@Override public boolean onError(MediaPlayer mediaPlayer, int what, int i1) { System.out.println("onError"); switch (what) { case MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK: Toast.makeText(this, "播放格式不支持", Toast.LENGTH_SHORT).show(); break; case MediaPlayer.MEDIA_ERROR_SERVER_DIED: Toast.makeText(this, "服务器连接失败", Toast.LENGTH_SHORT).show(); break; case MediaPlayer.MEDIA_ERROR_UNKNOWN: Toast.makeText(this, "未知播放错误", Toast.LENGTH_SHORT).show(); break; } // 返回true,告诉系统已处理错误,不要销毁Service return true; }
四、优化Service启动方式
在MainActivity的playAudio方法中,适配API26+的前台服务启动要求:
private void playAudio() { System.out.println("playAudio"); serviceIntent.putExtra("AudioLink", stream); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { startForegroundService(serviceIntent); } else { startService(serviceIntent); } }
测试验证
- 启动应用,点击播放按钮开始播放电台
- 点击返回键,应用退到后台
- 观察日志,确认
MyPlayService的onDestroy()不会被调用 - 检查通知栏是否显示前台服务通知(Android8.0+)
内容的提问来源于stack exchange,提问作者Poorna Senani Gamage
相关产品推荐
相关产品推荐

