android Q对于文件读写引入了新特性,在这个版本中,READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE均受到了限制,无法再像之前的版本直接获取到文件。
获取到文件夹的对象之后,调用listFiles()方法尝试获取该目录下面的文件时出现了问题,返回值永远是null,在网上查找了一番之后基本都指向了权限问题,但是通过调试可以确认我已经获取到了读写权限,但是仍然返回的是空。
如果希望恢复之前的权限逻辑,可以在manifest文件中设置:android:requestLegacyExternalStorage="true"
(但是不推荐此方法因为在下一个版本的Android中,此条配置将会失效,将强制采用外部储存限制。其实早在Android Q Beta 3之前都是强制的,但为了给开发者适配的时间才没有强制执行。所以如果你不抓住这段时间去适配,那么今年下半年出了Android 11。。。直接开花~~)以前我们习惯使用Environment.getExternalStorageDirectory()方法,那么现在可以使用getExternalFilesDir()方法(包括下载的安装包这类的文件)。如果是缓存类型文件,可以放到getExternalCacheDir()路径下。
现在 为了便于不影响之前选择图片返回File的逻辑(因为一般都是上传File,没有直接上传Uri的操作),所以我将最终选择的文件又转存进了getExternalFilesDir(),主要代码如下:
参考的推文方法
File imgFile = this.getExternalFilesDir("image");
if (!imgFile.exists()){
imgFile.mkdir();
}
try {
File file = new File(imgFile.getAbsolutePath() + File.separator +
System.currentTimeMillis() + ".jpg");
// 使用openInputStream(uri)方法获取字节输入流
InputStream fileInputStream = getContentResolver().openInputStream(uri);
FileOutputStream fileOutputStream = new FileOutputStream(file);
byte[] buffer = new byte[1024];
int byteRead;
while (-1 != (byteRead = fileInputStream.read(buffer))) {
fileOutputStream.write(buffer, 0, byteRead);
}
fileInputStream.close();
fileOutputStream.flush();
fileOutputStream.close();
// 文件可用新路径 file.getAbsolutePath()
} catch (Exception e) {
e.printStackTrace();
}
我的项目中改动之后
File imgelistFile = this.getExternalFilesDir("image");
if (!img.exists()) {
img.mkdir();
}
String mFilePath = imgelistFile .getAbsolutePath() + File.separator +System.currentTimeMillis() + ".jpg";
File mImageFile = new File(mFilePath);
String mImageUri = FileProvider.getUriForFile(this, DataManager.getFileProviderName(this), mImageFile);
InputStream fileInputStream = getContentResolver().openInputStream(mImageUri );
Bitmap bitmap = BitmapFactory.decodeStream(fileInputStream); //生成Bitmap