Android如何實(shí)現(xiàn)一個(gè)DocumentProvider示例詳解
前言
假如你做了一個(gè)云盤(pán)類(lèi)的app,或者可以保存用戶(hù)導(dǎo)入的配置。用戶(hù)在未來(lái)肯定需要獲取這些文件,一個(gè)辦法是寫(xiě)一個(gè)Activity,向一個(gè)文件管理軟件一樣把他們列出來(lái)。但是這個(gè)有一個(gè)問(wèn)題是用戶(hù)必須進(jìn)入app 才能訪(fǎng)問(wèn)。
現(xiàn)在有一個(gè)解決方案是實(shí)現(xiàn)一個(gè)DocumentProvider
步驟
DocumentProvider 繼承自Content Provider。
首先在Manifest 中注冊(cè)這個(gè)Provider
<provider android:name=".StorageProvider" android:authorities="com.storyteller_f.ping.documents" android:grantUriPermissions="true" android:exported="true" android:permission="android.permission.MANAGE_DOCUMENTS"> <intent-filter> <action android:name="android.content.action.DOCUMENTS_PROVIDER" /> </intent-filter> </provider>
創(chuàng)建這個(gè)Provider
class StorageProvider : DocumentsProvider() { companion object { private val DEFAULT_ROOT_PROJECTION: Array<String> = arrayOf( DocumentsContract.Root.COLUMN_ROOT_ID, DocumentsContract.Root.COLUMN_MIME_TYPES, DocumentsContract.Root.COLUMN_FLAGS, DocumentsContract.Root.COLUMN_ICON, DocumentsContract.Root.COLUMN_TITLE, DocumentsContract.Root.COLUMN_SUMMARY, DocumentsContract.Root.COLUMN_DOCUMENT_ID, DocumentsContract.Root.COLUMN_AVAILABLE_BYTES ) private val DEFAULT_DOCUMENT_PROJECTION: Array<String> = arrayOf( DocumentsContract.Document.COLUMN_DOCUMENT_ID, DocumentsContract.Document.COLUMN_MIME_TYPE, DocumentsContract.Document.COLUMN_FLAGS, DocumentsContract.Document.COLUMN_DISPLAY_NAME, DocumentsContract.Document.COLUMN_LAST_MODIFIED, DocumentsContract.Document.COLUMN_SIZE ) private const val TAG = "StorageProvider" } override fun onCreate(): Boolean { return true } }
重寫(xiě)queryRoot
在我們的需求下只有一種情況,訪(fǎng)問(wèn)的路徑應(yīng)該是/data/data/packagename/,不過(guò)如果一個(gè)app 支持多用戶(hù),那就應(yīng)該有多個(gè)目錄。所以需要一個(gè)方法告知文件管理應(yīng)用我們的app 有多少個(gè)根。
override fun queryRoots(projection: Array<out String>?): Cursor { Log.d(TAG, "queryRoots() called with: projection = $projection") val flags = DocumentsContract.Root.FLAG_LOCAL_ONLY or DocumentsContract.Root.FLAG_SUPPORTS_IS_CHILD return MatrixCursor(projection ?: DEFAULT_ROOT_PROJECTION).apply { newRow().apply { add(DocumentsContract.Root.COLUMN_ROOT_ID, DEFAULT_ROOT_ID) add(DocumentsContract.Root.COLUMN_MIME_TYPES, DocumentsContract.Document.MIME_TYPE_DIR) add(DocumentsContract.Root.COLUMN_FLAGS, flags) add(DocumentsContract.Root.COLUMN_ICON, R.drawable.ic_launcher_foreground) add(DocumentsContract.Root.COLUMN_TITLE, context?.getString(R.string.app_name)) add(DocumentsContract.Root.COLUMN_SUMMARY, "your data") add(DocumentsContract.Root.COLUMN_DOCUMENT_ID, "/") } } }
返回值是Cursor 就像一個(gè)數(shù)據(jù)庫(kù)連接查詢(xún)數(shù)據(jù)時(shí)一樣,不過(guò)我們沒(méi)有操作數(shù)據(jù)庫(kù),返回的數(shù)據(jù)是文件系統(tǒng)。所以我們返回一個(gè)MatrixCursor。
返回的數(shù)據(jù)沒(méi)有什么真實(shí)數(shù)據(jù),僅僅作為一個(gè)入口。
此時(shí)打開(kāi)Android 系統(tǒng)的文件管理,就能看到了
此時(shí)點(diǎn)擊的話(huà)就會(huì)崩潰,因?yàn)檫€沒(méi)有重寫(xiě)queryDocument
重寫(xiě)queryDocument
/** * Return metadata for the single requested document. You should avoid * making network requests to keep this request fast. * * @param documentId the document to return. * @param projection list of {@link Document} columns to put into the * cursor. If {@code null} all supported columns should be * included. * @throws AuthenticationRequiredException If authentication is required from * the user (such as login credentials), but it is not guaranteed * that the client will handle this properly. */ public abstract Cursor queryDocument(String documentId, String[] projection) throws FileNotFoundException;
這個(gè)方法才是真正返回?cái)?shù)據(jù)的地方,上面返回root 更像是盤(pán)符,這里是返回root 盤(pán)符對(duì)應(yīng)的根文件夾。數(shù)據(jù)結(jié)構(gòu)是一個(gè)樹(shù)形結(jié)構(gòu),queryDocument 返回根文件夾,根只有一個(gè),所以返回的數(shù)據(jù)也是只有一個(gè)。如果你返回了多個(gè)數(shù)據(jù)應(yīng)該也是無(wú)效的,系統(tǒng)會(huì)忽略掉。
一般我們需要根據(jù)documentId (盤(pán)符)返回,不過(guò)這里只有一個(gè),就不做區(qū)分了。
override fun queryDocument(documentId: String?, projection: Array<out String>?): Cursor { Log.d(TAG, "queryDocument() called with: documentId = $documentId, projection = $projection") return MatrixCursor(projection ?: DEFAULT_DOCUMENT_PROJECTION).apply { val root = context?.filesDir?.parentFile ?: return@apply newRow().apply { add(DocumentsContract.Document.COLUMN_DOCUMENT_ID, "/") add(DocumentsContract.Document.COLUMN_MIME_TYPE, DocumentsContract.Document.MIME_TYPE_DIR) val flags = 0 add(DocumentsContract.Document.COLUMN_FLAGS, flags) add(DocumentsContract.Document.COLUMN_DISPLAY_NAME, root.name) add(DocumentsContract.Document.COLUMN_LAST_MODIFIED, root.lastModified()) add(DocumentsContract.Document.COLUMN_SIZE, 0) } } }
重寫(xiě)getChildDocument
override fun queryChildDocuments(parentDocumentId: String?, projection: Array<out String>?, sortOrder: String?): Cursor { Log.d(TAG, "queryChildDocuments() called with: parentDocumentId = $parentDocumentId, projection = $projection, sortOrder = $sortOrder") return MatrixCursor(projection ?: DEFAULT_DOCUMENT_PROJECTION).apply { handleChild(parentDocumentId) } }
我們只需要根據(jù)parentDocumentId 來(lái)搜索就可以。就像一個(gè)遍歷出一個(gè)文件夾的子文件夾和子文件一樣。
除了上面介紹的,還可以繼承打開(kāi)document,創(chuàng)建document,顯示document thumbnail 等功能。
代碼可以在這里看 github.com/storyteller…
以上就是Android如何實(shí)現(xiàn)一個(gè)DocumentProvider示例詳解的詳細(xì)內(nèi)容,更多關(guān)于Android實(shí)現(xiàn)DocumentProvider的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android studio 4.1打包失敗和插件錯(cuò)誤提示的解決
這篇文章主要介紹了Android studio 4.1打包失敗和插件錯(cuò)誤提示的解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10Android實(shí)現(xiàn)漸變色的圓弧虛線(xiàn)效果
最近在學(xué)習(xí)Android的paint類(lèi)的時(shí)候,學(xué)習(xí)了PathEffect路徑效果和Shader渲染效果。所以就做了下面的一個(gè)效果,其中自定義的view組主要是用DashPathEffect、SweepGradient的API形成的效果。感興趣的朋友們可以參考借鑒,下面來(lái)一起看看吧。2016-10-10實(shí)例詳解用戶(hù)輸入 i. 檢測(cè)常用手勢(shì)
通過(guò)本段代碼給大家介紹當(dāng)用戶(hù)輸入i檢測(cè)常用手勢(shì)的相關(guān)內(nèi)容,代碼簡(jiǎn)單易懂,感興趣的朋友一起學(xué)習(xí)吧2016-01-01Android仿QQ空間動(dòng)態(tài)界面分享功能
這篇文章主要介紹了Android仿QQ空間動(dòng)態(tài)界面分享功能,本文圖文并茂給大家介紹的非常詳細(xì),需要的朋友可以參考下2017-04-04Android編程實(shí)現(xiàn)類(lèi)似于圓形ProgressBar的進(jìn)度條效果
這篇文章主要介紹了Android編程實(shí)現(xiàn)類(lèi)似于圓形ProgressBar的進(jìn)度條效果,結(jié)合實(shí)例形式分析了Android通過(guò)自定義View實(shí)現(xiàn)圓形進(jìn)度條效果的操作方法,需要的朋友可以參考下2017-03-03Android接收和發(fā)送短信的實(shí)現(xiàn)代碼
這篇文章主要為大家詳細(xì)介紹了Android接收和發(fā)送短信的實(shí)現(xiàn)代碼,感興趣的小伙伴們可以參考一下2016-08-08Android開(kāi)發(fā)之ListView、GridView 詳解及示例代碼
本文主要介紹Android開(kāi)發(fā)之ListView、GridView,這里整理了相關(guān)資料及簡(jiǎn)單示例代碼,幫助大家學(xué)習(xí)參考,有需要的小伙伴可以參考下2016-08-08Android開(kāi)發(fā)仿bilibili刷新按鈕的實(shí)現(xiàn)代碼
這篇文章主要介紹了Android 仿bilibili刷新按鈕的實(shí)現(xiàn)代碼,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-10-10