Android通知栏播放字节数组转换音频文件的实现方法
将音频Byte数组转为可播放的音频文件(Android平台)
嘿,你这个思路完全没问题——把音频byte数组写入临时文件再用MediaPlayer播放,我来帮你补全代码,还会加上通知栏播放的实现细节,适配Android的最新要求~
1. 基础版:Byte数组转临时文件+MediaPlayer播放
先给你补全完整的基础播放代码,包含异常处理和资源释放:
// 假设这是你的音频byte数组 byte[] mp3SoundByteArray = ...; try { // 创建应用私有缓存目录下的临时MP3文件,应用退出时自动删除 File tempMp3 = File.createTempFile("temp_audio", ".mp3", getCacheDir()); tempMp3.deleteOnExit(); // 将byte数组写入临时文件 FileOutputStream fos = new FileOutputStream(tempMp3); fos.write(mp3SoundByteArray); fos.close(); // 初始化MediaPlayer并设置播放逻辑 MediaPlayer mediaPlayer = new MediaPlayer(); mediaPlayer.setDataSource(tempMp3.getAbsolutePath()); mediaPlayer.prepareAsync(); // 异步准备,避免阻塞主线程引发ANR // 准备完成后开始播放 mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { @Override public void onPrepared(MediaPlayer mp) { mp.start(); // 这里可以触发通知栏显示逻辑 showPlaybackNotification(mp); } }); // 监听播放错误,及时释放资源 mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() { @Override public boolean onError(MediaPlayer mp, int what, int extra) { Toast.makeText(getApplicationContext(), "音频播放失败", Toast.LENGTH_SHORT).show(); mp.release(); return true; } }); // 播放结束后自动释放资源并移除通知 mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { mp.release(); NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); notificationManager.cancel(1); } }); } catch (IOException e) { e.printStackTrace(); Toast.makeText(getApplicationContext(), "临时文件创建失败", Toast.LENGTH_SHORT).show(); }
几个关键细节要注意:
- 用
getCacheDir()创建的文件属于应用私有缓存目录,不需要申请外部存储权限,Android 10+也不会有存储权限限制,非常省心。 - 一定要用
prepareAsync()而非同步的prepare(),否则在主线程执行会导致应用无响应(ANR)。 - 务必在播放完成、出错时调用
mediaPlayer.release(),避免内存泄漏。
2. 进阶版:通知栏播放控制(适配Android 8.0+)
如果要在通知栏显示播放/暂停、停止按钮,建议用前台服务实现(Android 8.0以后后台服务会被系统限制,播放音频必须用前台服务才能稳定运行)。
第一步:创建音频播放服务
public class AudioPlaybackService extends Service { private MediaPlayer mediaPlayer; private static final int NOTIFICATION_ID = 1; private static final String CHANNEL_ID = "AUDIO_PLAYBACK_CHANNEL"; @Override public void onCreate() { super.onCreate(); // Android 8.0+必须创建通知渠道 createNotificationChannel(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { // 接收从Activity传入的音频byte数组 byte[] mp3ByteArray = intent.getByteArrayExtra("AUDIO_BYTE_ARRAY"); if (mp3ByteArray != null) { try { File tempMp3 = File.createTempFile("service_audio", ".mp3", getCacheDir()); tempMp3.deleteOnExit(); FileOutputStream fos = new FileOutputStream(tempMp3); fos.write(mp3ByteArray); fos.close(); mediaPlayer = new MediaPlayer(); mediaPlayer.setDataSource(tempMp3.getAbsolutePath()); mediaPlayer.prepareAsync(); mediaPlayer.setOnPreparedListener(mp -> { mp.start(); // 启动前台服务并显示通知 startForeground(NOTIFICATION_ID, createPlaybackNotification()); }); mediaPlayer.setOnCompletionListener(mp -> { mp.release(); stopForeground(true); stopSelf(); }); mediaPlayer.setOnErrorListener((mp, what, extra) -> { mp.release(); stopForeground(true); stopSelf(); return true; }); } catch (IOException e) { e.printStackTrace(); stopSelf(); } } return START_STICKY; } // 创建带播放控制按钮的通知 private Notification createPlaybackNotification() { // 暂停按钮的Intent Intent pauseIntent = new Intent(this, AudioPlaybackService.class); pauseIntent.setAction("ACTION_PAUSE"); PendingIntent pausePendingIntent = PendingIntent.getService(this, 0, pauseIntent, PendingIntent.FLAG_IMMUTABLE); // 停止按钮的Intent Intent stopIntent = new Intent(this, AudioPlaybackService.class); stopIntent.setAction("ACTION_STOP"); PendingIntent stopPendingIntent = PendingIntent.getService(this, 1, stopIntent, PendingIntent.FLAG_IMMUTABLE); NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID) .setSmallIcon(R.drawable.ic_audio) // 替换成你的图标 .setContentTitle("正在播放音频") .setContentText("临时音频文件") .setPriority(NotificationCompat.PRIORITY_LOW) .addAction(R.drawable.ic_pause, "暂停", pausePendingIntent) // 替换成你的暂停图标 .addAction(R.drawable.ic_stop, "停止", stopPendingIntent) // 替换成你的停止图标 .setStyle(new androidx.media.app.NotificationCompat.MediaStyle() .setShowActionsInCompactView(0, 1)); // 在紧凑视图显示控制按钮 return builder.build(); } // 创建通知渠道(Android 8.0+必填) private void createNotificationChannel() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "音频播放", NotificationManager.IMPORTANCE_LOW); channel.setDescription("用于显示音频播放控制通知"); NotificationManager notificationManager = getSystemService(NotificationManager.class); notificationManager.createNotificationChannel(channel); } } @Override public IBinder onBind(Intent intent) { return null; } @Override public void onDestroy() { super.onDestroy(); if (mediaPlayer != null) { mediaPlayer.release(); } } }
第二步:在Activity中启动服务
Intent serviceIntent = new Intent(this, AudioPlaybackService.class); serviceIntent.putExtra("AUDIO_BYTE_ARRAY", mp3SoundByteArray); // Android 8.0+用startForegroundService,旧版本用startService if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { startForegroundService(serviceIntent); } else { startService(serviceIntent); }
第三步:在Manifest中注册服务
别忘了在AndroidManifest.xml里添加服务声明:
<service android:name=".AudioPlaybackService" />
3. 额外提醒
- 临时文件清理:
deleteOnExit()会在应用退出时自动删除临时文件,你也可以在播放完成后主动调用tempMp3.delete()提前清理。 - 播放控制逻辑扩展:上面的服务只实现了基础播放,你可以在
onStartCommand中判断Intent的Action,添加暂停、继续播放的逻辑。 - 兼容性:
PendingIntent.FLAG_IMMUTABLE是Android 12+推荐的,如果你要兼容更低版本,可以根据SDK版本切换为FLAG_UPDATE_CURRENT。
内容的提问来源于stack exchange,提问作者Proxy Hossain
相关产品推荐
相关产品推荐

