android10分区镜像,android 10 分区储存适配

搜索文档

以下代码段使用 `[ACTION_OPEN_DOCUMENT]来搜索包含图片文件的文档提供程序:

{".3gp", "video/3gpp"},

{".apk", "application/vnd.android.package-archive"},

{".asf", "video/x-ms-asf"},

{".avi", "video/x-msvideo"},

{".bin", "application/octet-stream"},

{".bmp", "image/bmp"},

{".c", "text/plain"},

{".class", "application/octet-stream"},

{".conf", "text/plain"},

{".cpp", "text/plain"},

{".doc", "application/msword"},

{".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"},

{".xls", "application/vnd.ms-excel"},

{".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"},

{".exe", "application/octet-stream"},

{".gif", "image/gif"},

{".gtar", "application/x-gtar"},

{".gz", "application/x-gzip"},

{".h", "text/plain"},

{".htm", "text/html"},

{".html", "text/html"},

{".jar", "application/java-archive"},

{".java", "text/plain"},

{".jpeg", "image/jpeg"},

{".jpg", "image/jpeg"},

{".js", "application/x-javascript"},

{".log", "text/plain"},

{".m3u", "audio/x-mpegurl"},

{".m4a", "audio/mp4a-latm"},

{".m4b", "audio/mp4a-latm"},

{".m4p", "audio/mp4a-latm"},

{".m4u", "video/vnd.mpegurl"},

{".m4v", "video/x-m4v"},

{".mov", "video/quicktime"},

{".mp2", "audio/x-mpeg"},

{".mp3", "audio/x-mpeg"},

{".mp4", "video/mp4"},

{".mpc", "application/vnd.mpohun.certificate"},

{".mpe", "video/mpeg"},

{".mpeg", "video/mpeg"},

{".mpg", "video/mpeg"},

{".mpg4", "video/mp4"},

{".mpga", "audio/mpeg"},

{".msg", "application/vnd.ms-outlook"},

{".ogg", "audio/ogg"},

{".pdf", "application/pdf"},

{".png", "image/png"},

{".pps", "application/vnd.ms-powerpoint"},

{".ppt", "application/vnd.ms-powerpoint"},

{".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"},

{".prop", "text/plain"},

{".rc", "text/plain"},

{".rmvb", "audio/x-pn-realaudio"},

{".rtf", "application/rtf"},

{".sh", "text/plain"},

{".tar", "application/x-tar"},

{".tgz", "application/x-compressed"},

{".txt", "text/plain"},

{".wav", "audio/x-wav"},

{".wma", "audio/x-ms-wma"},

{".wmv", "audio/x-ms-wmv"},

{".wps", "application/vnd.ms-works"},

{".xml", "text/plain"},

{".z", "application/x-compress"},

{".zip", "application/x-zip-compressed"},

{"", "*/*"}

};

————————————————

版权声明:本文为CSDN博主「Work_Times」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/qq_34099401/article/details/64439869

private const val READ_REQUEST_CODE: Int = 42

...

/**

* Fires an intent to spin up the "file chooser" UI and select an image.

*/

fun performFileSearch() {

// ACTION_OPEN_DOCUMENT is the intent to choose a file via the system's file

// browser.

val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {

// Filter to only show results that can be "opened", such as a

// file (as opposed to a list of contacts or timezones)

addCategory(Intent.CATEGORY_OPENABLE)

// Filter to show only images, using the image MIME data type.

// If one wanted to search for ogg vorbis files, the type would be "audio/ogg".

// To search for all documents available via installed storage providers,

// it would be "*/*".

type = "image/*"

}

startActivityForResult(intent, READ_REQUEST_CODE)

}

当应用触发 `[ACTION_OPEN_DOCUMENT] Intent 时,该 Intent 会启动选择器,以显示所有匹配的文档提供程序。

在 Intent 中添加 `[CATEGORY_OPENABLE]类别可对结果进行过滤,从而只显示可打开的文档(如图片文件)。

intent.setType("image/*") 语句可做进一步过滤,从而只显示 MIME 数据类型为图像的文档。

处理结果

当用户在选择器中选择文档后,系统会调用 [onActivityResult()]。resultData参数包含指向所选文档的 URI。您可以使用getData()` 提取该 URI。获得 URI 后,您可以用它来检索用户所需文档。例如:

override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {

// The ACTION_OPEN_DOCUMENT intent was sent with the request code

// READ_REQUEST_CODE. If the request code seen here doesn't match, it's the

// response to some other intent, and the code below shouldn't run at all.

if (requestCode == READ_REQUEST_CODE && resultCode == Activity.RESULT_OK) {

// The document selected by the user won't be returned in the intent.

// Instead, a URI to that document will be contained in the return intent

// provided to this method as a parameter.

// Pull that URI using resultData.getData().

resultData?.data?.also { uri ->

Log.i(TAG, "Uri: $uri")

showImage(uri)

}

}

}

fun dumpImageMetaData(uri: Uri) {

// The query, since it only applies to a single document, will only return

// one row. There's no need to filter, sort, or select fields, since we want

// all fields for one document.

val cursor: Cursor? = contentResolver.query( uri, null, null, null, null, null)

cursor?.use {

// moveToFirst() returns false if the cursor has 0 rows. Very handy for

// "if there's anything to look at, look at it" conditionals.

if (it.moveToFirst()) {

// Note it's called "Display Name". This is

// provider-specific, and might not necessarily be the file name.

val displayName: String =

it.getString(it.getColumnIndex(OpenableColumns.DISPLAY_NAME))

Log.i(TAG, "Display Name: $displayName")

val sizeIndex: Int = it.getColumnIndex(OpenableColumns.SIZE)

// If the size is unknown, the value stored is null. But since an

// int can't be null in Java, the behavior is implementation-specific,

// which is just a fancy term for "unpredictable". So as

// a rule, check if it's null before assigning to an int. This will

// happen often: The storage API allows for remote files, whose

// size might not be locally known.

val size: String = if (!it.isNull(sizeIndex)) {

// Technically the column stores an int, but cursor.getString()

// will do the conversion automatically.

it.getString(sizeIndex)

} else {

"Unknown"

}

Log.i(TAG, "Size: $size")

}

}

}

检查文档元数据

获得文档的 URI 后,您可以访问该文档的元数据。以下代码段用于获取 URI 所指定文档的元数据,并将其记入日志:

@Throws(IOException::class)

private fun getBitmapFromUri(uri: Uri): Bitmap {

val parcelFileDescriptor: ParcelFileDescriptor = contentResolver.openFileDescriptor(uri, "r")

val fileDescriptor: FileDescriptor = parcelFileDescriptor.fileDescriptor

val image: Bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor)

parcelFileDescriptor.close()

return image

}

请注意,您不应在界面线程上执行此操作。请使用 [AsyncTask] 在后台执行此操作。打开位图后,您可以在ImageView` 中显示该位图。

获取 InputStream

以下示例展示了如何从 URI 中获取 [InputStream](https://developer.android.google.cn/reference/java/io/InputStream)。在此代码段中,系统会将文件行读取到字符串中:

@Throws(IOException::class)

private fun readTextFromUri(uri: Uri): String {

val stringBuilder = StringBuilder()

contentResolver.openInputStream(uri)?.use { inputStream ->

BufferedReader(InputStreamReader(inputStream)).use { reader ->

var line: String? = reader.readLine()

while (line != null) {

stringBuilder.append(line)

line = reader.readLine()

}

}

}

return stringBuilder.toString()

}

创建文档

您的应用可通过使用 `[ACTION_CREATE_DOCUMENT]Intent,在文档提供程序中创建新文档。如要创建文件,请为您的 Intent 提供 MIME 类型和文件名,然后使用唯一的请求代码启动该 Intent。系统会为您执行其余操作:

private const val WRITE_REQUEST_CODE: Int = 43

private fun createFile(mimeType: String, fileName: String) {

val intent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply {

// Filter to only show results that can be "opened", such as

// a file (as opposed to a list of contacts or timezones).

addCategory(Intent.CATEGORY_OPENABLE)

// Create a file with the requested MIME type.

type = mimeType

putExtra(Intent.EXTRA_TITLE, fileName)

}

startActivityForResult(intent, WRITE_REQUEST_CODE)

}

创建新文档后,您可以在 `[onActivityResult()] 中获取该文档的 URI,以便继续向其写入内容。

删除文档

如果您获得了文档的 URI,并且文档的 [Document.COLUMN_FLAGS] 包含[SUPPORTS_DELETE],则便可删除该文档。例如

DocumentsContract.deleteDocument(contentResolver, uri)

编辑文档

您可以随时使用 SAF 编辑文本文档。以下代码段会触发 [ACTION_OPEN_DOCUMENT]Intent 并使用CATEGORY_OPENABLE` 类别,从而只显示可打开的文档。它会进一步过滤,从而只显示文本文件:

private const val EDIT_REQUEST_CODE: Int = 44

/**

* Open a file for writing and append some text to it.

*/

private fun editDocument() {

// ACTION_OPEN_DOCUMENT is the intent to choose a file via the system's

// file browser.

val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {

// Filter to only show results that can be "opened", such as a

// file (as opposed to a list of contacts or timezones).

addCategory(Intent.CATEGORY_OPENABLE)

// Filter to show only text files.

type = "text/plain"

}

startActivityForResult(intent, EDIT_REQUEST_CODE)

}

接下来,您可以从 onActivityResult()(请参阅[处理结果](https://developer.android.google.cn/guide/topics/providers/document-provider#results))调用代码,以执行编辑操作。以下代码段将从ContentResolver获取FileOutputStream`。其默认使用写入模式。最佳做法是请求获得最少的所需访问权限,因此如果您只需要写入权限,请勿请求获得读取/写入权限:

private fun alterDocument(uri: Uri) {

try {

contentResolver.openFileDescriptor(uri, "w")?.use {

// use{} lets the document provider know you're done by automatically closing the stream

FileOutputStream(it.fileDescriptor).use {

it.write(

("Overwritten by MyCloud at ${System.currentTimeMillis()}\n").toByteArray()

)

}

}

} catch (e: FileNotFoundException) {

e.printStackTrace()

} catch (e: IOException) {

e.printStackTrace()

}

}

保留权限

当应用打开文件进行读取或写入时,系统会为其提供针对该文件的 URI 授权,有效期直至用户设备重启。但假定您的应用是图像编辑应用,而且您希望用户能直接从应用中访问其编辑的最后 5 张图像。如果用户的设备已重启,则您必须让用户回到系统选择器以查找这些文件,而这显然不是理想的做法。

为防止出现此情况,您可以保留系统向应用授予的权限。实际上,您的应用是“获取”了系统提供的 URI 持久授权。如此一来,用户便可通过您的应用持续访问文件,即使设备已重启也不受影响:

val takeFlags: Int = intent.flags and

(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)

// Check for the freshest data.

contentResolver.takePersistableUriPermission(uri, takeFlags)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值