思維導圖與UML之ContentProvider

jinux111發表於2013-10-19

無數次的從頭開始,堅持寫部落格,但都沒有堅持下來,現在找到工作了,自己的生活即將開始,應該好好的維護一個部落格來記下自己的學習經歷。

文章中可能有錯誤,真誠歡迎指正

這是一個系列,用思維導圖來記下知識點,用UML來理解分析大的框架。我用的UML工具是jude社群版,思維導圖工具是freemind。


下面是ContentProvider的工作的體系結構,它是一個介面,將一個應用的資料暴露個其他應用,並且遮蔽了底層儲存資料的細節。

下面是用思維導圖總結的知識點和知識結構,忠實於官方文件。

下面是實現一個ContentProvider的過程:


下面讓我們用例子來說明ContentProvider到底是什麼:

1.從最簡單的開始:

建立一個Android專案MyContentProvider,然後把自動生成的Activity程式碼刪掉,同時把Android Manifest.xml中的Activity的註冊也刪掉。

然後新建一個類來繼承ContentProvider,在Android Manifest.xml註冊它。下面是相關程式碼:

MContentProvider.java:

public class MContentProvider extends ContentProvider{

    private String TAG="MContentProvider";

    @Override
    public boolean onCreate() {
        Log.e(TAG,"onCreate");
        return true;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
            String[] selectionArgs, String sortOrder) {
        Log.e(TAG,"query");

        return null;
    }

    @Override
    public String getType(Uri uri) {
        Log.e(TAG,"getType");
        return null;
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        Log.e(TAG,"insert");
        return null;
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        Log.e(TAG,"delete");
        return 0;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection,
            String[] selectionArgs) {
        Log.e(TAG,"update");
        return 0;
    }
    
}

上面知識用Log實現了ContentProvider的方法,顯示一條資訊

AndroidManifest.xml的ContentProvider註冊部分:

<provider
<!--(這裡指明要註冊的是哪個類) -->
 android:name="com.example.test.MContentProvider"   

<!--(訪問時uri的一部分) -->
 android:authorities="com.example.test.provider"     
<!--(如果設定為false則只能本應用訪問,true則表示其他應用可以訪問) -->         
 android:exported="true"                                                            
 android:label="@string/app_name" >
</provider>


這樣第一個應用就完了,它只提供了一個ContentProvider,當安裝它後,桌面沒有圖示,只有在顯示安裝的程式那可以看到

新建第二個應用TestMyProvider來實現對上一個應用的訪問。作為示範,只在oncreate()裡新增一下幾行:

ContentResolver cr = getContentResolver();
        cr.query(Uri.parse("content://com.example.test.provider/hello"), null,
                null, null, null);
        cr.insert(Uri.parse("content://com.example.test.provider/"),
                new ContentValues());

這樣執行這個應用,你會發現,在Logcat那會顯示出第一個應用query和insert函式體裡Log的內容。這就說明實現了跨應用的訪問。

下面來說說上面兩行是怎麼執行的:

首先對於ContentResolver的query,insert,update,delete分別對應了ContentProvider的query,insert,update,delete,這好理解。

但是它怎麼就呼叫了我們那個MContentProvider,這裡應該用到了“外觀模式”,一個ContentResolver,就代替了所有的ContentProvider,怎麼做到呢?

關鍵就在Uri這,對於ContentResolver的query,insert,update,delete都需要一個Uri,而這個Uri就指明瞭是對誰的請求。

ContentProvider的Uri制定Uri的scheme部分一定是content://

authority部分是什麼呢,這一部分就指明瞭要請求哪一個ContentProvider,上面我們用的是com.example.test.provider,為什麼用它就訪問我們那個ContentProvider呢?

去我們第一個應用裡AndroidManifest找可以找到     android:authorities="com.example.test.provider"  ,對了,這裡就宣告瞭我們的自定義的ContentProvider的authority。

Android文件中推薦authority使用包名的樣子後加上.provider

authority後還可以有其他內容,但對於我們上面的例子沒有用。

2下面我們修改前一個例子來演示一下Uri中authority後面的部分如何起作用,並介紹一下UriMatcher工具類:

下面對MContentProvider修改如下:

public class MContentProvider extends ContentProvider{

    private String TAG="MContentProvider";

    

   //這裡定義一個類屬性uriMatcher這樣只在載入類時執行一次,參數列示我們請求的uri是content://<authority>時所對應的int值
    static UriMatcher uriMatcher=new UriMatcher(0);    

    //同樣靜態語句塊也只在載入類時執行一次

    static {          

        //新增兩個uri    引數分別是authority部分,authority其後的部分,前兩者確定的uri對應的int值                                                                                                   
        uriMatcher.addURI("com.example.test.provider", "first", 1);           
        uriMatcher.addURI("com.example.test.provider", "second", 2);
    }
    
    @Override
    public boolean onCreate() {
        Log.e(TAG,"onCreate");
        return true;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
            String[] selectionArgs, String sortOrder) {
        Log.e(TAG,"query");

       //我們這裡就可以通過mathch方法來匹配返回一個uri對應的int值了,然後根據int值來執行不同的功能

        switch (uriMatcher.match(uri)) {
        case 1:            
                 Log.e(TAG,"我們在這裡做第一中處理");
                  break;
        case 2:
                 Log.e(TAG,"我們在這裡做第二中處理");
                 break;
        default:
                 break; 
        }   
        return null; 
       }

然後在TestMyProvider中

cr.query(Uri.parse("content://com.example.test.provider/first"), null,
				null, null, null);
cr.query(Uri.parse("content://com.example.test.provider/second"), null,
				null, null, null);
cr.query(Uri.parse("content://com.example.test.provider/"), null,
				null, null, null);
cr.insert(Uri.parse("content://com.example.test.provider/"),
				new ContentValues());

此時在執行第一個程式,然後執行第二個程式,會看到logcat輸出有了變化


本文目的是讓初學者瞭解ContentProvider到底是什麼,瞭解相關知識體系。

至於query等方法的其他引數,在介紹SqliteOpenHelper時講更合適。



相關文章