Android:音频Uri存入SharedPreferences后MediaPlayer调用setDataSource失败
问题分析与解决办法
我来帮你梳理下遇到的问题,以及对应的修复方案:
1. 核心问题:错误的Uri编码操作
你在LoadSettings()里调用了Uri.encode(str)再解析,这是完全多余的操作!uri.toString()本身就是该Uri的标准字符串表示,强行编码会把content://这类格式转成content%3A//,导致解析后的Uri完全无效,自然找不到音频资源。
修正后的LoadSettings方法:
private Uri LoadSettings() { SharedPreferences pref = getSharedPreferences(APP, MODE_PRIVATE); String str = pref.getString("uri", null); if(str == null) { return null; } // 直接解析原始字符串,不需要编码 return Uri.parse(str); }
2. 隐藏坑:Content Uri的持久化权限
通过Intent.ACTION_PICK获取的音频Uri大多是content://开头的内容Uri,这类Uri的访问权限是临时的——App重启后,系统会收回这个临时权限,导致你即使解析出正确的Uri,也无法访问对应的资源。
解决办法:申请持久化Uri权限
在你获取到Uri的onActivityResult方法里,调用ContentResolver.takePersistableUriPermission()把临时权限转为持久权限:
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK && requestCode == YOUR_PICK_REQUEST_CODE) { Uri selectedUri = data.getData(); if (selectedUri != null) { // 获取Intent中的权限标记 int takeFlags = data.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); // 申请持久化权限 getContentResolver().takePersistableUriPermission(selectedUri, takeFlags); // 再保存Uri SaveSettings(selectedUri); } } }
注:这个操作不需要在Manifest中额外声明权限,因为ACTION_PICK已经隐含了临时访问权限,我们只是把它转为持久有效。
3. MediaPlayer的优化建议
你的PlaySound方法存在资源泄漏和阻塞UI的风险,建议做以下调整:
private void PlaySound() { // 复用MediaPlayer实例,避免频繁创建 if (_mp == null) { _mp = new MediaPlayer(); _mp.setOnErrorListener((mp, what, extra) -> { Log.e("MediaPlayer", "播放错误: code=" + what + ", extra=" + extra); mp.release(); _mp = null; return true; }); } if (!_paused) { try { _mp.reset(); _mp.setDataSource(this, _uri); // 用异步prepare避免阻塞UI线程 _mp.prepareAsync(); _mp.setOnPreparedListener(MediaPlayer::start); } catch (IOException e) { Log.e("PlaySound", "设置数据源失败", e); } } else { _mp.start(); } _paused = false; }
另外,记得在App销毁时释放MediaPlayer资源:
@Override protected void onDestroy() { super.onDestroy(); if (_mp != null) { _mp.release(); _mp = null; } }
内容的提问来源于stack exchange,提问作者Blondy314
相关产品推荐
相关产品推荐

