Android中的Serializable、Parcelable">Android中的Serializable、Parcelable
800
2022-05-29
好問的人,只做了五分鐘的愚人;恥于發問的人,終身為愚人。
Android提供了5種方式來讓用戶保存持久化應用程序數據。根據自己的需求來做選擇,比如數據是否是應用程序私有的,是否能被其他程序訪問,需要多少數據存儲空間等,分別是:
使用SharedPreferences存儲數據
文件存儲數據
SQLite數據庫存儲數據
「使用ContentProvider存儲數據」
網絡存儲數據
咱們今天就來學習一下ContentProvider。作為Android四大巨頭之一的他有點名不副實,因為在一般的開發過程中,使用的次數比較少。大部分應用的數據緩存用SharedPreferences就能搞定了。
「ContentProvider(數據提供者)是應用程序之間共享數據的一種接口機制,是一種更為高級的數據共享方法。」
ContentProvider可以指定需要共享的數據,而其他應用程序則可以在不知道數據來源、路徑的情況下,對共享數據進行增刪改查等操作。
在Android系統中,許多Android系統內置的數據也是通過ContentProvider提供給用戶使用,例如通訊錄、音視頻文件和圖像文件等。
一、什么是ContentProvider
ContentProvider是Android的四大組件之一,以標準化的方式在Android 應用間共享數據。
ContentProvider封裝的數據存儲以及增刪改查等,并且必須實現一個對外統一的接口(Uri)。
二、什么是Uri
Uri(通用資源標識符 Universal Resource Identifer),代表數據操作的地址,每一個ContentProvider都會有唯一的地址。
ContentProvider使用的Uri語法結構如下:
content://authority/data_path/id
「content://」 是通用前綴,表示該Uri用于ContentProvider定位資源。
「authority」 是授權者名稱,用來確定具體由哪一個ContentProvider提供資源。因此一般authority都由類的小寫全稱組成,以保證唯一性。
「data_path」 是數據路徑,用來確定請求的是哪個數據集。
「id」 是數據編號,用來請求單條數據。如果是多條這個字段忽略。
樣例:
content://com.scc.userprovider/user多條
content://com.scc.userprovider/user/10單條
三、什么是ContentResolver
ContentResolver是數據調用者,ContentProvider將數據發布出來,通過ContentResolver對象結合Uri進行調用。
一般來說ContentProvider是單例模式,多個應用可通過ContentResolver調用ContentProvider的增刪改查操作數據,ContentResolver調用的數據操作會讓同一個ContentProvider處理。
四、創建ContentProvider
1、創建一個類讓其繼承ContentProvider,并重載6個函數
需要實現的主要方法是:
「insert()」、「delete()」、「update()」、「query()」:用于對數據集的增刪改查操作。
「onCreate()」:一般用來初始化底層數據集和建立數據連接等工作
「getType()」:用來返回指定Uri的MIME數據類型,
若Uri是單條數據,則返回的MIME數據類型以vnd.Android.cursor.item開頭;
若Uri是多條數據,則返回的MIME數據類型以vnd.android.cursor.dir/開頭。
數據訪問方法「如insert(Uri,ContentValues)和update(Uri,ContentValues,Bundle)」 可以同時從多個線程調用,并且必須是線程安全的。其他方法「如onCreate()」 僅從應用程序主線程調用,并且必須避免執行冗長的操作。請參閱其預期線程行為的方法描述。
2、聲明Uri規則,實現UriMatcher
咱先來看看UriMatcher是干嘛的,UriMatcher本質上是一個文本過濾器,有助于解析Uri,用在ContentProvider中幫助我們過濾,分辨出查詢者想要查詢哪個數據表。
UriMatcher的構造函數中,UriMatcher.NO_MATCH是Uri無匹配時的返回代碼,值為-1。addUri()方法用來添加新的匹配項,語法為:
public?void?addUri(String?authority,?String?path,?int?code)
authority表示匹配的授權者名稱;
path表示數據路徑;
code表示返回代碼。
下面咱搞個實例:
//這里的名稱必須與AndroidManifest.xml中android:authorities保持一致
public?static?final?String?AUTHORITY?=?"com.scc.userprovider";
//數據路徑
public?static?final?String?PATH_USERS?=?"user";
//訪問ContentProvider的URL
public?static?final?Uri?CONTENT_URI?=?Uri.parse("content://"?+?AUTHORITY?+?"/"?+?PATH_USERS);
//返回代碼
public?static?final?int?USER_INFO?=?1;
//創建UriMatcher對象
private?static?UriMatcher?uriMatcher;
//創建靜態代碼塊
static?{
//實例化UriMatcher對象
uriMatcher?=?new?UriMatcher(UriMatcher.NO_MATCH);
//參數1:authority;參數2:路徑;參數3:自定義代碼
uriMatcher.addURI(UserInfoContent.AUTHORITY,?UserInfoContent.PATH_USERS,?USER_INFO);
}
3、注冊ContentProvider
在AndroidManifest.xml文件中的 application節點下使用標簽注冊。樣例:
android:name=".UserProvider" android:exported="true"/> 五、使用ContentProvider 1、通過insert()方法添加單條數據 ContentValues?cv?=?new?ContentValues(); cv.put(UserInfoContent._ID,?bean.get_id()); cv.put(UserInfoContent.USER_NAME,?bean.getName()); cv.put(UserInfoContent.USER_AGE,?bean.getAge()); cv.put(UserInfoContent.USER_UPDATE_TIME,?bean.getUpdate_time()); Uri?uri?=?getContentResolver().insert(UserInfoContent.CONTENT_URI,?cv); Log.e(getClass().getName(),?"insert:"?+?uri); 通過bulkInsert()方法添加多條數據 ContentValues[]?arrayValues?=?new?ContentValues[10]; //實例化每一個ContentValues... int?count?=?getContentResolver().bulkInsert(UserInfoContent.CONTENT_URI,?arrayValues); 2、指定ID刪除單條數據 int?delete?=?getContentResolver().delete(UserInfoContent.CONTENT_URI,?"_id=12",?null); Log.e(getClass().getName(),?"delete(失敗返回-1):"?+?delete); 通過selection語句刪除多條數據 String?selection?=?UserInfoContent._ID?+?">12"; int?result?=?getContentResolver().delete(UserInfoContent.CONTENT_URI,?selection,?null); 3、修改數據 UserInfoBean?bean?=?new?UserInfoBean("蚩尤",?32,?"12:00"); ContentValues?cv?=?new?ContentValues(); cv.put(UserInfoContent.USER_NAME,?bean.getName()); cv.put(UserInfoContent.USER_AGE,?bean.getAge()); cv.put(UserInfoContent.USER_UPDATE_TIME,?bean.getUpdate_time()); getContentResolver().update(UserInfoContent.CONTENT_URI,?cv,?"_id=18",?null); 4、查詢數據 Cursor?cursor?=?getContentResolver().query(UserInfoContent.CONTENT_URI,?null,?selection,?null,?null); //循環取出游標指向的每條用戶記錄 while?(cursor.moveToNext())?{ UserInfoBean?user?=?new?UserInfoBean(); user.name?=?cursor.getString(cursor.getColumnIndex(UserInfoContent.USER_NAME)); user.age?=?cursor.getInt(cursor.getColumnIndex(UserInfoContent.USER_AGE)); user._id?=?cursor.getString(cursor.getColumnIndex(UserInfoContent._ID)); user.update_time?=?cursor.getString(cursor.getColumnIndex(UserInfoContent.USER_UPDATE_TIME)); userList.add(user);?//添加到用戶信息列表 } cursor.close();?//關閉數據庫游標 Log.e(getClass().getName(),?"Query用戶:"?+?String.format("當前共找到%d個用戶",?userList.size())); 六、跨應用使用ContentProvider 跨應用和本應用使用ContentProvider一樣的方法,這邊就不做復制了。 例五的Uri是拼接字段,拼接后的結果 : 「content://com.scc.userprovider/user。」 跨平臺使用getContentResolver().方法 的第一個參數: 「Uri uricontent = Uri.parse("content://com.scc.userprovider/user");」 1、新增數據+查找數據 2、修改數據+刪除數據 七、java.lang.SecurityException: Permission Denial: opening provider com.scc.cp.UserProvider from ProcessRecord 解決方案: 在AndroidManifest.xml文件中的 application節點下使用標簽注冊時android:exported="false"時,不允許其他應用調用。 所以其他和應用使用ContentProvider會崩潰報錯。將exported改為:android:exported="true"即可。 源碼:ContentProviderDemo.zip Android
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。