1. 程式人生 > >Android四大元件之ContentProvider(二)

Android四大元件之ContentProvider(二)

上節提到的四大元件之ContentProvider的簡單使用,在這篇文章中詳細的介紹其中的一些方法。

1.String getType(Uri uri)方法

首先看看官方對它的解釋:

    /**
     * Implement this to handle requests for the MIME type of the data at the
     * given URI.  The returned MIME type should start with
     * <code>vnd.android.cursor.item</code> for a single record,
     * or <code>vnd.android.cursor.dir/</code> for multiple items.
     * This method can be called from multiple threads, as described in
     * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
     * and Threads</a>.
     *
     * <p>Note that there are no permissions needed for an application to
     * access this information; if your content provider requires read and/or
     * write permissions, or is not exported, all applications can still call
     * this method regardless of their access permissions.  This allows them
     * to retrieve the MIME type for a URI when dispatching intents.
     *
     * @param uri the URI to query.
     * @return a MIME type string, or {@code null} if there is no type.
     */
    public abstract @Nullable String getType(@NonNull Uri uri);

本人英文小白,大家可以自行百度翻譯;我自己的理解是:

給定一個Uri返回相對應的MIME型別;注意,應用程式不需要許可權;如果您的內容提供者需要讀取和/或寫許可權,或不匯出,所有應用程式仍然可以呼叫此方法不考慮其訪問許可權。這使他們在排程意圖時檢索URI的MIME型別。

返回MIME型別有何要求:

  1. vnd.android.cursor.dir/或者vnd.android.cursor.item/開頭,根據Uri判斷是處理單條資料還是全部資料
  2. 後接vnd.< aothority >.< path>結尾
    例:uri = “content://org.wdl.provider/books”
    返回的MIME為:vnd.android.cursor.dir/vnd.org.wdl.provider.books

MIME的內容見:(https://blog.csdn.net/qq_34341338/article/details/82997517)

作用:

  1. 隱式的啟動activity等,通過IntentFliter匹配
    在這裡插入圖片描述

  2. 結合query(Uri, String[], String, String[], String)這個方法來解釋一下:

    在該方法中,返回一個Cursor遊標物件。而Cursor中是單條的記錄還是一個集合,需要和在getType()方法中返回的型別保持一致。當返回的 MIME型別是Xxx.CONTENT_ITEMS時,Cursor應該是一個集合;當返回的MIME型別是 Xxx.CONTENT_ITEM時,Cursor應該是單條記錄。

    由於在getType()方法裡面,我們顯示的返回了android平臺可以識別的MIME型別,所以在執行query()方法返回Cursor物件的時候,系統將不需要再進行驗證,從而可以說是節省了系統開銷

2.getContext().getContentResolver().notifyChange(uri, null)

仔細觀察前面ContentProvider的使用時,發現在insert,update,delete後都會呼叫該方法通知所有註冊在該Uri上的監聽者。而為了提供監聽ContentProvider資料的改變,Android提供了ContentObserver基類

如何使用?

  1. 自定義監聽類繼承自ContentObserver
  2. 重寫onChange()方法,當被監聽的ContentProvider資料改變時,會回撥onChange()方法
  3. 註冊監聽器,ContentResolver向指定的Uri註冊監聽器,方法:
    registerContentObserver(Uri uri,boolean notifyForDescendents,ContentObserver observer)
  • uri:ContentProvider的Uri
  • notifyForDescendents:當值為true時,假如監聽的Uri為content://abc,那麼Uri為content://abc/xyz或者content://abc/xyz/fox的資料改變時也會觸發該監聽器;值為false則只有Uri為content://abc的資料改變時才會觸發
  • observer:監聽器例項

使用:

package com.wdl.contentproviderclient

import android.content.ContentResolver
import android.content.ContentUris
import android.content.ContentValues
import android.content.Intent
import android.database.ContentObserver
import android.net.Uri
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.os.Handler
import android.util.Log
import kotlinx.android.synthetic.main.activity_main.*
import java.lang.StringBuilder

class MainActivity : AppCompatActivity() {
    lateinit var resolver:ContentResolver
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        resolver = contentResolver
        //註冊該URI的監聽
        resolver.registerContentObserver(Uri.parse("content://sms"),true,
                SmsObserver(resolver,null))
        btnQuery.setOnClickListener {
            val intent = Intent("com.wdl.mime")
            intent.data = Books.Book.BOOKS_CONTENT_URI
            startActivity(intent)
            val cursor = resolver.query(Books.Book.BOOKS_CONTENT_URI
                    ,null,"price=?", arrayOf("50.2"),null)
            //cursor.close()
            val stringBuilder = StringBuilder()
            while (cursor.moveToNext()){
                val id = cursor.getInt(cursor.getColumnIndexOrThrow(Books.Book.ID))
                val name = cursor.getString(cursor.getColumnIndexOrThrow(Books.Book.NAME))
                val price = cursor.getInt(cursor.getColumnIndexOrThrow(Books.Book.PRICE))
                stringBuilder.append("id=$id,name=$name,price=$price \n")
            }
            cursor.close()
            Log.e("wdl",stringBuilder.toString())
        }
        btnDelete.setOnClickListener {
            //val index = contentResolver.delete(uri,null,null)
            val index = resolver.delete(Books.Book.BOOKS_CONTENT_URI,"price=?", arrayOf("55.2"))

            Log.e("wdl",""+index)
        }
        btnInsert.setOnClickListener {
            val value = ContentValues()
            value.put(Books.Book.NAME,"smwdl")
            value.put(Books.Book.PRICE,50.2)
            val uri = resolver.insert(Books.Book.BOOKS_CONTENT_URI,value)
            Log.e("wdl",uri.toString())
        }
        btnUpdate.setOnClickListener {
            val value = ContentValues()
            value.put(Books.Book.PRICE,55.2)
            val uri = ContentUris.withAppendedId(Books.Book.BOOK_CONTENT_URI,1)
            val index = resolver.update(uri
                    ,value,"name like ?", arrayOf("smwdl"))
            Log.e("wdl",""+index)
        }
    }

    private class SmsObserver constructor(val resolver: ContentResolver, handler: Handler?): ContentObserver(handler) {
        //資料更改時回撥此方法
        override fun onChange(selfChange: Boolean) {
            val cursor = resolver.query(Uri.parse("content://sms/inbox"),null
                    ,null
                    ,null
                    ,null)
            while (cursor.moveToNext()){
                val builder = StringBuilder()
                builder.append("address=${cursor.getString(cursor.getColumnIndexOrThrow("address"))},")
                        .append("subject=${cursor.getString(cursor.getColumnIndexOrThrow("subject"))}")
                        .append("body=${cursor.getString(cursor.getColumnIndexOrThrow("body"))}")
                        .append("time=${cursor.getLong(cursor.getColumnIndexOrThrow("date"))}")
                Log.e("wdl",builder.toString())
            }
            cursor.close()
        }
    }
}

3.批量操作資料

未完待完成。。。。。。

Demo下載