日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android ContentProvider介绍

發(fā)布時間:2025/6/17 Android 50 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android ContentProvider介绍 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

在Android中數(shù)據(jù)的存儲一共有五種形式,分別是:Shared Preferences、網(wǎng)絡(luò)存儲、文件存儲,外儲存儲、SQLite。但是我們知道一般這些存儲都只是在單獨的一個應(yīng)用程序之中達到一個數(shù)據(jù)的共享。而使用ContentProvider共享數(shù)據(jù)的好處是統(tǒng)一了數(shù)據(jù)訪問方式。ContentProvide對數(shù)據(jù)進行封裝,不用關(guān)心數(shù)據(jù)存儲的細節(jié)。下面我們通過代碼來介紹這個ContentProvider的使用過程。

public class ItemContentProvier {/*Authority*/ public static final String AUTHORITY="com.itchq.contentprovider";/*Match Code*/public static final int ITEM=1;public static final int ITEM_POS=2;/*Default sort order*/public static final String DEFAULT_SORT_ORDER = "_id asc";/*MIME*/ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.com.itchq.contentprovider"; public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.com.itchq.contentprovider";public static final String ARTICE_ITEM="articeitem";/*Content URI*/public static final Uri CONTENT_ARTICE=Uri.parse("content://"+AUTHORITY+"/"+ARTICE_ITEM);public interface Artice{public static final String ID="_id";public static final String TITLE="title";public static final String CONTENT_ID="contentid";}}

上面這個類都是定義數(shù)據(jù)庫一些常量,我們往往把它單獨的提前出來使代碼結(jié)構(gòu)更清晰一點。

URI 通用資源標志符,這個Uri代表了要操作的數(shù)據(jù),后面要訪問這個數(shù)據(jù)庫就可以通過這個URI來指定,用于唯一標識某個具體的ContentProvider

URI格式如下:
[content://][com.itchq.contentprovider][/artice][/1]

?|------A------|-----------------B-------------------|---C---|---D--|

A:前綴表明數(shù)據(jù)受控于一個內(nèi)容提供者。它從不修改,也就是schema,ContentProvider(內(nèi)容提供者)的scheme已經(jīng)由Android所規(guī)定, scheme為:content://

B:稱為Authority,它唯一地標識了一個特定的Content Provider,因此,這部分內(nèi)容一般使用Content Provider所在的package來命名,使得它是唯一的,在上面的代碼中使用??? public static final String? AUTHORITY="com.itchq.contentprovider";定義這個變量,這個還有一個地方使用到,就是在AndroidMainfest.xml中要聲明這個數(shù)據(jù)庫的時候需要使用,如下代碼:

<providerandroid:name="com.itchq.contentprovider.itContentProvider"android:authorities="com.itchq.contentprovider"/>

?

上面這個android:authorities這個就是和我們的AUTHORITY里面定義的字符串是一樣的,這個地方要注意點,如果不一樣外部就不可以訪問這個數(shù)據(jù)庫了,我們所說的URI唯一性也是在這個地方來體現(xiàn)出來的,

C:稱為資源路徑,它表示所請求的資源的類型,這部分內(nèi)容是可選的

D:資源ID,它表示所請求的是一個特定的資源,它通常是一個數(shù)字,對應(yīng)前面我們所介紹的數(shù)據(jù)庫表中的_id字段的內(nèi)容,它唯一地標志了某一種資源下的一個特定的實例

我們在定義URI的時候一般情況行都是需要定義這個C,但是D就沒有定義,簡單點說C就是代表了數(shù)據(jù)庫中某一個表(這個名字是隨意定義不一定就是和我們的數(shù)據(jù)庫表名字相同,這里只是一個比喻),而D則是表示操作這個表的哪一個字段,相當于我們的SQL語句中 where id=1這個條件

繼續(xù)往下看:

/*MIME*/ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.com.itchq.contentprovider"; public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.com.itchq.contentprovider";

這個是MIME類型,每一個ContenProvider中都必須定義這個MIME,其實這個MIME類型一般來說就估計上面兩種,被分為兩部分前面是數(shù)據(jù)的大類別,后面定義具體的種類,比如上面的vnd.android.cursor.dir和vnd.android.cursor.item都是固定不會變的,后面的字段都是相同的而且隨便定義,一般的數(shù)據(jù)庫中都vnd.+包名。對于vnd.android.cursor.dir這個類型表示的訪問多個資源的URI,就是你操作的是一整張表,比如添加新數(shù)據(jù)了,刪除某一個表后者是查詢表的全部記錄等等,而vnd.android.cursor.item是表示訪問單個資源的URI,比如更新表中某一個自定的記錄,查詢某一條指定的信息,就是相當SQL中的where條件語句。

?

Artice這個接口是我們這個數(shù)據(jù)庫的表的字段,這里看出這個表有三個字段,分別是:_id,title,contentid。ITEM和ITEM_POS這兩個變量分別定義URI匹配規(guī)則的匹配碼。

比如如果我們訪問的URI是content://com.itchq.contentprovider/articeitem,則匹配規(guī)則返回的匹配碼為ITEM。如果訪問的是content://com.itchq.contentprovider/articeitem/# # 是一個通配符表示如何數(shù)據(jù),則匹配規(guī)則返回的匹配碼為ITEM_POS,這兩個常量我們后面還會有用到的

下面就是ContentProvider的定義了

?

package com.itchq.contentprovider;import java.util.HashMap;import com.itchq.contentprovider.ItemContentProvier.Artice;import android.content.ContentProvider; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; import android.content.UriMatcher; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase.CursorFactory; import android.database.sqlite.SQLiteException; import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteQueryBuilder; import android.net.Uri; import android.text.TextUtils;public class itContentProvider extends ContentProvider{private static final String DB_NAME="itchq.db";private static final String DB_TABLE_ARTICE="artice";private static final int DB_VERSION=1;private DBHelper dbHelper = null; private static final String DB_CREATE_ARTICE = "create table " + DB_TABLE_ARTICE + " (" + Artice.ID + " integer primary key autoincrement, " + Artice.TITLE + " text not null, " + Artice.CONTENT_ID + " integer not null);";private static final UriMatcher uriMatcher;private static final HashMap<String, String> articleProjectionMap;static{uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);uriMatcher.addURI(ItemContentProvier.AUTHORITY, ItemContentProvier.ARTICE_ITEM, ItemContentProvier.ITEM);uriMatcher.addURI(ItemContentProvier.AUTHORITY, ItemContentProvier.ARTICE_ITEM+"/#", ItemContentProvier.ITEM_POS);articleProjectionMap = new HashMap<String, String>(); articleProjectionMap.put(Artice.ID, Artice.ID); articleProjectionMap.put(Artice.TITLE, Artice.TITLE); articleProjectionMap.put(Artice.CONTENT_ID,Artice.CONTENT_ID); }@Overridepublic boolean onCreate() {// TODO Auto-generated method stubdbHelper = new DBHelper(getContext(), DB_NAME, null, DB_VERSION); return false;}@Overridepublic Cursor query(Uri uri, String[] projection, String selection,String[] selectionArgs, String sortOrder) {// TODO Auto-generated method stubSQLiteDatabase db = dbHelper.getReadableDatabase(); SQLiteQueryBuilder sqlBuilder = new SQLiteQueryBuilder(); switch(uriMatcher.match(uri)){case ItemContentProvier.ITEM:{sqlBuilder.setTables(DB_TABLE_ARTICE);sqlBuilder.setProjectionMap(articleProjectionMap); break;}case ItemContentProvier.ITEM_POS:{String id = uri.getPathSegments().get(1); sqlBuilder.setTables(DB_TABLE_ARTICE); sqlBuilder.setProjectionMap(articleProjectionMap); sqlBuilder.appendWhere(Artice.ID + "=" + id); break;}default: throw new IllegalArgumentException("Error Uri: " + uri); }Cursor cursor = sqlBuilder.query(db, projection, selection, selectionArgs, null, null, TextUtils.isEmpty(sortOrder) ? ItemContentProvier.DEFAULT_SORT_ORDER : sortOrder);cursor.setNotificationUri(getContext().getContentResolver(), uri); return cursor;}@Overridepublic String getType(Uri uri) {// TODO Auto-generated method stubswitch (uriMatcher.match(uri)) { case ItemContentProvier.ITEM:{return ItemContentProvier.CONTENT_TYPE;}case ItemContentProvier.ITEM_POS:{return ItemContentProvier.CONTENT_ITEM_TYPE;}default:throw new IllegalArgumentException("Error Uri: " + uri); }}@Overridepublic Uri insert(Uri uri, ContentValues values) {// TODO Auto-generated method stubSQLiteDatabase db = dbHelper.getWritableDatabase();long id = db.insert(DB_TABLE_ARTICE, Artice.ID, values); if (id < 0) {throw new SQLiteException("Unable to insert " + values + " for "+ uri);}Uri newUri = ContentUris.withAppendedId(uri, id);getContext().getContentResolver().notifyChange(newUri,null);return newUri;}@Overridepublic int delete(Uri uri, String selection, String[] selectionArgs) {// TODO Auto-generated method stubSQLiteDatabase db = dbHelper.getWritableDatabase(); int count = 0;switch(uriMatcher.match(uri)){case ItemContentProvier.ITEM:{count = db.delete(DB_TABLE_ARTICE, selection, selectionArgs);break;}case ItemContentProvier.ITEM_POS:{String id = uri.getPathSegments().get(1);count = db.delete(DB_TABLE_ARTICE,Artice.ID + "=" + id + (!TextUtils.isEmpty(selection) ? " and (" + selection + ')' : ""), selectionArgs);break;}default:throw new IllegalArgumentException("Error Uri: " + uri);}getContext().getContentResolver().notifyChange(uri, null);return count;}@Overridepublic int update(Uri uri, ContentValues values, String selection,String[] selectionArgs) {// TODO Auto-generated method stubSQLiteDatabase db = dbHelper.getWritableDatabase(); int count = 0;switch(uriMatcher.match(uri)){case ItemContentProvier.ITEM:{count = db.update(DB_TABLE_ARTICE, values, selection, selectionArgs);break;}case ItemContentProvier.ITEM_POS:{String id = uri.getPathSegments().get(1);count = db.update(DB_TABLE_ARTICE, values, Artice.ID + "=" + id + (!TextUtils.isEmpty(selection) ? " and (" + selection + ')' : ""), selectionArgs);break;}default:throw new IllegalArgumentException("Error Uri: " + uri);}getContext().getContentResolver().notifyChange(uri, null);return count;}private static class DBHelper extends SQLiteOpenHelper{public DBHelper(Context context, String name, CursorFactory factory,int version) {super(context, name, factory, version);// TODO Auto-generated constructor stub }@Overridepublic void onCreate(SQLiteDatabase db) {// TODO Auto-generated method stub db.execSQL(DB_CREATE_ARTICE);}@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {// TODO Auto-generated method stub }}}

?

繼承ContentProvider類需要實現(xiàn)默認下面這些方法

public boolean onCreate() 在創(chuàng)建ContentProvider時調(diào)用

?

public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) 用于查詢指定Uri的ContentProvider,返回一個Cursor

?

public int delete(Uri uri, String selection, String[] selectionArgs) 用于從指定Uri的ContentProvider中刪除數(shù)據(jù)

?

public int update(Uri uri, ContentValues values, String selection,String[] selectionArgs) 用于更新指定Uri的ContentProvider中的數(shù)據(jù)

?

public Uri insert(Uri uri, ContentValues values) 用于添加新數(shù)據(jù)到指定Uri的ContentProvider中

?

public String getType(Uri uri) 用于返回指定的Uri中的數(shù)據(jù)的MIME類型

這個就是前面說的,如果操作的數(shù)據(jù)屬于集合類型,那么MIME類型字符串應(yīng)該以vnd.android.cursor.dir/開頭。

public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.com.itchq.contentprovider";?

如果要操作的數(shù)據(jù)屬于非集合類型數(shù)據(jù)(簡單點說就是指定where條件的),那么MIME類型字符串應(yīng)該以vnd.android.cursor.item/開頭。即

public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.com.itchq.contentprovider";

?

UriMatcher類用于匹配Uri 這個就是要設(shè)置Uri的匹配規(guī)則,我們可以根據(jù)不同的Uri來操作不同的數(shù)據(jù),比如前面我們定義的那個URI

?

/*Content URI*/public static final Uri CONTENT_ARTICE=Uri.parse("content://"+AUTHORITY+"/"+ARTICE_ITEM);

?

分解這個URI字符串是”content://com.itchq.contentprovider/articeitem“,那么我們操作可以是content://com.itchq.contentprovider/articeitem這個字符串也也可能是content://com.itchq.contentprovider/articeitem/#這個字符串,前面表示操作整個數(shù)據(jù)庫表,后面指定是操作數(shù)據(jù)庫某一個字段,那我們是如何知道這個匹配碼呢?這個就需要UriMatcher類來設(shè)定

public void addURI (String authority, String path, int code) ;

authority就是上面定義的public static final String? AUTHORITY="com.itchq.contentprovider";這個變量,path就是就是指具體那個路徑,一般就是URI規(guī)則中表示C的部分,比如上面URI規(guī)則中?public static final Uri CONTENT_ARTICE=Uri.parse("content://"+AUTHORITY+"/"+ARTICE_ITEM);那么這個path指的就是ARTICE_ITEM這個字符串變量,即public static final String ARTICE_ITEM="articeitem"; code就是后面那個匹配碼,比如我們可以看一下update更新語句里面有這么一個switch函數(shù):

?

switch(uriMatcher.match(uri)){case ItemContentProvier.ITEM:{}case ItemContentProvier.ITEM_POS:{}default:throw new IllegalArgumentException("Error Uri: " + uri);}

?

上面的ItemContentProvier.ITEM 和 ItemContentProvier.ITEM_POS 就是已經(jīng)定義好的匹配碼,即code參數(shù),我們通過這個ItemContentProvier.ITEM可以知道操作整個數(shù)據(jù)庫表,ItemContentProvier.ITEM_POS操作的是數(shù)據(jù)庫表中某一列,這個匹配一般都是一開始初始化的時候就需要全部給注冊上的,

static{uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);uriMatcher.addURI(ItemContentProvier.AUTHORITY, ItemContentProvier.ARTICE_ITEM, ItemContentProvier.ITEM);uriMatcher.addURI(ItemContentProvier.AUTHORITY, ItemContentProvier.ARTICE_ITEM+"/#", ItemContentProvier.ITEM_POS);

這個就是注冊上的,我們先看這個path參數(shù)有ItemContentProvier.ARTICE_ITEMItemContentProvier.ARTICE_ITEM/#,這兩個就是分別表示操作的數(shù)據(jù)庫表和數(shù)據(jù)庫對應(yīng)某一列,最后一個參數(shù)就是我們上面也說到的匹配碼,構(gòu)造函數(shù)的參數(shù)為UriMatcher.NO_MATCH,它表示當uriMatcher不能匹配指定的URI時,就返回代碼UriMatcher.NO_MATCH常量值為-1

public int match (Uri uri)

與傳入的Uri匹配,它會首先與找我們之前通過addURI方法添加進來的Uri匹配,這個URI匹配是這樣的,前面部分固定是A部分:content://, B部分是authority,也就是我們addURI里面添加的第一個參數(shù),C部分表示是路徑,也就是我們在addRUI添加的第二個參數(shù)path,就是說最后匹配的URI就是這樣的 content://authority/path。

authority和path都是我們在addURI參數(shù)就第一個和第二個的參數(shù)。如果匹配成功就返回之前我們設(shè)置的code值,否則返回一個UriMatcher.NO_MATCH常量值為-1

articleProjectionMap = new HashMap<String, String>(); articleProjectionMap.put(Artice.ID, Artice.ID); articleProjectionMap.put(Artice.TITLE, Artice.TITLE); articleProjectionMap.put(Artice.CONTENT_ID,Artice.CONTENT_ID);

在上面的put函數(shù)中,第一個參數(shù)表示列的別名,第二個參數(shù)表示列的真實名稱。在這個例子中,我們把列的別名和和真實名稱都設(shè)置成一樣的。

在query函數(shù)中,我們使用SQLiteQueryBuilder來輔助數(shù)據(jù)庫查詢操作,使用這 個類的好處是我們可以不把數(shù)據(jù)庫表的字段暴露出來,而是提供別名給第三方應(yīng)用程序使用,這樣就可以把數(shù)據(jù)庫表內(nèi)部設(shè)計隱藏起來,方便后續(xù)擴展和維護。列別 名到真實列名的映射是由上面這個HashMap成員變量來實現(xiàn)的,當然這里沒有修改,也可以不用定義。

@Overridepublic String getType(Uri uri) {// TODO Auto-generated method stubswitch (uriMatcher.match(uri)) { case ItemContentProvier.ITEM:{return ItemContentProvier.CONTENT_TYPE;}case ItemContentProvier.ITEM_POS:{return ItemContentProvier.CONTENT_ITEM_TYPE;}default:throw new IllegalArgumentException("Error Uri: " + uri); }}

這個是返回當前Uri所數(shù)據(jù)的MIME類型,如果該Uri對應(yīng)的數(shù)據(jù)可能包括多條記錄,那么MIME類型字符串就是以 vnd.android.cursor.dir/開頭,我們通過前面的addURI指定 ItemContentProvier.ITEM是返回全面的類型,如果Uri對應(yīng)的數(shù)據(jù)只包含一條記錄,那么MIME類型字符串就是以 vnd.android.cursor.item/開頭,前面的addURI得知ItemContentProvier.ITEM_POS這個返回的是某一列信息。

還有一點是我們在itContentProvider類的內(nèi)部中定義了一個DBHelper類,它繼承于SQLiteOpenHelper類,它用是用輔助我 們操作數(shù)據(jù)庫的。使用這個DBHelper類來輔助操作數(shù)據(jù)庫的好處是只有當我們第一次對數(shù)據(jù)庫時行操作時,系統(tǒng)才會執(zhí)行打開數(shù)據(jù)庫文件的操作,

剩下的更新查詢刪除等操作就不多說了,最后不要忘記在AndroidManifest.xml中進行定義

<providerandroid:name="com.itchq.contentprovider.itContentProvider"android:authorities="com.itchq.contentprovider"android:multiprocess="false"/>

在配置Content Provider的時候,最重要的就是要指定它的authorities屬性了,只有配置了這個屬性,第三方應(yīng)用程序才能通過它來找到這個Content Provider。這要需要注意的,這里配置的authorities屬性的值是和我們前面在ItemContentProvier.java文件中定義的AUTHORITY 常量的值是一致的。另外一個屬性multiprocess是一個布爾值,它表示這個Content Provider是否可以在每個客戶進程中創(chuàng)建一個實例,這樣做的目的是為了減少進程間通信的開銷。這里我們?yōu)榱藴p少不必要的內(nèi)存開銷,把屬性 multiprocess的值設(shè)置為false,使得系統(tǒng)只能有一個Content Provider實例存在,它運行在自己的進程中。下面看看在Activity中投入和操作這些數(shù)據(jù)庫的

private void add(){ContentValues values = new ContentValues();values.put(Artice.TITLE, "test");values.put(Artice.CONTENT_ID, 1);Uri uri = getContentResolver().insert(ItemContentProvier.CONTENT_ARTICE, values);}private void query(){String[] projection = new String[] { Artice.ID, Artice.TITLE, Artice.CONTENT_ID};Cursor cursor = getContentResolver().query(ItemContentProvier.CONTENT_ARTICE, projection, null, null, ItemContentProvier.DEFAULT_SORT_ORDER);if (cursor.moveToFirst()) {do{int id=cursor.getInt(cursor.getColumnIndex(Artice.ID));String title=cursor.getString(cursor.getColumnIndex(Artice.TITLE));int content_id=cursor.getInt(cursor.getColumnIndex(Artice.CONTENT_ID));}while(cursor.moveToNext());}} ItemContentProvier.CONTENT_ARTICE就是我們前面定義的那個URI
這個介紹一個ContentUris類,這個類是它用于在Uri后面追加一個ID或者解析出傳入的Uri所帶上的ID值,就是我們說的URI規(guī)則中最后D部分
|------A------|-----------------B-------------------|---C---|---D--|
常用的兩個方法如下:
public static Uri withAppendedId (Uri contentUri, long id)??用于為路徑加上ID部分
Uri resultUri = ContentUris.withAppendedId(ItemContentProvier.CONTENT_ARTICE, 10);
那么這個Uri就是content://com.itchq.contentprovider/articeitem/10,那么我們在前面使用UriMatch.addURI匹配碼就是
uriMatcher.addURI(ItemContentProvier.AUTHORITY, ItemContentProvier.ARTICE_ITEM+"/#", ItemContentProvier.ITEM_POS);
這個,那么這個時候返回的匹配碼就是 ItemContentProvier.ITEM_POS

public static long parseId (Uri contentUri)從路徑中獲取ID部分
Uri uri = Uri.parse("content://com.itchq.contentprovider/articeitem/10"
long personid = ContentUris.parseId(uri);//獲取的結(jié)果為:10,前面的操作中有用到這個

轉(zhuǎn)載于:https://www.cnblogs.com/itchq/p/4014388.html

總結(jié)

以上是生活随笔為你收集整理的Android ContentProvider介绍的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。