如何在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
相关产品推荐
相关产品推荐

