Android數(shù)據(jù)持久化之ContentProvider機(jī)制詳解
本文實(shí)例講述了Android數(shù)據(jù)持久化之ContentProvider機(jī)制。分享給大家供大家參考,具體如下:
一般而言,android操作系統(tǒng)的應(yīng)用程序所建立的數(shù)據(jù)只允許自己使用,應(yīng)用程序彼此間無法借助公用存儲器來共享數(shù)據(jù),android系統(tǒng)提供了一個(gè)機(jī)制,即內(nèi)容提供器(ContentProvider),來公開自己私有的數(shù)據(jù)到數(shù)據(jù)內(nèi)容器,通過該機(jī)制,可以供其他應(yīng)用程序來讀取自己內(nèi)部的數(shù)據(jù),當(dāng)然也可以訪問其他應(yīng)用程序的數(shù)據(jù)。通常,內(nèi)容提供器背后都有SQLite數(shù)據(jù)庫的支持,用以存儲內(nèi)容提供內(nèi)部數(shù)據(jù)。
實(shí)現(xiàn)ContentProvider與實(shí)現(xiàn)SQLite的區(qū)別:
應(yīng)用程序?qū)崿F(xiàn)SQLite時(shí),由應(yīng)用程序直接與數(shù)據(jù)庫進(jìn)行對接,所以要在應(yīng)用程序中實(shí)現(xiàn)SQLite的接口:db.onCreate()、db.insert()、db.update()、db.delete()、db.query()和db.close();
實(shí)現(xiàn)內(nèi)容提供器時(shí),在應(yīng)用程序與數(shù)據(jù)庫之間要實(shí)現(xiàn)一個(gè)ContentProvider程序,這個(gè)ContentProvider程序會(huì)直接與數(shù)據(jù)庫進(jìn)行對接,此時(shí)應(yīng)用程序需要實(shí)現(xiàn)和ContentProvider程序接口的方法。
下面該說說如何建立內(nèi)容提供器了:
首先,實(shí)現(xiàn)內(nèi)容提供器接口:
實(shí)現(xiàn)該接口的5個(gè)重要方法;
其次,定義數(shù)據(jù)Uri:
提供器應(yīng)用程序需要定義一個(gè)“基底”Uri,以供其他應(yīng)用程序訪問這一內(nèi)容提供器,這一個(gè)Uri必須是唯一的,且必須是以“content://”開頭,content: 表示內(nèi)容提供器程序所控制數(shù)據(jù)的位置;在AndroidManifest.xml配置文件中添加如下代碼以進(jìn)行聲明:
<!-- 設(shè)置類名和授權(quán) multiprocess屬性是數(shù)據(jù)的同步性(同一時(shí)間可能有多個(gè)程序訪問該內(nèi)容提供器)--> <provider android:name="ContentProviderClass" android:multiprocess="true" android:authorities="com.example.data_contentprovider.ContentProviderClass" > </provider>
在應(yīng)用程序中添加如下代碼:
//acquire the Uri of ContentProvider getIntent().setData(Uri.parse("content://com.example.data_contentprovider.ContentProviderClass")); Uri uri = getIntent().getData();
定義一個(gè)Uri所在的位置,并設(shè)置一個(gè)變量來找到內(nèi)容提供器程序的接口;
如下是一個(gè)完整的代碼,功能是實(shí)現(xiàn)內(nèi)容提供器的建立以及通過該內(nèi)容提供器程序來添加和檢索數(shù)據(jù):
實(shí)現(xiàn)內(nèi)容提供器接口的代碼:
package com.example.data_contentprovider; import com.example.data_contentprovider.DB.DBHelper; import android.net.Uri; import android.content.ContentProvider; import android.content.ContentValues; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteQueryBuilder; public class ContentProviderClass extends ContentProvider { DBHelper dataBaseHelper; // 定義DataBaseHelper類變量dataBaseHelper // 實(shí)現(xiàn)ContentProvider的onCreate方法 @Override public boolean onCreate() { // TODO Auto-generated method stub dataBaseHelper = new DBHelper(getContext()); return true; } @Override public Uri insert(Uri uri, ContentValues values) { // TODO Auto-generated method stub SQLiteDatabase db = dataBaseHelper.getWritableDatabase(); db.insert("test", null, values); return null; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { // TODO Auto-generated method stub SQLiteDatabase db = dataBaseHelper.getReadableDatabase(); SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder(); queryBuilder.setTables("test"); Cursor cursor = queryBuilder.query(db, projection, selection, selectionArgs, null, null, null); return cursor; } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { // TODO Auto-generated method stub return 0; } @Override public String getType(Uri uri) { // TODO Auto-generated method stub return null; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { // TODO Auto-generated method stub return 0; } }
配置AndroidManifest.xml文件:
<!-- 設(shè)置類名和授權(quán) multiprocess屬性是數(shù)據(jù)的同步性(同一時(shí)間可能有多個(gè)程序訪問該內(nèi)容提供器)--> <provider android:name="ContentProviderClass" android:multiprocess="true" android:authorities="com.example.data_contentprovider.ContentProviderClass" > </provider>
建立一個(gè)SQLite數(shù)據(jù)庫系統(tǒng)來存儲和管理數(shù)據(jù),同時(shí)利用SQLiteOpenHilper類協(xié)助建立數(shù)據(jù)庫和SQLiteDatabase類來管理數(shù)據(jù)庫:
package com.example.data_contentprovider.DB; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.provider.BaseColumns; public class DBHelper extends SQLiteOpenHelper { // 建立test.db數(shù)據(jù)庫 public DBHelper(Context context) { super(context, "test.db", null, 1); } // 建立test表 @Override public void onCreate(SQLiteDatabase db) { db.execSQL("create table test (" + BaseColumns._ID + "integer primary key," + "name text," + "description text" + ");"); } // 更新新版本 @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSQL("DROP TABLE IF EXISTS test"); onCreate(db); } }
下面就是provider的應(yīng)用程序了:
package com.example.data_contentprovider; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import android.app.Activity; import android.content.ContentValues; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.widget.ListView; import android.widget.SimpleAdapter; public class ContentProviderActivity extends Activity { String [] from = {"column00","column01","column02"}; @SuppressWarnings("deprecation") @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); //acquire the Uri of ContentProvider getIntent().setData(Uri.parse("content://com.example.data_contentprovider.ContentProviderClass")); Uri uri = getIntent().getData(); //create some data to test ContentValues values = new ContentValues(); values.put("name", "marry"); values.put("description", "123456"); getContentResolver().insert(uri, values); //獲取ContentResolver對象(在應(yīng)用程序B中,通過ContentResolver獲取程序A的ContentProvider中的數(shù)據(jù)。) values.put("name", "hello"); values.put("description", "654321"); getContentResolver().insert(uri, values); //search db all colum,cursor point to first colum of result Cursor cursor = managedQuery(uri, null, null, null, null); cursor.moveToFirst(); //set ArrayList,view more field table ArrayList<Map<String,Object>> data = new ArrayList<Map<String,Object>>(); Map<String, Object> item; //from db read data and save to ArrayList data container for (int i = 0; i < cursor.getCount(); i++) { item = new HashMap<String, Object>(); item.put("column00", cursor.getString(0)); item.put("column01", cursor.getString(1)); item.put("column02", cursor.getString(2)); data.add(item); cursor.moveToNext(); } cursor.close(); //ArrayList container data save to listView ListView listView = new ListView(this); SimpleAdapter adapter = new SimpleAdapter(this, data, R.layout.activity_content_provider, from, new int[]{R.id.text1,R.id.text2,R.id.text3}); listView.setAdapter(adapter); setContentView(listView); } }
provider應(yīng)用程序就可以通過該內(nèi)容提供器檢索數(shù)據(jù)庫并向其添加數(shù)據(jù)了。
ContentProvider中重要的幾個(gè)類:
UriMatcher:
要了解UriMatcher,首先需要了解android中的Uri表示方法,眾所周知,Uri為通用資源標(biāo)識符,它代表的是要操作的數(shù)據(jù),Android中的每一種資源(比如文本,圖像,視頻等)都可以用Uri來表示。Android中的Uri由以下三部分組成:”content://”(即authory),數(shù)據(jù)的路徑,資源標(biāo)識ID(可選),其中如果存在ID,則表示某一個(gè)具體的資源,如果不存在ID,則表示路徑下的整體。因此addUri()函數(shù)的3個(gè)參數(shù)也是對應(yīng)上面的那3個(gè)。UriMatcher的匹配過程分為3步:初始化UriMatcher;注冊需要用的Uri;與已經(jīng)注冊的Uri進(jìn)行匹配。
ContentResolver :
當(dāng)使用ContentProvider在不同的應(yīng)用程序共享數(shù)據(jù)時(shí),其數(shù)據(jù)的暴露方式是采取類似數(shù)據(jù)庫中表的方法。而ContentResolver 是恰好是采用類似數(shù)據(jù)庫的方法來從ContentProvider中存取數(shù)據(jù)的,它是通過Uri來查詢ContentProvider中提供的數(shù)據(jù),查詢時(shí),還需知道目的數(shù)據(jù)庫的名稱,數(shù)據(jù)段的數(shù)據(jù)類型,或者說資源的ID。
SQLiteQueryBuilder:
是一個(gè)用來生產(chǎn)SQL查詢語句的輔助類,可以方便的去訪問SQLiteDatabase. 在構(gòu)造SQL查詢語句時(shí),它同樣也需要指定表名,指定列名,指定where條件等。
希望本文所述對大家Android程序設(shè)計(jì)有所幫助。
相關(guān)文章
Android頂部狀態(tài)欄透明化并釋放空間的兩種實(shí)現(xiàn)方法
這篇文章主要介紹了Android頂部狀態(tài)欄透明化并釋放空間的兩種實(shí)現(xiàn)方法,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-03-03Android NestedScrolling嵌套滾動(dòng)的示例代碼
這篇文章主要介紹了Android NestedScrolling嵌套滾動(dòng)的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-05-05android使用handlerthread創(chuàng)建線程示例
這篇文章主要介紹了android使用handlerthread創(chuàng)建線程,講解了這種方式的好處及為什么不使用Thread類的原因2014-01-01Android ScrollView嵌套ExpandableListView顯示不正常的問題的解決辦法
這篇文章主要介紹了Android ScrollView嵌套ExpandableListView顯示不正常的問題的解決辦法的相關(guān)資料,需要的朋友可以參考下2017-02-02android播放視頻時(shí)在立體聲與單聲道之間切換無變化原因分析及解決
使用第三方視頻播放器,有立體聲與單聲道之間切換,發(fā)現(xiàn)切換后無作用,原因是由于在HAL層默認(rèn)沒有處理上層發(fā)的stereo 轉(zhuǎn)mono的命令,具體的解決方法如下2013-06-06詳談自定義View之GridView單選 金額選擇Layout-ChooseMoneyLayout
下面小編就為大家?guī)硪黄斦勛远xView之GridView單選 金額選擇Layout-ChooseMoneyLayout。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-05-05android4.0混淆XmlPullParser報(bào)錯(cuò)原因分析解決
今天,用android4.0在proguard-project.txt中加入 -libraryjars libs/ksoap2-android-assembly-2.6.0-jar-with-dependencies.jar這句話后,混淆時(shí)報(bào)上面的錯(cuò)誤,下面與大家分享下具體的解決方法2013-06-06