搜索文档
以下代码段使用 `[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)
官网