targetSdkVersion = 30
- 分區(qū)存儲強制執(zhí)行:應用對文件的讀寫表窘,只能在沙盒環(huán)境也就是應用的專屬目錄(計入應用所占空間纵朋,隨應用卸載而刪除)采驻,其他媒體文件通過MediaStore訪問
targetSdkVersion = 29
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:requestLegacyExternalStorage="true"
android:theme="@style/Theme.MyApplication">
targetSdkVersion 覆蓋安裝可以使用 android:preserveLegacyExternalStorage="true" 暫時關閉
// targetSdkVersion = 30
val filePath1 = Environment.getExternalStoragePublicDirectory("")
val filePath = Environment.getExternalStorageDirectory()
val file = File(filePath,"me.txt")
file.createNewFile()
// 報錯:Caused by: java.io.IOException: Permission denied
幾種訪問文件的方法:
1假哎、應用專屬目錄
// sdcard == storage/emulated/0 這兩個路徑相同
// 比如me2.txt 也存在于storage/emulated/0/android/data/packageName/cache/me2.txt
// 以下目錄在android 10以下的手機 也可以創(chuàng)建并訪問
val filePath = File(filesDir,"me.txt")
filePath.createNewFile()
// 路徑:data/data/packageName/files/me.txt
val filePath2 = File(externalCacheDir,"me2.txt")
filePath2.createNewFile()
// 路徑:sdcard/android/data/packageName/cache/me2.txt
val filePath3 = File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),"me3.txt")
filePath3.createNewFile()
// 路徑:sdcard/android/data/packageName/files/download/me3.txt
val filePath4 = File(getExternalFilesDir(Environment.DIRECTORY_DCIM),"dd.jpg")
filePath4.createNewFile()
// 路徑:sdcard/android/data/packageName/files/DCIM/dd.jpg
2筐高、訪問公共媒體目錄文件
private fun intoMediaPath() {
// MediaStore.Images.Media.EXTERNAL_CONTENT_URI 根據Images關鍵字 假如查找視頻坊秸,則改為Video
val cursor = contentResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,null,null,null,
"${MediaStore.MediaColumns.DATE_ADDED} desc")
if(cursor != null){
while (cursor.moveToNext()){
val id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns._ID))
val uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,id)
Log.d("cjq","$uri")
if(i == 0){
val fd = contentResolver.openFileDescriptor(uri,"r")
fd?.let {
val bitmap = BitmapFactory.decodeFileDescriptor(it.fileDescriptor) // 圖片過大可能OOM
imageView.setImageBitmap(bitmap)
}
}
}
cursor.close()
}
}
3宣旱、SAF 存儲訪問框架( Storage Access FrameWork)
private fun intoMediaFile() {
//android 10 及以下都可用在张,配置不用的type打開不同文件位置至会,可配置*/*不做篩選
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
intent.addCategory(Intent.CATEGORY_OPENABLE)
intent.type = "image/*"
startActivityForResult(intent,100)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if(data == null ) return
val uri = data.data
val bitmap = MediaStore.Images.Media.getBitmap(contentResolver,uri) //圖片過大會OOM
imageView.setImageBitmap(bitmap)
}
4离咐、下載文件存放外部區(qū)域Download目錄
private fun downloadFile() {
if(Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) return
val values = ContentValues()
values.put(MediaStore.MediaColumns.DISPLAY_NAME, "tt.zip")
values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS)
val uri = contentResolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, values)
if (uri != null) {
val outputStream = contentResolver.openOutputStream(uri)
if (outputStream != null) {
outputStream.write(5)
}
}
}
- FileProvider使用場景
1、拍照
private fun capture() {
val takePhotoIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
val file = getExternalFilesDir(Environment.DIRECTORY_PICTURES)
val imageFile = createTempFile("cjq",".jpg",file)
uri = if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
FileProvider.getUriForFile(this,"cn.fonxnickel.officialcamerademo.fileprovider",imageFile) //需和manifest下定義的provider名稱一致
}else{
Uri.fromFile(imageFile)
}
takePhotoIntent.putExtra(MediaStore.EXTRA_OUTPUT,uri)
startActivityForResult(takePhotoIntent,10)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode != RESULT_OK) return
val bitmap = BitmapFactory.decodeStream(uri?.let { contentResolver.openInputStream(it) })
// val bitmap = MediaStore.Images.Media.getBitmap(contentResolver,uri) //圖片過大會OOM
imageView.setImageBitmap(bitmap)
}
在res下新建xml文件夾,并定義filepaths文件
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path
name="files-path"
path="." />
<cache-path
name="cache-path"
path="." />
<external-path
name="external_storage_root"
path="." />
<external-files-path
name="external_file_path"
path="." />
<external-cache-path
name="external_cache_path"
path="." />
<root-path
name="root-path"
path="" />
</paths>
在AndroidManifest下定義provider
<provider
android:authorities="cn.fonxnickel.officialcamerademo.fileprovider"
android:name="androidx.core.content.FileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths"/>
</provider>
2宵蛀、安裝apk
3昆著、應用間共享文件