Android四大組件--ContentProvider詳解(轉)


一、相關ContentProvider概念解析:

1、ContentProvider簡介
在Android官方指出的Android的數據存儲方式總共有五種,分別是:Shared Preferences、網絡存儲、文件存儲、外儲存儲、SQLite。但是我們知道一般這些存儲都只是在單獨的一個應用程序之中達到一個數據的共享,有時候我們需要操作其他應用程序的一些數據,例如我們需要操作系統里的媒體庫、通訊錄等,這時我們就可能通過ContentProvider來滿足我們的需求了。

2、為什么要選擇ContentProvider?

ContentProvider向我們提供了我們在應用程序之前共享數據的一種機制,而我們知道每一個應用程序都是運行在不同的應用程序的,數據和文件在不同應用程序之間達到數據的共享不是沒有可能,而是顯得比較復雜,而正好Android中的ContentProvider則達到了這一需求,比如有時候我們需要操作手機里的聯系人,手機里的多媒體等一些信息,我們都可以用到這個ContentProvider來達到我們所需。

1)、ContentProvider為存儲和獲取數據提供了統一的接口。ContentProvide對數據進行封裝,不用關心數據存儲的細節。使用表的形式來組織數據。
2)、使用ContentProvider可以在不同的應用程序之間共享數據。 
3)、Android為常見的一些數據提供了默認的ContentProvider(包括音頻、視頻、圖片和通訊錄等)。 
總的來說使用ContentProvider對外共享數據的好處是統一了數據的訪問方式。

3、Uri介紹

為系統的每一個資源給其一個名字,比方說通話記錄。
1)、每一個ContentProvider都擁有一個公共的URI,這個URI用於表示這個ContentProvider所提供的數據。 
2)、Android所提供的ContentProvider都存放在android.provider包中。 將其分為A,B,C,D 4個部分:

A:標准前綴,用來說明一個Content Provider控制這些數據,無法改變的;"content://"
B:URI 的標識,用於唯一標識這個ContentProvider,外部調用者可以根據這個標識來找到它。它定義了是哪個Content Provider提供這些數據。對於第三方應用程序,為了保證URI標識的唯一性,它必須是一個完整的、小寫的類名。這個標識在 元素的 authorities屬性中說明:一般是定義該ContentProvider的包.類的名稱
C:路徑(path),通俗的講就是你要操作的數據庫中表的名字,或者你也可以自己定義,記得在使用的時候保持一致就可以了;"content://com.bing.provider.myprovider/tablename"
D:如果URI中包含表示需要獲取的記錄的ID;則就返回該id對應的數據,如果沒有ID,就表示返回全部; "content://com.bing.provider.myprovider/tablename/#" #表示數據id。

PS:

路徑(path)可以用來表示我們要操作的數據,路徑的構建應根據業務而定,如下:
1、要操作person表中id為10的記錄,可以構建這樣的路徑:/person/10
2、要操作person表中id為10的記錄的name字段, person/10/name
3、要操作person表中的所有記錄,可以構建這樣的路徑:/person
4、要操作xxx表中的記錄,可以構建這樣的路徑:/xxx
5、當然要操作的數據不一定來自數據庫,也可以是文件、xml或網絡等其他存儲方式,如下:
要操作xml文件中person節點下的name節點,可以構建這樣的路徑:/person/name
6、如果要把一個字符串轉換成Uri,可以使用Uri類中的parse()方法,如下:Uri uri = Uri.parse("content://com.bing.provider.personprovider/person")

4、UriMatcher類使用介紹

因為Uri代表了要操作的數據,所以我們經常需要解析Uri,並從Uri中獲取數據。Android系統提供了兩個用於操作Uri的工具類,分別為UriMatcher和ContentUris 。掌握它們的使用,會便於我們的開發工作。
UriMatcher類用於匹配Uri,它的用法如下:
首先第一步把你需要匹配Uri路徑全部給注冊上,如下:

//常量UriMatcher.NO_MATCH表示不匹配任何路徑的返回碼
UriMatcher  sMatcher = new UriMatcher(UriMatcher.NO_MATCH);
//如果match()方法匹配content://com.bing.procvide.personprovider/person路徑,返回匹配碼為1
sMatcher.addURI("com.bing.procvide.personprovider", "person", 1);//添加需要匹配uri,如果匹配就會返回匹配碼
//如果match()方法匹配content://com.bing.provider.personprovider/person/230路徑,返回匹配碼為2
sMatcher.addURI("com.bing.provider.personprovider", "person/#", 2);//#號為通配符
switch (sMatcher.match(Uri.parse("content://com.ljq.provider.personprovider/person/10"))) { 
   case 1
     break;
   case 2
     break;
   default://不匹配
     break;
}

注冊完需要匹配的Uri后,就可以使用sMatcher.match(uri)方法對輸入的Uri進行匹配,如果匹配就返回匹配碼,匹配碼是調用addURI()方法傳入的第三個參數,假設匹配content://com.ljq.provider.personprovider/person路徑,返回的匹配碼為1 

 

 

5、ContentUris類使用介紹

ContentUris類用於操作Uri路徑后面的ID部分,它有兩個比較實用的方法:
withAppendedId(uri, id)用於為路徑加上ID部分:

Uri uri = Uri.parse("content://com.bing.provider.personprovider/person")
Uri resultUri = ContentUris.withAppendedId(uri, 10); 
//生成后的Uri為:content://com.bing.provider.personprovider/person/10

parseId(uri)方法用於從路徑中獲取ID部分:

Uri uri = Uri.parse("content://com.ljq.provider.personprovider/person/10")
long personid = ContentUris.parseId(uri);//獲取的結果為:10

6、使用ContentProvider共享數據

 

1)ContentProvider類主要方法的作用:
public boolean onCreate():該方法在ContentProvider創建后就會被調用,Android開機后,ContentProvider在其它應用第一次訪問它時才會被創建。
public Uri insert(Uri uri, ContentValues values):該方法用於供外部應用往ContentProvider添加數據。
public int delete(Uri uri, String selection, String[] selectionArgs):該方法用於供外部應用從ContentProvider刪除數據。
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs):該方法用於供外部應用更新ContentProvider中的數據。
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder):該方法用於供外部應用從ContentProvider中獲取數據。
public String getType(Uri uri):該方法用於返回當前Url所代表數據的MIME類型。

2)如果操作的數據屬於集合類型,那么MIME類型字符串應該以vnd.android.cursor.dir/開頭,

例如:要得到所有person記錄的Uri為content://com.bing.provider.personprovider/person,那么返回的MIME類型字符串應該為:"vnd.android.cursor.dir/person"。

3)如果要操作的數據屬於非集合類型數據,那么MIME類型字符串應該以vnd.android.cursor.item/開頭,

例如:得到id為10的person記錄,Uri為content://com.bing.provider.personprovider/person/10,那么返回的MIME類型字符串為:"vnd.android.cursor.item/person"。

7、ContentResolver操作ContentProvider中的數據

1)當外部應用需要對ContentProvider中的數據進行添加、刪除、修改和查詢操作時,可以使用ContentResolver 類來完成,要獲取ContentResolver 對象,可以使用Activity提供的getContentResolver()方法。

2)ContentResolver 類提供了與ContentProvider類相同簽名的四個方法:
public Uri insert(Uri uri, ContentValues values):該方法用於往ContentProvider添加數據。
public int delete(Uri uri, String selection, String[] selectionArgs):該方法用於從ContentProvider刪除數據。
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs):該方法用於更新ContentProvider中的數據。
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder):該方法用於從ContentProvider中獲取數據。

這些方法的第一個參數為Uri,代表要操作的ContentProvider和對其中的什么數據進行操作,
其實和contentprovider里面的方法是一樣的.他們所對應的數據,最終是會被傳到我們在之前程序里面定義的那個contentprovider類的方法,
假設給定的是:Uri.parse("content://com.bing.providers.personprovider/person/10"),那么將會對主機名為com.bing.providers.personprovider的ContentProvider進行操作,操作的數據為person表中id為10的記錄。

使用ContentResolver對ContentProvider中的數據進行添加、刪除、修改和查詢操作:

ContentResolver resolver =  getContentResolver();
Uri uri = Uri.parse("content://com.bing.provider.personprovider/person");
//添加一條記錄
ContentValues values = new ContentValues();
values.put("name", "bingxin");
values.put("age", 25);
resolver.insert(uri, values);  
//獲取person表中所有記錄
Cursor cursor = resolver.query(uri, null, null, null, "personid desc");
while(cursor.moveToNext()){
   Log.i("ContentTest", "personid="+ cursor.getInt(0)+ ",name="+ cursor.getString(1));
}
//把id為1的記錄的name字段值更改新為zhangsan
ContentValues updateValues = new ContentValues();
updateValues.put("name", "zhangsan");
Uri updateIdUri = ContentUris.withAppendedId(uri, 2);
resolver.update(updateIdUri, updateValues, null, null);
//刪除id為2的記錄
Uri deleteIdUri = ContentUris.withAppendedId(uri, 2);
resolver.delete(deleteIdUri, null, null);

8、監聽ContentProvider中數據的變化

如果ContentProvider的訪問者需要知道ContentProvider中的數據發生變化,可以在ContentProvider發生數據變化時調用getContentResolver().notifyChange(uri, null)來通知注冊在此URI上的訪問者,例子如下:

public class PersonContentProvider extends ContentProvider {
   public Uri insert(Uri uri, ContentValues values) {
      db.insert("person", "personid", values);
      getContext().getContentResolver().notifyChange(uri, null);
   }
}

如果ContentProvider的訪問者需要得到數據變化通知,必須使用ContentObserver對數據(數據采用uri描述)進行監聽,當監聽到數據變化通知時,系統就會調用ContentObserver的onChange()方法:

getContentResolver().registerContentObserver(Uri.parse("content://com.ljq.providers.personprovider/person"),
       true, new PersonObserver(new Handler()));
public class PersonObserver extends ContentObserver{
   public PersonObserver(Handler handler) {
      super(handler);
   }
   public void onChange(boolean selfChange) {
      //此處可以進行相應的業務處理
   }
}

二、ContentProvider的實現過程

1、定義一個CONTENT_URI常量,提供了訪問ContentProvider的標識符。 

public static final Uri CONTENT_URI = Uri.parse("content://com.example.codelab.transportationprovider");

其中:content是協議
Com.exmaple.codelab.transportationprovider是類名,包含完整的包名。
Uri.parse將一個字符串轉換成Uri類型。
如果Provider包含子表,同樣定義包含字表的CONTENT_URI。
content://com.example.codelab.transportationprovider/train
content://com.example.codelab.transportationprovider/air/domestic
content://com.example.codelab.transportationprovider/air/international
然后定義列,確保里面包含一個_id的列。
2、定義一個類,繼承ContentProvider。 

public class FirstContentProvider extends ContentProvider

先介紹一下ContentProvider用到的UriMatcher。UriMatcher的一個重要的函數是match(Uri uri)。這個函數可以匹配Uri,根據傳入的不同Uri返回不同的自定義整形值,以表明Uri訪問的不同資源的類型。
例如:

public static final UriMatcher uriMatcher; 
      static { 
                     uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); 
                     uriMatcher.addURI(Book.AUTHORITY, "item", Book.ITEM); 
                     uriMatcher.addURI(Book.AUTHORITY, "item/#", Book.ITEM_ID); 
              }

這里UriMatcher類型的靜態字段是用來匹配傳入到ContentProvider中的Uri的類。其構造方法傳入的匹配碼是使用match()方法匹配根路徑時返回的值,這個匹配碼可以為一個大於零的數表示匹配根路徑或傳入-1,即常量UriMatcher.NO_MATCH表示不匹配根路徑。

 

addURI()方法是用來增加其他URI匹配路徑的,

第一個參數傳入標識ContentProvider的AUTHORITY字符串。

第二個參數傳入需要匹配的路徑,這里的#號為通配符,代表匹配任意數字,另外還可以用*來匹配任意文本。

第三個參數必須傳入一個大於零的匹配碼,用於match()方法對相匹配的URI返回相對應的匹配碼。 例如:sMatcher.addURI(“com.test.provider.personprovider”, “person”, 1);如果match()方法匹配content://com.test.provider.personprovider/person路徑,返回匹配碼為1。

3、實現query,insert,update,delete,getType和onCreate方法。 
4、在AndroidManifest.xml當中進行聲明。

<!-- android:name是完成ContentProvider類的全稱
             android:authorities是和FirstProvidermetaData中的常量AUTHORITY的值一樣,否則會報錯
         -->
        <provider android:name="com.bj.FirstContentProvider" android:authorities="com.bj.firstcontentprovider"></provider>

三、實例

1、常量類

/**
 * 提供ContentProvider對外的各種常量,當外部數據需要訪問的時候,就可以參考這些常量操作數據。
 * @author HB
 *
 */
public class ContentData {
    public static final String AUTHORITY = "hb.android.contentProvider";
    public static final String DATABASE_NAME = "teacher.db";
    //創建 數據庫的時候,都必須加上版本信息;並且必須大於4
    public static final int DATABASE_VERSION = 4;
    public static final String USERS_TABLE_NAME = "teacher";
     
    public static final class UserTableData implements BaseColumns {
        public static final String TABLE_NAME = "teacher";
        //Uri,外部程序需要訪問就是通過這個Uri訪問的,這個Uri必須的唯一的。
        public static final Uri CONTENT_URI = Uri.parse("content://"+ AUTHORITY + "/teacher");
        // 數據集的MIME類型字符串則應該以vnd.android.cursor.dir/開頭  
        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/hb.android.teachers";
        // 單一數據的MIME類型字符串應該以vnd.android.cursor.item/開頭  
        public static final String CONTENT_TYPE_ITME = "vnd.android.cursor.item/hb.android.teacher";
        /* 自定義匹配碼 */ 
        public static final int TEACHERS = 1;  
        /* 自定義匹配碼 */ 
        public static final int TEACHER = 2;  
         
        public static final String TITLE = "title";
        public static final String NAME = "name";
        public static final String DATE_ADDED = "date_added";
        public static final String SEX = "SEX";
        public static final String DEFAULT_SORT_ORDER = "_id desc";
         
        public static final UriMatcher uriMatcher;  
        static {  
            // 常量UriMatcher.NO_MATCH表示不匹配任何路徑的返回碼  
            uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);  
            // 如果match()方法匹配content://hb.android.teacherProvider/teachern路徑,返回匹配碼為TEACHERS  
            uriMatcher.addURI(ContentData.AUTHORITY, "teacher", TEACHERS);  
            // 如果match()方法匹配content://hb.android.teacherProvider/teacher/230,路徑,返回匹配碼為TEACHER  
            uriMatcher.addURI(ContentData.AUTHORITY, "teacher/#", TEACHER);  
        }
    }
}

PS:

 

在創建UriMatcher對象uriMatcher時,我們傳給構造函數的參數為UriMatcher.NO_MATCH,它表示當uriMatcher不能匹配指定的URI時,就返回代碼UriMatcher.NO_MATCH。接下來增加了三個匹配規則,分別是uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); uriMatcher.addURI(ContentData.AUTHORITY, "teacher", TEACHERS); uriMatcher.addURI(ContentData.AUTHORITY, "teacher/#", TEACHER);

它們的匹配碼分別是teacher.ITEM、teacher.ITEM_ID和teacher.ITEM_POS,其中,符號#表示匹配任何數字。

2、SQLite操作類DBOpenHelper

/**
 * 這個類繼承SQLiteOpenHelper抽象類,用於創建數據庫和表。創建數據庫是調用它的父類構造方法創建。
 * @author HB
 */
public class DBOpenHelper extends SQLiteOpenHelper {
 
    // 在SQLiteOepnHelper的子類當中,必須有該構造函數,用來創建一個數據庫;
    public DBOpenHelper(Context context, String name, CursorFactory factory,
            int version) {
        // 必須通過super調用父類當中的構造函數
        super(context, name, factory, version);
        // TODO Auto-generated constructor stub
    }
 
    // public DBOpenHelper(Context context, String name) {
    // this(context, name, VERSION);
    // }
 
    public DBOpenHelper(Context context, String name, int version) {
        this(context, name, null, version);
    }
     
    /**
     * 只有當數據庫執行創建 的時候,才會執行這個方法。如果更改表名,也不會創建,只有當創建數據庫的時候,才會創建改表名之后 的數據表
     */
    @Override
    public void onCreate(SQLiteDatabase db) {
System.out.println("create table");
        db.execSQL("create table " + ContentData.UserTableData.TABLE_NAME
                + "(" + ContentData.UserTableData._ID
                + " INTEGER PRIMARY KEY autoincrement,"
                + ContentData.UserTableData.NAME + " varchar(20),"
                + ContentData.UserTableData.TITLE + " varchar(20),"
                + ContentData.UserTableData.DATE_ADDED + " long,"
                + ContentData.UserTableData.SEX + " boolean)" + ";");
    }
 
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
 
    }
 
}

3、內容提供者代碼

/**
 * 這個類給外部程序提供訪問內部數據的一個接口
 * @author HB
 *
 */
public class TeacherContentProvider extends ContentProvider {
     
    private DBOpenHelper dbOpenHelper = null;  
    // UriMatcher類用來匹配Uri,使用match()方法匹配路徑時返回匹配碼  
       
       
    /**
     * 是一個回調函數,在ContentProvider創建的時候,就會運行,第二個參數為指定數據庫名稱,如果不指定,就會找不到數據庫;
     * 如果數據庫存在的情況下是不會再創建一個數據庫的。(當然首次調用 在這里也不會生成數據庫必須調用SQLiteDatabase的 getWritableDatabase,getReadableDatabase兩個方法中的一個才會創建數據庫)
     */
    @Override 
    public boolean onCreate() { 
        //這里會調用 DBOpenHelper的構造函數創建一個數據庫;
        dbOpenHelper = new DBOpenHelper(this.getContext(), ContentData.DATABASE_NAME, ContentData.DATABASE_VERSION);
        return true;  
    }  
    /**
     * 當執行這個方法的時候,如果沒有數據庫,他會創建,同時也會創建表,但是如果沒有表,下面在執行insert的時候就會出錯
     * 這里的插入數據也完全可以用sql語句書寫,然后調用 db.execSQL(sql)執行。
     */
    @Override 
    public Uri insert(Uri uri, ContentValues values){  
        //獲得一個可寫的數據庫引用,如果數據庫不存在,則根據onCreate的方法里創建;
        SQLiteDatabase db = dbOpenHelper.getWritableDatabase();  
        long id = 0;  
         
        switch (uriMatcher.match(uri)) {  
        case TEACHERS:  
            id = db.insert("teacher", null, values);    // 返回的是記錄的行號,主鍵為int,實際上就是主鍵值  
            return ContentUris.withAppendedId(uri, id);  
        case TEACHER:  
            id = db.insert("teacher", null, values); 
            String path = uri.toString();  
            return Uri.parse(path.substring(0, path.lastIndexOf("/"))+id); // 替換掉id  
        default:  
            throw new IllegalArgumentException("Unknown URI " + uri);  
        }
    }  
       
    @Override 
    public int delete(Uri uri, String selection, String[] selectionArgs) {  
        SQLiteDatabase db = dbOpenHelper.getWritableDatabase();  
        int count = 0;  
        switch (uriMatcher.match(uri)) {  
        case TEACHERS:  
            count = db.delete("teacher", selection, selectionArgs);  
            break;  
        case TEACHER:  
            // 下面的方法用於從URI中解析出id,對這樣的路徑content://hb.android.teacherProvider/teacher/10  
            // 進行解析,返回值為10  
            long personid = ContentUris.parseId(uri);  
            String where = "_ID=" + personid;   // 刪除指定id的記錄  
            where += !TextUtils.isEmpty(selection) ? " and (" + selection + ")" : "";   // 把其它條件附加上  
            count = db.delete("teacher", where, selectionArgs);  
            break;  
        default:  
            throw new IllegalArgumentException("Unknown URI " + uri);  
        }  
        db.close();  
        return count;  
    }  
   
    @Override 
    public int update(Uri uri, ContentValues values, String selection,  
            String[] selectionArgs) {  
        SQLiteDatabase db = dbOpenHelper.getWritableDatabase();  
        int count = 0;  
        switch (uriMatcher.match(uri)) {  
        case TEACHERS:  
            count = db.update("teacher", values, selection, selectionArgs);  
            break;  
        case TEACHER:  
            // 下面的方法用於從URI中解析出id,對這樣的路徑content://com.ljq.provider.personprovider/person/10  
            // 進行解析,返回值為10  
            long personid = ContentUris.parseId(uri);  
            String where = "_ID=" + personid;// 獲取指定id的記錄  
            where += !TextUtils.isEmpty(selection) ? " and (" + selection + ")" : "";// 把其它條件附加上  
            count = db.update("teacher", values, where, selectionArgs);  
            break;  
        default:  
            throw new IllegalArgumentException("Unknown URI " + uri);  
        }  
        db.close();  
        return count;  
    }  
       
    @Override 
    public String getType(Uri uri) {  
        switch (uriMatcher.match(uri)) {  
        case TEACHERS:  
            return CONTENT_TYPE;  
        case TEACHER:  
            return CONTENT_TYPE_ITME;  
        default:  
            throw new IllegalArgumentException("Unknown URI " + uri);  
        }  
    }  
   
    @Override 
    public Cursor query(Uri uri, String[] projection, String selection,  
            String[] selectionArgs, String sortOrder) {  
        SQLiteDatabase db = dbOpenHelper.getReadableDatabase();  
        switch (uriMatcher.match(uri)) {  
        case TEACHERS:  
            return db.query("teacher", projection, selection, selectionArgs, null, null, sortOrder);  
        case TEACHER:  
            // 進行解析,返回值為10  
            long personid = ContentUris.parseId(uri);  
            String where = "_ID=" + personid;// 獲取指定id的記錄  
            where += !TextUtils.isEmpty(selection) ? " and (" + selection + ")" : "";// 把其它條件附加上  
            return db.query("teacher", projection, where, selectionArgs, null, null, sortOrder);  
        default:  
            throw new IllegalArgumentException("Unknown URI " + uri);  
        }  
    }  
}

PS:

 

 

1、這里我們在ArticlesProvider類的內部中定義了一個DBHelper類,它繼承於SQLiteOpenHelper類,它用是用輔助我們操作數據庫的。使用這個DBHelper類來輔助操作數據庫的好處是只有當我們第一次對數據庫時行操作時,系統才會執行打開數據庫文件的操作。拿我們這個例子來說,只有第三方應用程序第一次調用query、insert、update或者delete函數來操作數據庫時,我們才會真正去打開相應的數據庫文件。這樣在onCreate函數里,就不用執行打開數據庫的操作,因為這是一個耗時的操作,而在onCreate函數中,要避免執行這些耗時的操作。

2、我們在實現自己的Content Provider時,必須繼承於ContentProvider類,並且實現以下六個函數:

-- onCreate(),用來執行一些初始化的工作。

-- query(Uri, String[], String, String[], String),用來返回數據給調用者。

-- insert(Uri, ContentValues),用來插入新的數據。

-- update(Uri, ContentValues, String, String[]),用來更新已有的數據。

-- delete(Uri, String, String[]),用來刪除數據。

-- getType(Uri),用來返回數據的MIME類型。

4、manifest

<!--?xml version="1.0" encoding="utf-8"?-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="hb.android.contentProvider" android:versioncode="1" android:versionname="1.0">
    <uses-sdk android:minsdkversion="8">
     
         
            <intent-filter>
                 
                <category android:name="android.intent.category.LAUNCHER">
            </category></action></intent-filter>
        </activity>
<provider android:name=".TeacherContentProvider" android:authorities="hb.android.contentProvider" android:multiprocess="false">
    </provider></application>
</uses-sdk></manifest>

PS:

 

在配置Content Provider的時候,最重要的就是要指定它的authorities屬性了,只有配置了這個屬性,第三方應用程序才能通過它來找到這個Content Provider。這要需要注意的,這里配置的authorities屬性的值是和我們前面在Articles.java文件中定義的AUTHORITY常量的值是一致的。另外一個屬性multiprocess是一個布爾值,它表示這個Content Provider是否可以在每個客戶進程中創建一個實例,這樣做的目的是為了減少進程間通信的開銷。這里我們為了減少不必要的內存開銷,把屬性multiprocess的值設置為false,使得系統只能有一個Content Provider實例存在,它運行在自己的進程中。在這個配置文件里面,我們還可以設置這個Content Provider的訪問權限,這里我們為了簡單起見,就不設置權限了。
6、布局文件

<!--?xml version="1.0" encoding="utf-8"?-->
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent">
<button android:id="@+id/insert" android:text="@string/insert" android:layout_width="fill_parent" android:layout_height="wrap_content">
</button><button android:id="@+id/query" android:text="@string/query" android:layout_width="fill_parent" android:layout_height="wrap_content">
</button><button android:id="@+id/querys" android:text="@string/querys" android:layout_width="fill_parent" android:layout_height="wrap_content">
</button><button android:id="@+id/update" android:text="@string/update" android:layout_width="fill_parent" android:layout_height="wrap_content">
</button><button android:id="@+id/delete" android:text="@string/delete" android:layout_width="fill_parent" android:layout_height="wrap_content">
 
</button></linearlayout>

7、activity

package hb.android.contentProvider;
 
import java.util.Date;
 
import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
 
/**
 * 這個類用來測試ContentProvider是否可用。通過 給定的uri訪問,數據庫;
 * 
 * @author HB
 * 
 */
public class TeacherActivity extends Activity {
    Button insert;
    Button query;
    Button update;
    Button delete;
    Button querys;
    Uri uri = Uri.parse("content://hb.android.contentProvider/teacher");
 
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
 
        insert = (Button) findViewById(R.id.insert);
        query = (Button) findViewById(R.id.query);
        update = (Button) findViewById(R.id.update);
        delete = (Button) findViewById(R.id.delete);
        querys = (Button) findViewById(R.id.querys);
        // 綁定監聽器的兩種方法一;
        insert.setOnClickListener(new InsertListener());
        query.setOnClickListener(new QueryListener());
        // 方法二
        update.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                // TODO Auto-generated method stub
                ContentResolver cr = getContentResolver();
                ContentValues cv = new ContentValues();
                cv.put("name", "huangbiao");
                cv.put("date_added", (new Date()).toString());
                int uri2 = cr.update(uri, cv, "_ID=?", new String[]{"3"});
System.out.println("updated"+":"+uri2);
            }
        });
 
        delete.setOnClickListener(new OnClickListener() {
             
            public void onClick(View v) {
                ContentResolver cr = getContentResolver();
                cr.delete(uri, "_ID=?", new String[]{"2"});
            }
        });
 
        querys.setOnClickListener(new OnClickListener() {
 
            public void onClick(View v) {
                // TODO Auto-generated method stub
                ContentResolver cr = getContentResolver();
                // 查找id為1的數據
                Cursor c = cr.query(uri, null, null,null, null);
                System.out.println(c.getCount());
                c.close();
            }
        });
    }
 
    class InsertListener implements OnClickListener {
 
        public void onClick(View v) {
            // TODO Auto-generated method stub
            ContentResolver cr = getContentResolver();
 
            ContentValues cv = new ContentValues();
            cv.put("title", "jiaoshou");
            cv.put("name", "jiaoshi");
            cv.put("sex", true);
            Uri uri2 = cr.insert(uri, cv);
            System.out.println(uri2.toString());
        }
 
    }
 
    class QueryListener implements OnClickListener {
 
        public void onClick(View v) {
            // TODO Auto-generated method stub
            ContentResolver cr = getContentResolver();
            // 查找id為1的數據
            Cursor c = cr.query(uri, null, "_ID=?", new String[] { "1" }, null);
            //這里必須要調用 c.moveToFirst將游標移動到第一條數據,不然會出現index -1 requested , with a size of 1錯誤;cr.query返回的是一個結果集。
            if (c.moveToFirst() == false) {
                // 為空的Cursor
                return;
            }
            int name = c.getColumnIndex("name");
            System.out.println(c.getString(name));
            c.close();
        }
    }
}

最終的效果如下:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM