Android Studio中使用Intent访问文件遇异常及文件位置问题
Android使用Intent访问图片/音频:解决FileUriExposedException与"media not found"问题
问题背景
作为Android Studio新手,尝试用Intent访问设备图片和音频,原代码使用Uri.fromFile()触发FileUriExposedException,已配置FileProvider,但修改后点击按钮提示"media not found",文件放在storage/emulated/0/image.png,需修正代码并确认文件位置。
原错误代码(触发FileUriExposedException)
public class MainActivity extends AppCompatActivity { private Button mBtnPlayMP3, mBtnViewImg; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mBtnPlayMP3 = (Button)findViewById(R.id.btnPlayMP3); mBtnViewImg = (Button)findViewById(R.id.btnViewImg); mBtnPlayMP3.setOnClickListener(btnPlayMP3OnClick); mBtnViewImg.setOnClickListener(btnViewImgOnClick); } private View.OnClickListener btnPlayMP3OnClick = new View.OnClickListener() { public void onClick(View v) { Intent it = new Intent(Intent.ACTION_VIEW); String sMp3File = Environment.getExternalStorageDirectory().getPath() + File.separator + "song.mp3"; File file = new File(sMp3File); boolean b = file.exists(); it.setDataAndType(Uri.fromFile(file), "audio/*"); startActivity(it); } }; private View.OnClickListener btnViewImgOnClick = new View.OnClickListener() { public void onClick(View v) { Intent it = new Intent(Intent.ACTION_VIEW); String sImgFile = Environment.getExternalStorageDirectory().getPath() + File.separator + "image.png"; File file = new File(sImgFile); it.setDataAndType(Uri.fromFile(file), "image/*"); startActivity(it); } }; }
触发的错误
android.os.FileUriExposedException: file:///storage/emulated/0/image.png exposed beyond app through Intent.getData()
已完成的FileProvider配置
AndroidManifest.xml中的配置
<provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.provider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/provider_paths" /> </provider>
res/xml/provider_paths.xml配置(优化后)
<?xml version="1.0" encoding="utf-8"?> <paths> <!-- 单个external-path即可覆盖外部存储根目录,无需重复定义 --> <external-path name="external_files" path="."/> </paths>
修正后的完整MainActivity代码
import android.content.Intent; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.view.View; import android.widget.Button; import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; import androidx.core.content.FileProvider; import java.io.File; import java.util.Objects; public class MainActivity extends AppCompatActivity { private Button mBtnPlayMP3, mBtnViewImg; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mBtnPlayMP3 = findViewById(R.id.btnPlayMP3); mBtnViewImg = findViewById(R.id.btnViewImg); mBtnPlayMP3.setOnClickListener(btnPlayMP3OnClick); mBtnViewImg.setOnClickListener(btnViewImgOnClick); } private final View.OnClickListener btnPlayMP3OnClick = new View.OnClickListener() { @Override public void onClick(View v) { openMediaFile("song.mp3", "audio/*"); } }; private final View.OnClickListener btnViewImgOnClick = new View.OnClickListener() { @Override public void onClick(View v) { openMediaFile("image.png", "image/*"); } }; // 封装通用方法,减少重复代码 private void openMediaFile(String fileName, String mimeType) { File externalDir = Environment.getExternalStorageDirectory(); File mediaFile = new File(externalDir, fileName); // 先检查文件是否存在 if (!mediaFile.exists()) { Toast.makeText(this, "文件不存在:" + mediaFile.getAbsolutePath(), Toast.LENGTH_LONG).show(); return; } Uri fileUri; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { // Android 7.0及以上使用FileProvider生成安全Uri fileUri = FileProvider.getUriForFile( Objects.requireNonNull(getApplicationContext()), BuildConfig.APPLICATION_ID + ".provider", mediaFile); } else { // 低版本直接使用文件Uri fileUri = Uri.fromFile(mediaFile); } Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(fileUri, mimeType); // 授予临时读取权限 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // 检查是否有应用能处理该Intent,避免崩溃 if (intent.resolveActivity(getPackageManager()) != null) { startActivity(intent); } else { Toast.makeText(this, "没有找到可打开该文件的应用", Toast.LENGTH_LONG).show(); } } }
文件位置与权限说明
文件放置位置
- 你当前放置的
storage/emulated/0/image.png是正确的,对应手机文件管理器的「内部存储」根目录。 - 务必确认文件名及后缀完全匹配(Android文件名区分大小写,比如不要写成
Image.png或image.PNG)。
- 你当前放置的
必要权限配置
在AndroidManifest.xml中添加对应权限:<!-- Android 10及以下需要 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <!-- Android 13及以上,针对图片/音频需单独申请权限 --> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />动态权限申请(必填,针对Android 6.0+)
如果应用目标SDK为API 23及以上,需在运行时请求权限,否则会因权限不足导致无法访问文件,出现"media not found"。在MainActivity中添加以下代码:import android.Manifest; import android.content.pm.PackageManager; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; private static final int REQUEST_PERMISSION_CODE = 100; @Override protected void onStart() { super.onStart(); checkStoragePermissions(); } private void checkStoragePermissions() { boolean hasPermission; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { hasPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_MEDIA_IMAGES) == PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(this, Manifest.permission.READ_MEDIA_AUDIO) == PackageManager.PERMISSION_GRANTED; } else { hasPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED; } if (!hasPermission) { String[] permissions; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { permissions = new String[]{Manifest.permission.READ_MEDIA_IMAGES, Manifest.permission.READ_MEDIA_AUDIO}; } else { permissions = new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}; } ActivityCompat.requestPermissions(this, permissions, REQUEST_PERMISSION_CODE); } } @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_PERMISSION_CODE) { boolean allGranted = true; for (int result : grantResults) { if (result != PackageManager.PERMISSION_GRANTED) { allGranted = false; break; } } if (!allGranted) { Toast.makeText(this, "需要授予存储权限才能访问文件", Toast.LENGTH_LONG).show(); } } }
内容的提问来源于stack exchange,提问作者Lo Dennis
相关产品推荐
相关产品推荐

