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

MediaStore.Audio.Radio示例缺失及安卓应用离线电台播放需求

我完全懂你找不到安卓Radio相关资源的郁闷——毕竟这个功能从API Level 21才新增,而且日常用的人不多,网上资料确实稀缺。下面直接给你MediaStore.Audio.Radio的实用示例,以及离线电台播放的实现思路,帮你在自己的应用里搞定需求:

一、MediaStore.Audio.Radio 基础操作示例

首先,你需要先申请必要的权限:

  • READ_EXTERNAL_STORAGE(读取系统电台数据)
  • INTERNET(在线播放电台)
  • RECORD_AUDIO & WRITE_EXTERNAL_STORAGE(离线录制用,高版本Android需要适配MANAGE_EXTERNAL_STORAGE)

1. 获取系统电台列表

// 查询系统中的电台信息
val projection = arrayOf(
    MediaStore.Audio.Radio._ID,
    MediaStore.Audio.Radio.NAME,
    MediaStore.Audio.Radio.STREAM_URI,
    MediaStore.Audio.Radio.FREQUENCY
)

val cursor = contentResolver.query(
    MediaStore.Audio.Radio.EXTERNAL_CONTENT_URI,
    projection,
    null,
    null,
    "${MediaStore.Audio.Radio.NAME} ASC"
)

cursor?.use {
    while (it.moveToNext()) {
        val id = it.getLong(it.getColumnIndexOrThrow(MediaStore.Audio.Radio._ID))
        val name = it.getString(it.getColumnIndexOrThrow(MediaStore.Audio.Radio.NAME))
        val streamUri = it.getString(it.getColumnIndexOrThrow(MediaStore.Audio.Radio.STREAM_URI))
        val frequency = it.getInt(it.getColumnIndexOrThrow(MediaStore.Audio.Radio.FREQUENCY))
        
        // 这里可以把电台信息存到自定义的数据类里,供后续使用
        println("电台:$name,频率:$frequency,流地址:$streamUri")
    }
}

2. 在线播放电台

用MediaPlayer来播放电台流:

private var mediaPlayer: MediaPlayer? = null

fun playRadio(streamUri: String) {
    mediaPlayer?.release()
    mediaPlayer = MediaPlayer().apply {
        setAudioAttributes(
            AudioAttributes.Builder()
                .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
                .setUsage(AudioAttributes.USAGE_MEDIA)
                .build()
        )
        setDataSource(streamUri)
        prepareAsync()
        setOnPreparedListener { start() }
        setOnErrorListener { _, what, extra ->
            println("播放出错:what=$what, extra=$extra")
            true
        }
    }
}

// 记得在页面销毁时释放资源
override fun onDestroy() {
    super.onDestroy()
    mediaPlayer?.release()
    mediaPlayer = null
}
二、离线电台播放实现思路

要实现离线播放,核心是录制电台流到本地文件,之后播放本地文件即可:

1. 录制电台流

可以直接通过网络请求读取流并写入文件(比MediaRecorder更灵活):

fun recordRadioToFile(streamUri: String, outputPath: String) {
    CoroutineScope(Dispatchers.IO).launch {
        try {
            val url = URL(streamUri)
            val connection = url.openConnection() as HttpURLConnection
            connection.doInput = true
            connection.connect()
            
            val inputStream = connection.inputStream
            val outputStream = FileOutputStream(outputPath)
            
            val buffer = ByteArray(4096)
            var bytesRead: Int
            while (inputStream.read(buffer).also { bytesRead = it } != -1) {
                outputStream.write(buffer, 0, bytesRead)
            }
            
            inputStream.close()
            outputStream.close()
            connection.disconnect()
            
            // 录制完成,通知主线程更新UI
            withContext(Dispatchers.Main) {
                println("录制完成,文件路径:$outputPath")
            }
        } catch (e: Exception) {
            e.printStackTrace()
            withContext(Dispatchers.Main) {
                println("录制失败:${e.message}")
            }
        }
    }
}

2. 播放本地录制的电台文件

直接用MediaPlayer播放本地文件路径即可,和播放普通音频文件一样:

fun playOfflineRadio(localFilePath: String) {
    mediaPlayer?.release()
    mediaPlayer = MediaPlayer().apply {
        setAudioAttributes(
            AudioAttributes.Builder()
                .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
                .setUsage(AudioAttributes.USAGE_MEDIA)
                .build()
        )
        setDataSource(localFilePath)
        prepareAsync()
        setOnPreparedListener { start() }
    }
}
注意事项
  • 高版本Android(13+)需要单独申请POST_NOTIFICATIONS权限,否则后台播放可能被限制
  • 录制的文件格式建议用.mp3或者.m4a,保证兼容性
  • 处理电台流时要注意网络异常,比如断网时要及时停止录制或播放

内容的提问来源于stack exchange,提问作者Sagar Adhikari

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 11:29:46