摘要:前言屬于的四大組件之一本文全面解析了,包括原理使用方法實(shí)例講解,希望你們會(huì)喜歡。
前言
ContentProvider屬于 Android的四大組件之一
本文全面解析了 ContentProvider ,包括ContentProvider 原理、使用方法 & 實(shí)例講解,希望你們會(huì)喜歡。
目錄 1. 定義即內(nèi)容提供者,是 Android 四大組件之一
2. 作用進(jìn)程間 進(jìn)行數(shù)據(jù)交互 & 共享,即跨進(jìn)程通信
3. 原理ContentProvider的底層是采用 Android中的Binder機(jī)制
具體請(qǐng)看文章圖文詳解 Android Binder跨進(jìn)程通信的原理
4. 具體使用關(guān)于ContentProvider的使用主要介紹以下內(nèi)容:
4.1 統(tǒng)一資源標(biāo)識(shí)符(URI)定義:Uniform Resource Identifier,即統(tǒng)一資源標(biāo)識(shí)符
作用:唯一標(biāo)識(shí) ContentProvider & 其中的數(shù)據(jù)
> 外界進(jìn)程通過(guò) `URI` 找到對(duì)應(yīng)的`ContentProvider` & 其中的數(shù)據(jù),再進(jìn)行數(shù)據(jù)操作
具體使用
`URI`分為 系統(tǒng)預(yù)置 & 自定義,分別對(duì)應(yīng)系統(tǒng)內(nèi)置的數(shù)據(jù)(如通訊錄、日程表等等)和自定義數(shù)據(jù)庫(kù) > 1. 關(guān)于 系統(tǒng)預(yù)置`URI` 此處不作過(guò)多講解,需要的同學(xué)可自行查看 > 2. 此處主要講解 自定義`URI`
// 設(shè)置URI Uri uri = Uri.parse("content://com.carson.provider/User/1") // 上述URI指向的資源是:名為 `com.carson.provider`的`ContentProvider` 中表名 為`User` 中的 `id`為1的數(shù)據(jù) // 特別注意:URI模式存在匹配通配符* & # // *:匹配任意長(zhǎng)度的任何有效字符的字符串 // 以下的URI 表示 匹配provider的任何內(nèi)容 content://com.example.app.provider/* // #:匹配任意長(zhǎng)度的數(shù)字字符的字符串 // 以下的URI 表示 匹配provider中的table表的所有行 content://com.example.app.provider/table/#4.2 MIME數(shù)據(jù)類型
作用:指定某個(gè)擴(kuò)展名的文件用某種應(yīng)用程序來(lái)打開
如指定`.html`文件采用`text`應(yīng)用程序打開、指定`.pdf`文件采用`flash`應(yīng)用程序打開
具體使用:
4.2.1 ContentProvider根據(jù) URI 返回MIME類型
ContentProvider.geType(uri) ;
4.2.2 MIME類型組成
每種MIME類型 由2部分組成 = 類型 + 子類型
MIME類型是 一個(gè) 包含2部分的字符串
text / html // 類型 = text、子類型 = html text/css text/xml application/pdf
4.2.3 MIME類型形式
MIME類型有2種形式:
// 形式1:?jiǎn)螚l記錄 vnd.android.cursor.item/自定義 // 形式2:多條記錄(集合) vnd.android.cursor.dir/自定義 // 注: // 1. vnd:表示父類型和子類型具有非標(biāo)準(zhǔn)的、特定的形式。 // 2. 父類型已固定好(即不能更改),只能區(qū)別是單條還是多條記錄 // 3. 子類型可自定義實(shí)例說(shuō)明
<-- 單條記錄 --> // 單個(gè)記錄的MIME類型 vnd.android.cursor.item/vnd.yourcompanyname.contenttype // 若一個(gè)Uri如下 content://com.example.transportationprovider/trains/122 // 則ContentProvider會(huì)通過(guò)ContentProvider.geType(url)返回以下MIME類型 vnd.android.cursor.item/vnd.example.rail <-- 多條記錄 --> // 多個(gè)記錄的MIME類型 vnd.android.cursor.dir/vnd.yourcompanyname.contenttype // 若一個(gè)Uri如下 content://com.example.transportationprovider/trains // 則ContentProvider會(huì)通過(guò)ContentProvider.geType(url)返回以下MIME類型 vnd.android.cursor.dir/vnd.example.rail4.3 ContentProvider類 4.3.1 組織數(shù)據(jù)方式
ContentProvider主要以 表格的形式 組織數(shù)據(jù)
> 同時(shí)也支持文件數(shù)據(jù),只是表格形式用得比較多
每個(gè)表格中包含多張表,每張表包含行 & 列,分別對(duì)應(yīng)記錄 & 字段
> 同數(shù)據(jù)庫(kù)4.3.2 主要方法
進(jìn)程間共享數(shù)據(jù)的本質(zhì)是:添加、刪除、獲取 & 修改(更新)數(shù)據(jù)
所以ContentProvider的核心方法也主要是上述4個(gè)作用
<-- 4個(gè)核心方法 --> public Uri insert(Uri uri, ContentValues values) // 外部進(jìn)程向 ContentProvider 中添加數(shù)據(jù) public int delete(Uri uri, String selection, String[] selectionArgs) // 外部進(jìn)程 刪除 ContentProvider 中的數(shù)據(jù) public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) // 外部進(jìn)程更新 ContentProvider 中的數(shù)據(jù) public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) // 外部應(yīng)用 獲取 ContentProvider 中的數(shù)據(jù) // 注: // 1. 上述4個(gè)方法由外部進(jìn)程回調(diào),并運(yùn)行在ContentProvider進(jìn)程的Binder線程池中(不是主線程) // 2. 存在多線程并發(fā)訪問(wèn),需要實(shí)現(xiàn)線程同步 // a. 若ContentProvider的數(shù)據(jù)存儲(chǔ)方式是使用SQLite & 一個(gè),則不需要,因?yàn)镾QLite內(nèi)部實(shí)現(xiàn)好了線程同步,若是多個(gè)SQLite則需要,因?yàn)镾QL對(duì)象之間無(wú)法進(jìn)行線程同步 // b. 若ContentProvider的數(shù)據(jù)存儲(chǔ)方式是內(nèi)存,則需要自己實(shí)現(xiàn)線程同步 <-- 2個(gè)其他方法 --> public boolean onCreate() // ContentProvider創(chuàng)建后 或 打開系統(tǒng)后其它進(jìn)程第一次訪問(wèn)該ContentProvider時(shí) 由系統(tǒng)進(jìn)行調(diào)用 // 注:運(yùn)行在ContentProvider進(jìn)程的主線程,故不能做耗時(shí)操作 public String getType(Uri uri) // 得到數(shù)據(jù)類型,即返回當(dāng)前 Url 所代表數(shù)據(jù)的MIME類型
Android為常見的數(shù)據(jù)(如通訊錄、日程表等)提供了內(nèi)置了默認(rèn)的ContentProvider
但也可根據(jù)需求自定義ContentProvider,但上述6個(gè)方法必須重寫
> 本文主要講解自定義`ContentProvider`
ContentProvider類并不會(huì)直接與外部進(jìn)程交互,而是通過(guò)ContentResolver 類
4.4 ContentResolver類 4.1 作用統(tǒng)一管理不同 ContentProvider間的操作
4.2 為什么要使用通過(guò)ContentResolver類從而與ContentProvider類進(jìn)行交互,而不直接訪問(wèn)ContentProvider類?即通過(guò) URI 即可操作 不同的ContentProvider 中的數(shù)據(jù)
外部進(jìn)程通過(guò) ContentResolver類 從而與ContentProvider類進(jìn)行交互
答:
一般來(lái)說(shuō),一款應(yīng)用要使用多個(gè)ContentProvider,若需要了解每個(gè)ContentProvider的不同實(shí)現(xiàn)從而再完成數(shù)據(jù)交互,操作成本高 & 難度大
所以再ContentProvider類上加多了一個(gè) ContentResolver類對(duì)所有的ContentProvider進(jìn)行統(tǒng)一管理。
4.3 具體使用ContentResolver 類提供了與ContentProvider類相同名字 & 作用的4個(gè)方法
// 外部進(jìn)程向 ContentProvider 中添加數(shù)據(jù) public Uri insert(Uri uri, ContentValues values) // 外部進(jìn)程 刪除 ContentProvider 中的數(shù)據(jù) public int delete(Uri uri, String selection, String[] selectionArgs) // 外部進(jìn)程更新 ContentProvider 中的數(shù)據(jù) public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) // 外部應(yīng)用 獲取 ContentProvider 中的數(shù)據(jù) public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
實(shí)例說(shuō)明
// 使用ContentResolver前,需要先獲取ContentResolver // 可通過(guò)在所有繼承Context的類中 通過(guò)調(diào)用getContentResolver()來(lái)獲得ContentResolver ContentResolver resolver = getContentResolver(); // 設(shè)置ContentProvider的URI Uri uri = Uri.parse("content://cn.scu.myprovider/user"); // 根據(jù)URI 操作 ContentProvider中的數(shù)據(jù) // 此處是獲取ContentProvider中 user表的所有記錄 Cursor cursor = resolver.query(uri, null, null, null, "userid desc");
Android 提供了3個(gè)用于輔助ContentProvide的工具類:
ContentUris
UriMatcher
ContentObserver
4.5 ContentUris類作用:操作 URI
具體使用
核心方法有兩個(gè):`withAppendedId()` &`parseId()`
// withAppendedId()作用:向URI追加一個(gè)id Uri uri = Uri.parse("content://cn.scu.myprovider/user") Uri resultUri = ContentUris.withAppendedId(uri, 7); // 最終生成后的Uri為:content://cn.scu.myprovider/user/7 // parseId()作用:從URL中獲取ID Uri uri = Uri.parse("content://cn.scu.myprovider/user/7") long personid = ContentUris.parseId(uri); //獲取的結(jié)果為:74.6 UriMatcher類
作用
在ContentProvider 中注冊(cè)URI
根據(jù) URI 匹配 ContentProvider 中對(duì)應(yīng)的數(shù)據(jù)表
具體使用
// 步驟1:初始化UriMatcher對(duì)象 UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH); //常量UriMatcher.NO_MATCH = 不匹配任何路徑的返回碼 // 即初始化時(shí)不匹配任何東西 // 步驟2:在ContentProvider 中注冊(cè)URI(addURI()) int URI_CODE_a = 1; int URI_CODE_b = 2; matcher.addURI("cn.scu.myprovider", "user1", URI_CODE_a); matcher.addURI("cn.scu.myprovider", "user2", URI_CODE_b); // 若URI資源路徑 = content://cn.scu.myprovider/user1 ,則返回注冊(cè)碼URI_CODE_a // 若URI資源路徑 = content://cn.scu.myprovider/user2 ,則返回注冊(cè)碼URI_CODE_b // 步驟3:根據(jù)URI 匹配 URI_CODE,從而匹配ContentProvider中相應(yīng)的資源(match()) @Override public String getType(Uri uri) { Uri uri = Uri.parse(" content://cn.scu.myprovider/user1"); switch(matcher.match(uri)){ // 根據(jù)URI匹配的返回碼是URI_CODE_a // 即matcher.match(uri) == URI_CODE_a case URI_CODE_a: return tableNameUser1; // 如果根據(jù)URI匹配的返回碼是URI_CODE_a,則返回ContentProvider中的名為tableNameUser1的表 case URI_CODE_b: return tableNameUser2; // 如果根據(jù)URI匹配的返回碼是URI_CODE_b,則返回ContentProvider中的名為tableNameUser2的表 } }4.7 ContentObserver類
定義:內(nèi)容觀察者
作用:觀察 Uri引起 ContentProvider 中的數(shù)據(jù)變化 & 通知外界(即訪問(wèn)該數(shù)據(jù)訪問(wèn)者)
> 當(dāng)`ContentProvider` 中的數(shù)據(jù)發(fā)生變化(增、刪 & 改)時(shí),就會(huì)觸發(fā)該 `ContentObserver`類
具體使用
// 步驟1:注冊(cè)內(nèi)容觀察者ContentObserver getContentResolver().registerContentObserver(uri); // 通過(guò)ContentResolver類進(jìn)行注冊(cè),并指定需要觀察的URI // 步驟2:當(dāng)該URI的ContentProvider數(shù)據(jù)發(fā)生變化時(shí),通知外界(即訪問(wèn)該ContentProvider數(shù)據(jù)的訪問(wèn)者) public class UserContentProvider extends ContentProvider { public Uri insert(Uri uri, ContentValues values) { db.insert("user", "userid", values); getContext().getContentResolver().notifyChange(uri, null); // 通知訪問(wèn)者 } } // 步驟3:解除觀察者 getContentResolver().unregisterContentObserver(uri); // 同樣需要通過(guò)ContentResolver類進(jìn)行解除
至此,關(guān)于ContentProvider的使用已經(jīng)講解完畢
5. 實(shí)例說(shuō)明由于ContentProvider不僅常用于進(jìn)程間通信,同時(shí)也適用于進(jìn)程內(nèi)通信
所以本實(shí)例會(huì)采用ContentProvider講解:
進(jìn)程內(nèi)通信
進(jìn)程間通信
實(shí)例說(shuō)明:采用的數(shù)據(jù)源是Android中的SQLite數(shù)據(jù)庫(kù)
*
5.1 進(jìn)程內(nèi)通信
步驟說(shuō)明:
創(chuàng)建數(shù)據(jù)庫(kù)類
自定義 ContentProvider 類
注冊(cè) 創(chuàng)建的 ContentProvider類
進(jìn)程內(nèi)訪問(wèn) ContentProvider的數(shù)據(jù)
具體使用
步驟1:創(chuàng)建數(shù)據(jù)庫(kù)類
關(guān)于數(shù)據(jù)庫(kù)操作請(qǐng)看文章:Android:SQLlite數(shù)據(jù)庫(kù)操作最詳細(xì)解析
DBHelper.java
public class DBHelper extends SQLiteOpenHelper { // 數(shù)據(jù)庫(kù)名 private static final String DATABASE_NAME = "finch.db"; // 表名 public static final String USER_TABLE_NAME = "user"; public static final String JOB_TABLE_NAME = "job"; private static final int DATABASE_VERSION = 1; //數(shù)據(jù)庫(kù)版本號(hào) public DBHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase db) { // 創(chuàng)建兩個(gè)表格:用戶表 和職業(yè)表 db.execSQL("CREATE TABLE IF NOT EXISTS " + USER_TABLE_NAME + "(_id INTEGER PRIMARY KEY AUTOINCREMENT," + " name TEXT)"); db.execSQL("CREATE TABLE IF NOT EXISTS " + JOB_TABLE_NAME + "(_id INTEGER PRIMARY KEY AUTOINCREMENT," + " job TEXT)"); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } }
步驟2:自定義 ContentProvider 類
public class MyProvider extends ContentProvider { private Context mContext; DBHelper mDbHelper = null; SQLiteDatabase db = null; public static final String AUTOHORITY = "cn.scu.myprovider"; // 設(shè)置ContentProvider的唯一標(biāo)識(shí) public static final int User_Code = 1; public static final int Job_Code = 2; // UriMatcher類使用:在ContentProvider 中注冊(cè)URI private static final UriMatcher mMatcher; static{ mMatcher = new UriMatcher(UriMatcher.NO_MATCH); // 初始化 mMatcher.addURI(AUTOHORITY,"user", User_Code); mMatcher.addURI(AUTOHORITY, "job", Job_Code); // 若URI資源路徑 = content://cn.scu.myprovider/user ,則返回注冊(cè)碼User_Code // 若URI資源路徑 = content://cn.scu.myprovider/job ,則返回注冊(cè)碼Job_Code } // 以下是ContentProvider的6個(gè)方法 /** * 初始化ContentProvider */ @Override public boolean onCreate() { mContext = getContext(); // 在ContentProvider創(chuàng)建時(shí)對(duì)數(shù)據(jù)庫(kù)進(jìn)行初始化 // 運(yùn)行在主線程,故不能做耗時(shí)操作,此處僅作展示 mDbHelper = new DBHelper(getContext()); db = mDbHelper.getWritableDatabase(); // 初始化兩個(gè)表的數(shù)據(jù)(先清空兩個(gè)表,再各加入一個(gè)記錄) db.execSQL("delete from user"); db.execSQL("insert into user values(1,"Carson");"); db.execSQL("insert into user values(2,"Kobe");"); db.execSQL("delete from job"); db.execSQL("insert into job values(1,"Android");"); db.execSQL("insert into job values(2,"iOS");"); return true; } /** * 添加數(shù)據(jù) */ @Override public Uri insert(Uri uri, ContentValues values) { // 根據(jù)URI匹配 URI_CODE,從而匹配ContentProvider中相應(yīng)的表名 // 該方法在最下面 String table = getTableName(uri); // 向該表添加數(shù)據(jù) db.insert(table, null, values); // 當(dāng)該URI的ContentProvider數(shù)據(jù)發(fā)生變化時(shí),通知外界(即訪問(wèn)該ContentProvider數(shù)據(jù)的訪問(wèn)者) mContext.getContentResolver().notifyChange(uri, null); // // 通過(guò)ContentUris類從URL中獲取ID // long personid = ContentUris.parseId(uri); // System.out.println(personid); return uri; } /** * 查詢數(shù)據(jù) */ @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { // 根據(jù)URI匹配 URI_CODE,從而匹配ContentProvider中相應(yīng)的表名 // 該方法在最下面 String table = getTableName(uri); // // 通過(guò)ContentUris類從URL中獲取ID // long personid = ContentUris.parseId(uri); // System.out.println(personid); // 查詢數(shù)據(jù) return db.query(table,projection,selection,selectionArgs,null,null,sortOrder,null); } /** * 更新數(shù)據(jù) */ @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { // 由于不展示,此處不作展開 return 0; } /** * 刪除數(shù)據(jù) */ @Override public int delete(Uri uri, String selection, String[] selectionArgs) { // 由于不展示,此處不作展開 return 0; } @Override public String getType(Uri uri) { // 由于不展示,此處不作展開 return null; } /** * 根據(jù)URI匹配 URI_CODE,從而匹配ContentProvider中相應(yīng)的表名 */ private String getTableName(Uri uri){ String tableName = null; switch (mMatcher.match(uri)) { case User_Code: tableName = DBHelper.USER_TABLE_NAME; break; case Job_Code: tableName = DBHelper.JOB_TABLE_NAME; break; } return tableName; } }
步驟3:注冊(cè) 創(chuàng)建的 ContentProvider類
AndroidManifest.xml
步驟4:進(jìn)程內(nèi)訪問(wèn) ContentProvider中的數(shù)據(jù)
MainActivity.java
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); /** * 對(duì)user表進(jìn)行操作 */ // 設(shè)置URI Uri uri_user = Uri.parse("content://cn.scu.myprovider/user"); // 插入表中數(shù)據(jù) ContentValues values = new ContentValues(); values.put("_id", 3); values.put("name", "Iverson"); // 獲取ContentResolver ContentResolver resolver = getContentResolver(); // 通過(guò)ContentResolver 根據(jù)URI 向ContentProvider中插入數(shù)據(jù) resolver.insert(uri_user,values); // 通過(guò)ContentResolver 向ContentProvider中查詢數(shù)據(jù) Cursor cursor = resolver.query(uri_user, new String[]{"_id","name"}, null, null, null); while (cursor.moveToNext()){ System.out.println("query book:" + cursor.getInt(0) +" "+ cursor.getString(1)); // 將表中數(shù)據(jù)全部輸出 } cursor.close(); // 關(guān)閉游標(biāo) /** * 對(duì)job表進(jìn)行操作 */ // 和上述類似,只是URI需要更改,從而匹配不同的URI CODE,從而找到不同的數(shù)據(jù)資源 Uri uri_job = Uri.parse("content://cn.scu.myprovider/job"); // 插入表中數(shù)據(jù) ContentValues values2 = new ContentValues(); values2.put("_id", 3); values2.put("job", "NBA Player"); // 獲取ContentResolver ContentResolver resolver2 = getContentResolver(); // 通過(guò)ContentResolver 根據(jù)URI 向ContentProvider中插入數(shù)據(jù) resolver2.insert(uri_job,values2); // 通過(guò)ContentResolver 向ContentProvider中查詢數(shù)據(jù) Cursor cursor2 = resolver2.query(uri_job, new String[]{"_id","job"}, null, null, null); while (cursor2.moveToNext()){ System.out.println("query job:" + cursor2.getInt(0) +" "+ cursor2.getString(1)); // 將表中數(shù)據(jù)全部輸出 } cursor2.close(); // 關(guān)閉游標(biāo) } }結(jié)果 源碼地址
Carson-Ho Github地址:ContentProvider
至此,進(jìn)程內(nèi)對(duì)ContentProvider中的數(shù)據(jù)進(jìn)行共享講解完畢。
*
5.2 進(jìn)程間進(jìn)行數(shù)據(jù)共享實(shí)例說(shuō)明:本文需要?jiǎng)?chuàng)建2個(gè)進(jìn)程,即創(chuàng)建兩個(gè)工程,作用如下
具體使用
進(jìn)程1使用步驟如下:
創(chuàng)建數(shù)據(jù)庫(kù)類
自定義 ContentProvider 類
注冊(cè) 創(chuàng)建的 ContentProvider 類
前2個(gè)步驟同上例相同,此處不作過(guò)多描述,此處主要講解步驟3.
步驟3:注冊(cè) 創(chuàng)建的 ContentProvider類
AndroidManifest.xml
// 聲明本應(yīng)用 可允許通信的權(quán)限 // 細(xì)分讀 & 寫權(quán)限如下,但本Demo直接采用全權(quán)限 // //
至此,進(jìn)程1創(chuàng)建完畢,即創(chuàng)建ContentProvider & 數(shù)據(jù) 準(zhǔn)備好了。
進(jìn)程2步驟1:聲明可訪問(wèn)的權(quán)限
AndroidManifest.xml
// 聲明本應(yīng)用可允許通信的權(quán)限(全權(quán)限)// 細(xì)分讀 & 寫權(quán)限如下,但本Demo直接采用全權(quán)限 // // // 注:聲明的權(quán)限必須與進(jìn)程1中設(shè)置的權(quán)限對(duì)應(yīng)
步驟2:訪問(wèn) ContentProvider的類
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); /** * 對(duì)user表進(jìn)行操作 */ // 設(shè)置URI Uri uri_user = Uri.parse("content://scut.carson_ho.myprovider/user"); // 插入表中數(shù)據(jù) ContentValues values = new ContentValues(); values.put("_id", 4); values.put("name", "Jordan"); // 獲取ContentResolver ContentResolver resolver = getContentResolver(); // 通過(guò)ContentResolver 根據(jù)URI 向ContentProvider中插入數(shù)據(jù) resolver.insert(uri_user,values); // 通過(guò)ContentResolver 向ContentProvider中查詢數(shù)據(jù) Cursor cursor = resolver.query(uri_user, new String[]{"_id","name"}, null, null, null); while (cursor.moveToNext()){ System.out.println("query book:" + cursor.getInt(0) +" "+ cursor.getString(1)); // 將表中數(shù)據(jù)全部輸出 } cursor.close(); // 關(guān)閉游標(biāo) /** * 對(duì)job表進(jìn)行操作 */ // 和上述類似,只是URI需要更改,從而匹配不同的URI CODE,從而找到不同的數(shù)據(jù)資源 Uri uri_job = Uri.parse("content://scut.carson_ho.myprovider/job"); // 插入表中數(shù)據(jù) ContentValues values2 = new ContentValues(); values2.put("_id", 4); values2.put("job", "NBA Player"); // 獲取ContentResolver ContentResolver resolver2 = getContentResolver(); // 通過(guò)ContentResolver 根據(jù)URI 向ContentProvider中插入數(shù)據(jù) resolver2.insert(uri_job,values2); // 通過(guò)ContentResolver 向ContentProvider中查詢數(shù)據(jù) Cursor cursor2 = resolver2.query(uri_job, new String[]{"_id","job"}, null, null, null); while (cursor2.moveToNext()){ System.out.println("query job:" + cursor2.getInt(0) +" "+ cursor2.getString(1)); // 將表中數(shù)據(jù)全部輸出 } cursor2.close(); // 關(guān)閉游標(biāo) } }
至此,訪問(wèn)ContentProvider數(shù)據(jù)的進(jìn)程2創(chuàng)建完畢
結(jié)果展示在進(jìn)程展示時(shí),需要先運(yùn)行準(zhǔn)備數(shù)據(jù)的進(jìn)程1,再運(yùn)行需要訪問(wèn)數(shù)據(jù)的進(jìn)程2
運(yùn)行準(zhǔn)備數(shù)據(jù)的進(jìn)程1
在進(jìn)程1中,我們準(zhǔn)備好了一系列數(shù)據(jù)
運(yùn)行需要訪問(wèn)數(shù)據(jù)的進(jìn)程2
在進(jìn)程2中,我們先向`ContentProvider`中插入數(shù)據(jù),再查詢數(shù)據(jù)
至此,關(guān)于ContentProvider在進(jìn)程內(nèi) & 進(jìn)程間的使用講解完畢。
6. 優(yōu)點(diǎn) 6.1 安全ContentProvider為應(yīng)用間的數(shù)據(jù)交互提供了一個(gè)安全的環(huán)境:允許把自己的應(yīng)用數(shù)據(jù)根據(jù)需求開放給 其他應(yīng)用 進(jìn)行 增、刪、改、查,而不用擔(dān)心因?yàn)橹苯娱_放數(shù)據(jù)庫(kù)權(quán)限而帶來(lái)的安全問(wèn)題
6.2 訪問(wèn)簡(jiǎn)單 & 高效對(duì)比于其他對(duì)外共享數(shù)據(jù)的方式,數(shù)據(jù)訪問(wèn)方式會(huì)因數(shù)據(jù)存儲(chǔ)的方式而不同:
采用 文件方式 對(duì)外共享數(shù)據(jù),需要進(jìn)行文件操作讀寫數(shù)據(jù);
采用 Sharedpreferences 共享數(shù)據(jù),需要使用sharedpreferences API讀寫數(shù)據(jù)
這使得訪問(wèn)數(shù)據(jù)變得復(fù)雜 & 難度大。
而采用ContentProvider方式,其 解耦了 底層數(shù)據(jù)的存儲(chǔ)方式,使得無(wú)論底層數(shù)據(jù)存儲(chǔ)采用何種方式,外界對(duì)數(shù)據(jù)的訪問(wèn)方式都是統(tǒng)一的,這使得訪問(wèn)簡(jiǎn)單 & 高效
> 如一開始數(shù)據(jù)存儲(chǔ)方式 采用 `SQLite` 數(shù)據(jù)庫(kù),后來(lái)把數(shù)據(jù)庫(kù)換成 `MongoDB`,也不會(huì)對(duì)上層數(shù)據(jù)`ContentProvider`使用代碼產(chǎn)生影響7. 總結(jié)
我用一張圖總結(jié)本文內(nèi)容
ContentProvider的底層是采用 Android中的Binder機(jī)制,若想了解請(qǐng)看文章圖文詳解 Android Binder跨進(jìn)程通信的原理
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/70540.html
摘要:如何自學(xué)知識(shí)儲(chǔ)備本知識(shí)點(diǎn)不做重點(diǎn)講解對(duì)于有基礎(chǔ)的同學(xué)推薦看編程思想,鞏固基礎(chǔ),查漏補(bǔ)全,了解并熟悉更多細(xì)節(jié)知識(shí)點(diǎn)?;A(chǔ)學(xué)習(xí)基礎(chǔ)學(xué)習(xí)對(duì)于這些基礎(chǔ)的使用谷歌官網(wǎng)給出了很好的實(shí)例。是谷歌根據(jù)自帶的改進(jìn)的。是基于谷歌內(nèi)核的一個(gè)可以作為瀏覽器的視圖。 如何自學(xué)Android 1. Java知識(shí)儲(chǔ)備 本知識(shí)點(diǎn)不做重點(diǎn)講解: 對(duì)于有基礎(chǔ)的同學(xué)推薦看《Java編程思想》,鞏固基礎(chǔ),查漏補(bǔ)全,了解...
摘要:四大組件都支持這個(gè)屬性。到目前為止,中總共有三種啟動(dòng)方式。返回值方法有一個(gè)的返回值,這個(gè)返回值標(biāo)識(shí)服務(wù)關(guān)閉后系統(tǒng)的后續(xù)操作。,啟動(dòng)后的服務(wù)被殺死,不能保證系統(tǒng)一定會(huì)重新創(chuàng)建。 1. 簡(jiǎn)介 這篇文章會(huì)從Service的一些小知識(shí)點(diǎn),延伸到Android中幾種常用進(jìn)程間通信方法。 2. 進(jìn)程 ? ? ? ?Service是一種不提供用戶交互頁(yè)面但是可以在后臺(tái)長(zhǎng)時(shí)間運(yùn)行的組件,可以通過(guò)在An...
閱讀 1580·2021-11-24 10:17
閱讀 1083·2021-09-29 09:43
閱讀 2214·2021-09-23 11:21
閱讀 2324·2019-08-30 14:13
閱讀 1339·2019-08-29 13:58
閱讀 3217·2019-08-28 17:51
閱讀 1917·2019-08-26 13:29
閱讀 3033·2019-08-26 10:13