搜索文檔
以下代碼段使用 `[ACTION_OPEN_DOCUMENT]來(lái)搜索包含圖片文件的文檔提供程序:
{".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"},
{"", "*/*"}
};
————————————————
版權(quán)聲明:本文為CSDN博主「Work_Times」的原創(chuàng)文章,遵循CC 4.0 BY-SA版權(quán)協(xié)議圃阳,轉(zhuǎn)載請(qǐng)附上原文出處鏈接及本聲明渤早。
原文鏈接: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)
}
- 當(dāng)應(yīng)用觸發(fā) `[ACTION_OPEN_DOCUMENT] Intent 時(shí)胁孙,該 Intent 會(huì)啟動(dòng)選擇器,以顯示所有匹配的文檔提供程序袭异。
- 在 Intent 中添加 `[CATEGORY_OPENABLE]類別可對(duì)結(jié)果進(jìn)行過濾焙糟,從而只顯示可打開的文檔(如圖片文件)。
-
intent.setType("image/*")
語(yǔ)句可做進(jìn)一步過濾晾捏,從而只顯示 MIME 數(shù)據(jù)類型為圖像的文檔蒿涎。
處理結(jié)果
當(dāng)用戶在選擇器中選擇文檔后,系統(tǒng)會(huì)調(diào)用 [onActivityResult()]惦辛。
resultData參數(shù)包含指向所選文檔的 URI劳秋。您可以使用
getData()` 提取該 URI。獲得 URI 后,您可以用它來(lái)檢索用戶所需文檔玻淑。例如:
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")
}
}
}
檢查文檔元數(shù)據(jù)
獲得文檔的 URI 后嗽冒,您可以訪問該文檔的元數(shù)據(jù)。以下代碼段用于獲取 URI 所指定文檔的元數(shù)據(jù)补履,并將其記入日志:
@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
}
請(qǐng)注意添坊,您不應(yīng)在界面線程上執(zhí)行此操作。請(qǐng)使用 [AsyncTask] 在后臺(tái)執(zhí)行此操作箫锤。打開位圖后贬蛙,您可以在
ImageView` 中顯示該位圖。
獲取 InputStream
以下示例展示了如何從 URI 中獲取 [InputStream](https://developer.android.google.cn/reference/java/io/InputStream)
谚攒。在此代碼段中阳准,系統(tǒng)會(huì)將文件行讀取到字符串中:
@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()
}
創(chuàng)建文檔
您的應(yīng)用可通過使用 `[ACTION_CREATE_DOCUMENT]Intent,在文檔提供程序中創(chuàng)建新文檔馏臭。如要?jiǎng)?chuàng)建文件野蝇,請(qǐng)為您的 Intent 提供 MIME 類型和文件名,然后使用唯一的請(qǐng)求代碼啟動(dòng)該 Intent括儒。系統(tǒng)會(huì)為您執(zhí)行其余操作:
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)
}
創(chuàng)建新文檔后绕沈,您可以在 `[onActivityResult()] 中獲取該文檔的 URI,以便繼續(xù)向其寫入內(nèi)容塑崖。
刪除文檔
如果您獲得了文檔的 URI七冲,并且文檔的 [Document.COLUMN_FLAGS] 包含
[SUPPORTS_DELETE],則便可刪除該文檔规婆。例如
DocumentsContract.deleteDocument(contentResolver, uri)
編輯文檔
您可以隨時(shí)使用 SAF 編輯文本文檔。以下代碼段會(huì)觸發(fā) [ACTION_OPEN_DOCUMENT]Intent 并使用
CATEGORY_OPENABLE` 類別蝉稳,從而只顯示可打開的文檔抒蚜。它會(huì)進(jìn)一步過濾,從而只顯示文本文件:
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)
}
接下來(lái)耘戚,您可以從 onActivityResult()(請(qǐng)參閱[處理結(jié)果](https://developer.android.google.cn/guide/topics/providers/document-provider#results))調(diào)用代碼嗡髓,以執(zhí)行編輯操作。以下代碼段將從
ContentResolver獲取
FileOutputStream`收津。其默認(rèn)使用寫入模式饿这。最佳做法是請(qǐng)求獲得最少的所需訪問權(quán)限,因此如果您只需要寫入權(quán)限撞秋,請(qǐng)勿請(qǐng)求獲得讀取/寫入權(quán)限:
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()
}
}
保留權(quán)限
當(dāng)應(yīng)用打開文件進(jìn)行讀取或?qū)懭霑r(shí)长捧,系統(tǒng)會(huì)為其提供針對(duì)該文件的 URI 授權(quán),有效期直至用戶設(shè)備重啟吻贿。但假定您的應(yīng)用是圖像編輯應(yīng)用串结,而且您希望用戶能直接從應(yīng)用中訪問其編輯的最后 5 張圖像。如果用戶的設(shè)備已重啟,則您必須讓用戶回到系統(tǒng)選擇器以查找這些文件肌割,而這顯然不是理想的做法卧蜓。
為防止出現(xiàn)此情況,您可以保留系統(tǒng)向應(yīng)用授予的權(quán)限把敞。實(shí)際上弥奸,您的應(yīng)用是“獲取”了系統(tǒng)提供的 URI 持久授權(quán)。如此一來(lái)奋早,用戶便可通過您的應(yīng)用持續(xù)訪問文件其爵,即使設(shè)備已重啟也不受影響:
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)