ContentProvider數據庫共享之——實例講解

 

版權聲明:本文爲博主原創文章,未經博主容許不得轉載。 https://blog.csdn.net/harvic880925/article/details/44591631

前言:如今這段時間沒這麼忙了,要抓緊時間把要總結的知識沉澱下來,今年從新分了項目組,在新項目中應該不會那麼忙了,看來有時間來學一些本身的東西了。如今而言,我須要的是時間。只要不斷的努力,總有一天,你會與從不一樣。加油。html

 

相關文章:
一、《ContentProvider數據庫共享之——概述》
二、《ContentProvider數據庫共享之——實例講解》
三、《ContentProvider數據庫共享之——MIME類型與getType()》
四、《ContentProvider數據庫共享之——讀寫權限與數據監聽》java

 

在上篇文章中,已經給你們初步講解了有關ContentProvder的總體流程及設計方式,在這篇文章中將經過實例來說述ContentProvider的操做過程;android

1、ContentProvider提供數據庫查詢接口

在上篇中,咱們提到過,兩個應用間是經過Content URI來媒介傳遞消息的,咱們的應用在收到URI之後,經過匹配完成對應的數據庫操做功能。聽的有點迷糊?不要緊,下面會細講,我這裏要說的是,匹配成功後要完成的數據庫操做!!!那好,咱們的第一步:建數據庫,數據表數據庫

一、利用SQLiteOpenHelper建立數據庫、數據表

在這裏,咱們在一個數據庫(「harvic.db」)中建立兩個數據表」first」與」second」;每一個表都有多出一個字段「table_name」,來保存當前數據表的名稱
代碼以下:數組

 

  1.  
    public class DatabaseHelper extends SQLiteOpenHelper {
  2.  
    public static final String DATABASE_NAME = "harvic.db";
  3.  
    public static final int DATABASE_VERSION = 1;
  4.  
    public static final String TABLE_FIRST_NAME = "first";
  5.  
    public static final String TABLE_SECOND_NAME = "second";
  6.  
    public static final String SQL_CREATE_TABLE_FIRST = "CREATE TABLE " +TABLE_FIRST_NAME +"("
  7.  
    + BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
  8.  
    + "table_name" +" VARCHAR(50) default 'first',"
  9.  
    + "name" + " VARCHAR(50),"
  10.  
    + "detail" + " TEXT"
  11.  
    + ");" ;
  12.  
    public static final String SQL_CREATE_TABLE_SECOND = "CREATE TABLE "+TABLE_SECOND_NAME+" ("
  13.  
    + BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
  14.  
    + "table_name" +" VARCHAR(50) default 'second',"
  15.  
    + "name" + " VARCHAR(50),"
  16.  
    + "detail" + " TEXT"
  17.  
    + ");" ;
  18.  
     
  19.  
    public DatabaseHelper(Context context) {
  20.  
    super(context, DATABASE_NAME, null, DATABASE_VERSION);
  21.  
    }
  22.  
     
  23.  
    @Override
  24.  
    public void onCreate(SQLiteDatabase db) {
  25.  
    Log.e( "harvic", "create table: " + SQL_CREATE_TABLE_FIRST);
  26.  
    db.execSQL(SQL_CREATE_TABLE_FIRST);
  27.  
    db.execSQL(SQL_CREATE_TABLE_SECOND);
  28.  
    }
  29.  
     
  30.  
    @Override
  31.  
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  32.  
    db.execSQL( "DROP TABLE IF EXISTS first");
  33.  
    db.execSQL( "DROP TABLE IF EXISTS second");
  34.  
    onCreate(db);
  35.  
    }
  36.  
    }

二、利用ContentProvider提供數據庫操做接口

新建一個類PeopleContentProvider,派生自ContentProvider基類,寫好以後,就會自動生成query(),insert(),update(),delete()和getType()方法;這些方法就是根據傳過來的URI來操做數據庫的接口。此時的PeopleContentProvider是這樣的:

 

 

  1.  
    public class PeopleContentProvider extends ContentProvider {
  2.  
    @Override
  3.  
    public boolean onCreate() {
  4.  
    return false;
  5.  
    }
  6.  
     
  7.  
    @Override
  8.  
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
  9.  
    return null;
  10.  
    }
  11.  
     
  12.  
    @Override
  13.  
    public String getType(Uri uri) {
  14.  
    return null;
  15.  
    }
  16.  
     
  17.  
    @Override
  18.  
    public Uri insert(Uri uri, ContentValues values) {
  19.  
    return null;
  20.  
    }
  21.  
     
  22.  
    @Override
  23.  
    public int delete(Uri uri, String selection, String[] selectionArgs) {
  24.  
    return 0;
  25.  
    }
  26.  
     
  27.  
    @Override
  28.  
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
  29.  
    return 0;
  30.  
    }
  31.  
    }

三、使用UriMatcher匹配URI

咱們先無論這幾個函數的具體操做,先想一想在上節中我提到的當一個URI逐級匹配到了ContentProvider類裏之後,會怎麼作——利用UriMatcher進行再次匹配!!!UriMatcher匹配成功之後,纔會執行對應的操做。因此上面的那些操做是在UriMatcher匹配以後。
好,咱們就先看看UriMatcher是怎麼匹配的。

 

  1.  
    public class PeopleContentProvider extends ContentProvider {
  2.  
    private static final UriMatcher sUriMatcher;
  3.  
    private static final int MATCH_FIRST = 1;
  4.  
    private static final int MATCH_SECOND = 2;
  5.  
    public static final String AUTHORITY = "com.harvic.provider.PeopleContentProvider";
  6.  
    public static final Uri CONTENT_URI_FIRST = Uri.parse("content://" + AUTHORITY + "/frist");
  7.  
    public static final Uri CONTENT_URI_SECOND = Uri.parse("content://" + AUTHORITY + "/second");
  8.  
     
  9.  
    static {
  10.  
    sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
  11.  
    sUriMatcher.addURI(AUTHORITY, "first", MATCH_FIRST);
  12.  
    sUriMatcher.addURI(AUTHORITY, "second", MATCH_SECOND);
  13.  
    }
  14.  
     
  15.  
    private DatabaseHelper mDbHelper;
  16.  
     
  17.  
    @Override
  18.  
    public boolean onCreate() {
  19.  
    mDbHelper = new DatabaseHelper(getContext());
  20.  
    return false;
  21.  
    }
  22.  
    …………
  23.  
    }
上面的代碼是最重要的一句話:

 

 

sUriMatcher.addURI(AUTHORITY, "first", MATCH_FIRST);
addUri的官方聲明爲:
public void addURI (String authority, String path, int code)
  • authority:這個參數就是ContentProvider的authority參數,這個參數必須與AndroidManifest.xml中的對應provider的authorities值同樣;
  • path:就匹配在URI中authority後的那一坨,在這個例子中,咱們構造了兩個URI
    (1)、content://com.harvic.provider.PeopleContentProvider/frist
    (2)、content://com.harvic.provider.PeopleContentProvider/second
    而path匹配的就是authority後面的/first或者/second
  • code:這個值就是在匹配path後,返回的對應的數字匹配值;

 

 

sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
句話的意思是,若是匹配不成功,返回UriMatcher.NO_MATCH
咱們要作一個應用:外部可使用兩個URI傳來給咱們,當傳來content://com.harvic.provider.PeopleContentProvider/frist時,就操做first數據庫;若是傳來content://com.harvic.provider.PeopleContentProvider/second時,就操做second數據庫

四、insert方法

 

下面先看看insert方法,主要功能爲:當URI匹配content://com.harvic.provider.PeopleContentProvider/frist時,將數據插入first數據庫
當URI匹配content://com.harvic.provider.PeopleContentProvider/second時,將數據插入second數據庫ide

 

  1.  
    @Override
  2.  
    public Uri insert(Uri uri, ContentValues values) {
  3.  
    SQLiteDatabase db = mDbHelper.getWritableDatabase();
  4.  
    switch (sUriMatcher.match(uri)){
  5.  
    case MATCH_FIRST:{
  6.  
    long rowID = db.insert(DatabaseHelper.TABLE_FIRST_NAME, null, values);
  7.  
    if(rowID > 0) {
  8.  
    Uri retUri = ContentUris.withAppendedId(CONTENT_URI_FIRST, rowID);
  9.  
    return retUri;
  10.  
    }
  11.  
    }
  12.  
    break;
  13.  
    case MATCH_SECOND:{
  14.  
    long rowID = db.insert(DatabaseHelper.TABLE_SECOND_NAME, null, values);
  15.  
    if(rowID > 0) {
  16.  
    Uri retUri = ContentUris.withAppendedId(CONTENT_URI_SECOND, rowID);
  17.  
    return retUri;
  18.  
    }
  19.  
    }
  20.  
    break;
  21.  
    default:
  22.  
    throw new IllegalArgumentException("Unknown URI " + uri);
  23.  
    }
  24.  
    return null;
  25.  
    }
下面對上面這段代碼進行講解:
首先,利用UriMatcher.match(uri)來匹配到來的URI,若是這個URI與content://com.harvic.provider.PeopleContentProvider/frist匹配,就會返回1即MATCH_FIRST;
即:當與"/first"匹配時,就將數據鍵值對(values)插入到first表中:
long rowID = db.insert(DatabaseHelper.TABLE_FIRST_NAME, null, values);
插入以後,會返回新插入記錄的當前所在行號,而後將行號添加到URI的末尾,作爲結果返回
Uri retUri = ContentUris.withAppendedId(CONTENT_URI_FIRST, rowID);
當匹配content://com.harvic.provider.PeopleContentProvider/second時,同理,再也不贅述。

五、update()方法

 

在看了insert方法以後,update方法難度也不大,也是根據UriMatcher.match(uri)的返回值來判斷當前與哪一個URI匹配,根據匹配的URI來操做對應的數據庫,代碼以下:函數

 

  1.  
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
  2.  
    SQLiteDatabase db = mDbHelper.getWritableDatabase();
  3.  
    int count = 0;
  4.  
    switch(sUriMatcher.match(uri)) {
  5.  
    case MATCH_FIRST:
  6.  
    count = db.update(DatabaseHelper.TABLE_FIRST_NAME, values, selection, selectionArgs);
  7.  
    break;
  8.  
    case MATCH_SECOND:
  9.  
    count = db.update(DatabaseHelper.TABLE_SECOND_NAME, values, selection, selectionArgs);
  10.  
    break;
  11.  
     
  12.  
    default:
  13.  
    throw new IllegalArgumentException("Unknow URI : " + uri);
  14.  
    }
  15.  
    this.getContext().getContentResolver().notifyChange(uri, null);
  16.  
    return count;
  17.  
    }
在最後調用getContentResolver().notifyChange(uri, null);來通知當前的數據庫有改變,讓監聽這個數據庫的全部應用執行對應的操做,有關共享數據庫的變量監聽與響應的問題,咱們會在最後一篇中講述。這裏就先不提,這裏不加這一句也是沒問題的。我這裏只是一個引子,你們知道這個事就好了。

六、query() 方法

 

至於query()方法就再也不細講了,跟上面的同樣,根據不一樣的URI來操做不一樣的查詢操做而已,代碼以下:post

 

  1.  
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
  2.  
    SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
  3.  
    switch (sUriMatcher.match(uri)) {
  4.  
    case MATCH_FIRST:
  5.  
    // 設置查詢的表
  6.  
    queryBuilder.setTables(DatabaseHelper.TABLE_FIRST_NAME);
  7.  
    break;
  8.  
     
  9.  
    case MATCH_SECOND:
  10.  
    queryBuilder.setTables(DatabaseHelper.TABLE_SECOND_NAME);
  11.  
    break;
  12.  
     
  13.  
    default:
  14.  
    throw new IllegalArgumentException("Unknow URI: " + uri);
  15.  
    }
  16.  
     
  17.  
    SQLiteDatabase db = mDbHelper.getReadableDatabase();
  18.  
    Cursor cursor = queryBuilder.query(db, projection, selection, selectionArgs, null, null, null);
  19.  
    return cursor;
  20.  
    }

七、delete()方法

delete()方法以下:

 

 

  1.  
    public int delete(Uri uri, String selection, String[] selectionArgs) {
  2.  
    SQLiteDatabase db = mDbHelper.getWritableDatabase();
  3.  
    int count = 0;
  4.  
    switch(sUriMatcher.match(uri)) {
  5.  
    case MATCH_FIRST:
  6.  
    count = db.delete(DatabaseHelper.TABLE_FIRST_NAME, selection, selectionArgs);
  7.  
    break;
  8.  
     
  9.  
    case MATCH_SECOND:
  10.  
    count = db.delete(DatabaseHelper.TABLE_SECOND_NAME, selection, selectionArgs);
  11.  
    break;
  12.  
    default:
  13.  
    throw new IllegalArgumentException("Unknow URI :" + uri);
  14.  
     
  15.  
    }
  16.  
    return count;
  17.  
    }

八、getType()

這個函數,咱們這裏暫時用不到,直接返回NULL,下篇咱們會專門來說這個函數的做用與意義。

 

 

  1.  
    public String getType(Uri uri) {
  2.  
    return null;
  3.  
    }

九、AndroidManifest.xml中聲明provider

在AndroidManifest.xml中要聲明咱們建立的Provider:

 

 

  1.  
    <provider
  2.  
    android:authorities= "com.harvic.provider.PeopleContentProvider"
  3.  
    android:name= ".PeopleContentProvider"
  4.  
    android:exported= "true"/>

2、第三方應用經過URI操做共享數據庫

 

一、ContentResolver操做URI

在第三方應用中,咱們要如何利用URI來執行共享數據數的操做呢,這是利用ContentResolver這個類來完成的。
獲取ContentResolver實例的方法爲:ui

 

ContentResolver cr = this.getContentResolver();
ContentResolver有下面幾個數據庫操做:查詢、插入、更新、刪除

 

 

  1.  
    public final Cursor query (Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
  2.  
    public final Uri insert (Uri url, ContentValues values)
  3.  
    public final int update (Uri uri, ContentValues values, String where, String[] selectionArgs)
  4.  
    public final int delete (Uri url, String where, String[] selectionArgs)
第一個參數都是傳入要指定的URI,而後再後面的幾個參數指定數據庫條件——where語句和對應的參數;下面咱們就用戶實例來看看這幾個函數究竟是怎麼用的。

二、全局操做

 

新建一個工程,命名爲「UseProvider」,界面長這個樣子:this

最上頭有兩個按鈕,用來切換當前使用哪一個URI來增、刪、改、查操做;因爲不一樣的URI會操做不一樣的數據表,因此咱們使用不一樣的URI,會在不一樣的數據表中操做;
先列出來那兩個要匹配的URI,以及全局當前要使用的URI(mCurrentURI ),mCurrentURI 默認是/first對應的URI,若是要切換,使用界面上最上頭的那兩個按鈕來切換當前所使用的URI。

 

  1.  
    public static final String AUTHORITY = "com.harvic.provider.PeopleContentProvider";
  2.  
    public static final Uri CONTENT_URI_FIRST = Uri.parse("content://" + AUTHORITY + "/first");
  3.  
    public static final Uri CONTENT_URI_SECOND = Uri.parse("content://" + AUTHORITY + "/second");
  4.  
    public static Uri mCurrentURI = CONTENT_URI_FIRST;

三、query()——查詢操做

下面先來看看查詢操做的過程:

 

 

  1.  
    private void query() {
  2.  
    Cursor cursor = this.getContentResolver().query(mCurrentURI, null, null, null, null);
  3.  
    Log.e( "test ", "count=" + cursor.getCount());
  4.  
    cursor.moveToFirst();
  5.  
    while (!cursor.isAfterLast()) {
  6.  
    String table = cursor.getString(cursor.getColumnIndex( "table_name"));
  7.  
    String name = cursor.getString(cursor.getColumnIndex( "name"));
  8.  
    String detail = cursor.getString(cursor.getColumnIndex( "detail"));
  9.  
    Log.e( "test", "table_name:" + table);
  10.  
    Log.e( "test ", "name: " + name);
  11.  
    Log.e( "test ", "detail: " + detail);
  12.  
    cursor.moveToNext();
  13.  
    }
  14.  
    cursor.close();
  15.  
    }
其實只有一句話,就完成的查詢操做:(因爲沒有加任何的限定語句,因此是查詢出此數據表中的全部記錄)
Cursor cursor = this.getContentResolver().query(mCurrentURI, null, null, null, null);
而後將返回的數據庫記錄指針Cursor,逐個讀出全部的記錄;

四、insert()插入操做

 

 

public final Uri insert (Uri url, ContentValues values)
插入操做有點特殊,第二個函數要求傳入要插入的ContentValues的鍵值對;其實也沒什麼難度,跟普通的數據庫操做同樣;
  1.  
    private void insert() {
  2.  
    ContentValues values = new ContentValues();
  3.  
    values.put( "name", "hello");
  4.  
    values.put( "detail", "my name is harvic");
  5.  
    Uri uri = this.getContentResolver().insert(mCurrentURI, values);
  6.  
    Log.e( "test ", uri.toString());
  7.  
    }

五、update()更新操做

public final int update (Uri uri, ContentValues values, String where, String[] selectionArgs)
這個函數的意思就是,先用where語句找出要更新的記錄,而後將values鍵值對更新到對應的記錄中;
  • uri:即要匹配的URI
  • values:這是要更新的鍵值對
  • where:SQL中對應的where語句
  • selectionArgs:where語句中若是有可變參數,能夠放在selectionArgs這個字符串數組中;這些與數據庫中的用法同樣,再也不細講。
  1.  
    private void update() {
  2.  
    ContentValues values = new ContentValues();
  3.  
    values.put( "detail", "my name is harvic !!!!!!!!!!!!!!!!!!!!!!!!!!");
  4.  
    int count = this.getContentResolver().update(mCurrentURI, values, "_id = 1", null);
  5.  
    Log.e( "test ", "count=" + count);
  6.  
    query();
  7.  
    }
在這裏,咱們將_id = 1的記錄的detail字符更新,在後面多加了N個感嘆號。

六、delete()刪除操做

 

 

public final int delete (Uri url, String where, String[] selectionArgs)
刪除操做的參數比較好理解,第二個參數是SQL中的WHERE語句的過濾條件,selectionArgs一樣是Where語句中的可變參數;
  1.  
    private void delete() {
  2.  
    int count = this.getContentResolver().delete(mCurrentURI, "_id = 1", null);
  3.  
    Log.e( "test ", "count=" + count);
  4.  
    query();
  5.  
    }
刪除_id = 1的記錄;

3、結果

 

一、咱們先運行ContentProvider對應的APP:ContentProviderBlog,而後再運行UseProvider;
二、而後先用content://com.harvic.provider.PeopleContentProvider/frist 來操做ContentProviderBlog的數據庫:
三、點兩個insert操做,看返回的URI,在每一個URI後都添加上了當前新插入記錄的行號

四、而後作下查詢操做——query()
因爲咱們的URI是針對first記錄的,因此在這裏的table_name,能夠看到是「first」,即咱們操做的是first表,若是咱們把URI改爲second對應的URI,那操做的就會變成second表

五、更新操做——update()

執行Update()操做,會將_id = 1的記錄的detail字段更新爲「my name is harvic !!!!!!!!!!!!!!!!!!!!!!!!!!」;其它記錄的值不變,結果以下:

六、刪除操做——delete()

一樣,刪除操做也會只刪除_id = 1的記錄,因此操做以後的query()結果以下:

總結:在這篇文章中,咱們寫了兩個應用ContentProviderBlog和UseProvider,其中ContentProviderBlog派生自ContentProvider,提供第三方操做它數據庫的接口;而UseProvider就是所謂第三方應用,在UseProvider中經過URI來操做ContentProviderBlog的數據庫;

好了,到這裏,整個文章就結束了,你們在看完這篇文章之後再回過頭來看第一篇,應該對應用間數據庫共享的總體流程已經有清晰的瞭解了。

 

源碼來了,源碼包含兩部份內容:

一、《ContentProviderBlog》:這個是提供共享數據庫接口的APP;
二、《UseProvider》:第三方經過URI來操做數據庫的APP;

 

若是本文有幫到你,記得關注哦

源碼下載地址:http://download.csdn.net/detail/harvic880925/8528507

請你們尊重原創者版權,轉載請標明出處: http://blog.csdn.net/harvic880925/article/details/44591631  謝謝!

相關文章
相關標籤/搜索