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

如何在SharedPreferences中保存文件Uri并在MediaPlayer中调用?报错排查

解决MediaPlayer使用保存的Content Uri时抛出IllegalStateException的问题

问题原因

  • 临时权限失效:ActivityResultContracts.GetContent()返回的content://类型Uri仅拥有临时访问权限,App重启后权限会被回收,直接使用保存的Uri字符串解析后访问会触发权限异常。
  • 无效Uri解析:你的uri()方法中默认值是空字符串,Uri.parse("")会生成一个无效的Uri对象,传入MediaPlayer会导致状态异常。
  • MediaPlayer状态错误:如果调用setDataSource时MediaPlayer处于非空闲/未重置状态,也会抛出IllegalStateException。

解决方案

1. 获取并保存永久Uri权限

在选择文件后,通过ContentResolver.takePersistableUriPermission获取永久访问权限,确保App重启后仍能访问该文件:

val resultLauncher = registerForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? ->
    uri?.let {
        // 申请永久读权限
        val takeFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION
        contentResolver.takePersistableUriPermission(it, takeFlags)
        // 保存Uri字符串到SharedPreferences
        val settings = getSharedPreferences("Settings", Context.MODE_PRIVATE)
        settings.edit().putString("customtimersound", it.toString()).apply()
    }
}

resultLauncher.launch("audio/*")

2. 修正Uri解析逻辑

避免解析空字符串生成无效Uri,返回可空类型并做判空处理:

fun uri(context: Context): Uri? {
    val settings: SharedPreferences = context.getSharedPreferences("Settings", Context.MODE_PRIVATE)
    val uriString = settings.getString("customtimersound", null)
    return uriString?.let { Uri.parse(it) }
}

3. 规范MediaPlayer使用流程

确保调用setDataSource前MediaPlayer处于正确状态(如重置后),并对Uri做非空判断:

val audioUri = SettingsActivity.uri(this@MainActivity)
audioUri?.let {
    val mediaPlayer = MediaPlayer().apply {
        reset() // 重置到空闲状态
        try {
            setDataSource(this@MainActivity, it)
            prepareAsync() // 异步准备避免阻塞主线程
        } catch (e: IOException) {
            // 处理文件读取异常
            e.printStackTrace()
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 03:04:58