23、從頭學Android之ContentProvider

來源:互聯網
上載者:User

應用情境:

在Android官方指出的Android的資料存放區方式總共有五種,分別是:Shared Preferences、網路儲存、檔案儲存體、外儲儲存、SQLite。但是我們知道一般這些儲存都只是在單獨的一個應用程式之中達到一個資料的共用,而且這些知識在前面我都有介紹,有時候我們需要操作其他應用程式的一些資料,例如我們需要作業系統裡的媒體庫、通訊錄等,這時我們就可能通過ContentProvider來滿足我們的需求了

ContentProvider概述:

ContentProvider向我們提供了我們在應用程式之前共用資料的一種機制,而我們知道每一個應用程式都是運行在不同的應用程式的,資料和檔案在不同應用程式之間達到資料的共用不是沒有可能,而是顯得比較複雜,而正好Android中的ContentProvider則達到了這一需求,比如有時候我們需要操作手機裡的連絡人,手機裡的多媒體等一些資訊,我們都可以用到這個ContentProvider來達到我們所需。

如何理解ContentProvider

上面說了一大堆ContentProvider的概述,可能大家還是不太特別理解ContentProvider到底是幹什麼的,那麼我們以一個網站來形象的描述這個ContentProvider吧,可以這麼理解為ContentProvider就是一個網站,它向我們去訪問網站這裡的資料達到了一種可能,它就是一個向外提供資料的介面。那麼既然它是向外提供資料,我們有時候也需要去修改資料,這時我們就可以用到另外一個類來實現這個對資料的修改ContentResolver類,這個類就可以通過URI來操作資料。至於這些類的作用及描述在下面就會一一的介紹到。

如何?ContentProvider

理解了ContentProvider類,那麼我們怎麼去實現ContentProvider呢?怎麼樣讓外部程式去訪問或者修改我們的資料呢?這樣的一個操作其實是非常簡單的,我們只需要下面的兩步就可以實現ContentProvider

1、  編寫一個實現ContentProvider的在,這個子類必須要實現一些必須實現的方法,在ContentProvider類裡面,有一系列針對於資料的增、刪、改、查等方法

2、  ContentProvider也是Android中的四大組件,因此也必須在AndroidMainfest.xml中完成對ContentProvider的註冊。註冊方式為:

 

與ContentProvider相關操作的類介紹

從Uri談起

什麼是Uri?

Uri是指通用資源標誌符

A:首碼表明資料受控於一個內容提供者。它從不修改,也就是schema

B:是指在AndroidMainfest.xml中我們註冊的provider中的android:authorities屬性所對應的

C:具體操作於哪個條目

D:具體指定到哪個條目下的哪條記錄

再看它的類結構和常用方法:

Uri

在這個裡它是沒有構造方法的,它通常通過下面的這個方法來返回一個Uri對象

方法名稱

描述

public static Uri parse (String uriString)

通過一個傳入的字串來構造一個Uri對象

熟悉完Uri類再看與之相關的另外兩個類

UriMatcher類:

因為Uri代表了要操作的資料,所以我們經常需要解析Uri,並從Uri中擷取資料。Android系統提供了兩個用於操作Uri的工具類,分別為UriMatcher 和ContentUris 。掌握它們的使用,會便於我們的開發工作。

先看下它比較常用的幾個方法:

方法名稱

描述

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

往UriMatcher類裡添加一個拼湊的Uri,在此我們可以理解為UriMatcher為一個Uri的容器,為個容器裡麵包含著我們即將可能要操作的Uri,它用於我們商務邏輯的處理,特別是第三個參數code,如果通過下面的match()方法匹配成功就返回這個code值

public int match (Uri uri)

與傳入的Uri匹配,它會首先與找我們之前通過addURI方法添加進來的Uri匹配,如果匹配成功就返回之前我們設定的code值,否則返回一個UriMatcher.NO_MATCH常量值為-1

熟悉完上面的方法,那麼我們再來看它如何使用:

UriMatcher類用於匹配Uri,它的用法如下:

UriMatcher類的用法

首先第一步把你需要匹配Uri路徑全部給註冊上,如下:

//常量UriMatcher.NO_MATCH表示不匹配任何路徑的返回碼

UriMatcher  sMatcher = new UriMatcher(UriMatcher.NO_MATCH);

//如果match()方法匹配content:// com.jiahui.provider.myprovider/person路徑,返回匹配碼為1

sMatcher.addURI(“com.jiahui.provider.myprovider”, “person”, 1);//添加需要匹配uri,如果匹配就會返回匹配碼

//如果match()方法匹配content:// com.jiahui.provider.myprovider /person/230路徑,返回匹配碼為2

sMatcher.addURI(“com.jiahui.provider.myprovider”, “person/#”, 2);//#號為萬用字元

switch (sMatcher.match(Uri.parse("content:// com.jiahui.provider.myprovider /person/10"))) {

   case 1

    break;

   case 2

    break;

   default://不匹配

    break;

}

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

再看另外一個工具類

ContentUris:

它用於在Uri後面追加一個ID或者解析出傳入的Uri所帶上的ID值,常用的兩個方法如下:

方法名稱

描述

public static Uri withAppendedId (Uri contentUri, long id)

用於為路徑加上ID部分

public static long parseId (Uri contentUri)

從路徑中擷取ID部分

熟悉完上面所提及的相關的類,接下來我們再看這個ContentProvider核心類

ContentProvider

常用方法

方法名稱

描述

public abstract boolean onCreate ()

在ContentProvider建立後被調用。

public abstract Uri insert (Uri uri, ContentValues values)

根據Uri插入values對就的資料

public abstract int delete (Uri uri, String selection, String[] selectionArgs)

根據Uri刪除selection指定的條件所匹配的全部記錄

public abstract int update (Uri uri, ContentValues values, String selection, String[] selectionArgs)

根據Uri修改selection指定的條件所匹配的全部記錄

public abstract Cursor query (Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)

根據Uri查詢出selection指定的條件所匹配的全部記錄,並且可以指定查詢哪些列(projection),以什麼方式(sortOrder)排序

public abstract String getType (Uri uri)

返回當前Uri所資料的MIME類型,如果該Uri對應的資料可能包括多條記錄,那麼MIME類型字串就是以vnd.android.cursor.dir/開頭,如果Uri對應的資料只包含一條記錄,那麼MIME類型字串就是以vnd.android.cursor.item/開頭

既然我們知道了ContentProvider類是向外提供資料的一種機制,那麼在之前我們也說過要想來操作這個對外提供的資料,我們就用到了另外一個類:

ContentResolver

在這個類裡面也定義了一系列的增、刪、改、查方法,與其ContentProvider定義的方法基本上相同,在此不再複核。讀者可以自己查閱相關文檔。

可能大家在這裡還是有點理不清這些類的一些關係,特別是ContentResolver與ContentProvider與Uri類的關係,那麼我上張圖吧,或許對大家有所協助:

好了熟悉完上面所述的這麼多類那麼我們就在實踐中見證真理吧:

執行個體:

實現效果:

  

代碼實現:

 

先開發我們自己的ContentProvider:

package com.jiahui.provider;import com.jiahui.db.DBHelper;import android.content.ContentProvider;import android.content.ContentUris;import android.content.ContentValues;import android.content.UriMatcher;import android.database.Cursor;import android.database.sqlite.SQLiteDatabase;import android.net.Uri;public class MyProvider extends ContentProvider {private DBHelper dbHelper;// 定義一個UriMatcher類private static final UriMatcher MATCHER = new UriMatcher(UriMatcher.NO_MATCH);private static final int PERSONS = 1;private static final int PERSON = 2;static {MATCHER.addURI("com.jiahui.provider.myprovider", "person", PERSONS);MATCHER.addURI("com.jiahui.provider.myprovider", "person/#", PERSON);}@Overridepublic boolean onCreate() {System.out.println("---oncreate----");dbHelper = new DBHelper(this.getContext());return false;}// 查詢資料@Overridepublic Cursor query(Uri uri, String[] projection, String selection,String[] selectionArgs, String sortOrder) {SQLiteDatabase db = dbHelper.getWritableDatabase();switch (MATCHER.match(uri)) {case PERSONS:// 查詢所有的資料return db.query("person", projection, selection, selectionArgs,null, null, sortOrder);case PERSON:// 查詢某個ID的資料// 通過ContentUris這個工具類解釋出IDlong id = ContentUris.parseId(uri);String where = " _id=" + id;if (!"".equals(selection) && selection != null) {where = selection + " and " + where;}return db.query("person", projection, where, selectionArgs, null,null, sortOrder);default:throw new IllegalArgumentException("unknow uri" + uri.toString());}}// 返回當前操作的資料的mimeType@Overridepublic String getType(Uri uri) {switch (MATCHER.match(uri)) {case PERSONS:return "vnd.android.cursor.dir/person";case PERSON:return "vnd.android.cursor.item/person";default:throw new IllegalArgumentException("Unkwon Uri:" + uri.toString());}}// 插入資料@Overridepublic Uri insert(Uri uri, ContentValues values) {SQLiteDatabase db = dbHelper.getWritableDatabase();Uri insertUri = null;switch (MATCHER.match(uri)) {case PERSONS:long rowid = db.insert("person", "name", values);insertUri = ContentUris.withAppendedId(uri, rowid);break;default:throw new IllegalArgumentException("Unkwon Uri:" + uri.toString());}return insertUri;}// 刪除資料@Overridepublic int delete(Uri uri, String selection, String[] selectionArgs) {SQLiteDatabase db = dbHelper.getWritableDatabase();int count = 0;switch (MATCHER.match(uri)) {case PERSONS:count = db.delete("person", selection, selectionArgs);return count;case PERSON:long id = ContentUris.parseId(uri);String where = "_id=" + id;if (selection != null && !"".equals(selection)) {where = selection + " and " + where;}count = db.delete("person", where, selectionArgs);return count;default:throw new IllegalArgumentException("Unkwon Uri:" + uri.toString());}}// 更新資料@Overridepublic int update(Uri uri, ContentValues values, String selection,String[] selectionArgs) {SQLiteDatabase db = dbHelper.getWritableDatabase();int count = 0;switch (MATCHER.match(uri)) {case PERSONS:count = db.update("person", values, selection, selectionArgs);break;case PERSON:// 通過ContentUri工具類得到IDlong id = ContentUris.parseId(uri);String where = "_id=" + id;if (selection != null && !"".equals(selection)) {where = selection + " and " + where;}count = db.update("person", values, where, selectionArgs);break;default:throw new IllegalArgumentException("Unkwon Uri:" + uri.toString());}return count;}}

 

千萬別忘記了要在AndroidMainfest.xml檔案中註冊這個組件哦:

 <provider            android:authorities="com.jiahui.provider.myprovider"            android:name=".MyProvider" >        </provider>

 

然後在一個主Activity編寫一些實現代碼:

package com.jiahui.provider;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import android.app.Activity;import android.content.ContentResolver;import android.content.ContentUris;import android.content.ContentValues;import android.content.Context;import android.content.Intent;import android.database.Cursor;import android.net.Uri;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.view.View;import android.widget.AdapterView;import android.widget.AdapterView.OnItemClickListener;import android.widget.Button;import android.widget.EditText;import android.widget.ListView;import android.widget.SimpleAdapter;import android.widget.Toast;import com.jiahui.model.Person;public class ContentProviderDemoActivity extends Activity {private Button btnadd, btnqueryall;private EditText edtname, edtage;private ListView lvall;private List<Person> persons;private SimpleAdapter simpleAdapter;private Handler handler = new Handler() {@Overridepublic void handleMessage(Message msg) {List<Map<String, Object>> data = (List<Map<String, Object>>) msg.obj;System.out.println(data.size());simpleAdapter = new SimpleAdapter(ContentProviderDemoActivity.this, data, R.layout.list_item,new String[] { "id", "name", "age" }, new int[] {R.id.tvId, R.id.tvname, R.id.tvage });lvall.setAdapter(simpleAdapter);}};public void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);persons = new ArrayList<Person>();btnqueryall = (Button) this.findViewById(R.id.btnqueryall);btnadd = (Button) this.findViewById(R.id.btnadd);edtname = (EditText) this.findViewById(R.id.edtname);edtage = (EditText) this.findViewById(R.id.edtage);lvall = (ListView) this.findViewById(R.id.lvall);btnadd.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {ContentResolver contentResolver = ContentProviderDemoActivity.this.getContentResolver();Uri url = Uri.parse("content://com.jiahui.provider.myprovider/person");ContentValues values = new ContentValues();values.put("name", edtname.getText().toString());values.put("age", edtage.getText().toString());Uri result = contentResolver.insert(url, values);System.out.println(result.toString());if (ContentUris.parseId(result)>0) {Toast.makeText(ContentProviderDemoActivity.this, "添加成功", Toast.LENGTH_LONG).show();//添加成功後再啟動線程查詢MyThread thread = new MyThread(ContentProviderDemoActivity.this);thread.start();}}});//查詢所有btnqueryall.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {MyThread thread = new MyThread(ContentProviderDemoActivity.this);thread.start();}});lvall.setOnItemClickListener(new OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> parent, View view,int position, long id) {// Toast.makeText(ContentProviderDemoActivity.this, position,// Toast.LENGTH_LONG).show();System.out.println("position:" + position);Person person = persons.get(position);Bundle bundle = new Bundle();bundle.putInt("id", person.getId());bundle.putString("name", person.getName());bundle.putInt("age", person.getAge());Intent intent = new Intent(ContentProviderDemoActivity.this,ItemActivity.class);intent.putExtra("item", bundle);startActivityForResult(intent, 1);}});}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {if (resultCode==2) {MyThread thread = new MyThread(ContentProviderDemoActivity.this);thread.start();}}class MyThread extends Thread {Context context;public MyThread(Context context) {//一定要清空。否則會 有問題,每執行一次都會把之前的全部的item加進去persons.clear();lvall.setAdapter(null);this.context = context;}@Overridepublic void run() {Uri url = Uri.parse("content://com.jiahui.provider.myprovider/person");Cursor cursor = context.getContentResolver().query(url,new String[] { "_id", "name", "age" }, null, null, "_id");while (cursor.moveToNext()) {// System.out.println("_id:"// + cursor.getInt(cursor.getColumnIndex("_id")));// System.out.println("name:"// + cursor.getString(cursor.getColumnIndex("name")));// System.out.println("age:"// + cursor.getInt(cursor.getColumnIndex("age")));Person person = new Person();person.setId(cursor.getInt(cursor.getColumnIndex("_id")));person.setName(cursor.getString(cursor.getColumnIndex("name")));person.setAge(cursor.getInt(cursor.getColumnIndex("age")));persons.add(person);}cursor.close();List<Map<String, Object>> data = new ArrayList<Map<String, Object>>();Map<String, Object> map=null;for (int i = 0; i < persons.size(); i++) {map = new HashMap<String, Object>();map.put("id", persons.get(i).getId());map.put("name", persons.get(i).getName());map.put("age", persons.get(i).getAge());data.add(map);}if (data.size()>=persons.size()) {}Message msg = handler.obtainMessage();msg.obj = data;handler.sendMessage(msg);}}}

 

ItemActivity代碼:

package com.jiahui.provider;import android.app.Activity;import android.content.ContentResolver;import android.content.ContentValues;import android.content.Intent;import android.net.Uri;import android.os.Bundle;import android.view.View;import android.widget.Button;import android.widget.EditText;import android.widget.TextView;import android.widget.Toast;public class ItemActivity extends Activity {private EditText edt_item_name;private EditText edt_item_age;private EditText edt_item_id;private Button btndel, btnupdate;private Intent intent;@Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);setContentView(R.layout.item);edt_item_id = (EditText) this.findViewById(R.id.edt_item_id);edt_item_id.setEnabled(false);// 控制不可用edt_item_name = (EditText) this.findViewById(R.id.edt_item_name);edt_item_age = (EditText) this.findViewById(R.id.edt_item_age);// 得到傳過來的資料btndel = (Button) this.findViewById(R.id.btndel);btnupdate = (Button) this.findViewById(R.id.btnupdate);intent = getIntent();Bundle bundle = intent.getBundleExtra("item");int id = bundle.getInt("id");System.out.println("id----" + id);String name = bundle.getString("name");int age = bundle.getInt("age");edt_item_id.setText(String.valueOf(id));edt_item_name.setText(name);edt_item_age.setText(String.valueOf(age));btndel.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {ContentResolver contentResolver = ItemActivity.this.getContentResolver();// 構建UriString url = "content://com.jiahui.provider.myprovider/person/"+ edt_item_id.getText();Uri uri = Uri.parse(url);int result = contentResolver.delete(uri, null, null);System.out.println("delete result:" + result);if (result >= 1) {Toast.makeText(ItemActivity.this, "刪除成功", Toast.LENGTH_LONG).show();ItemActivity.this.setResult(2);ItemActivity.this.finish();}}});btnupdate.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {ContentResolver contentResolver = ItemActivity.this.getContentResolver();// 構建UriString url = "content://com.jiahui.provider.myprovider/person/"+ edt_item_id.getText();Uri uri = Uri.parse(url);ContentValues values = new ContentValues();values.put("name", edt_item_name.getText().toString());values.put("age",Integer.parseInt(edt_item_age.getText().toString()));int result = contentResolver.update(uri, values, null, null);System.out.println("update result:" + result);if (result >= 1) {Toast.makeText(ItemActivity.this, "更新成功", Toast.LENGTH_LONG).show();ItemActivity.this.setResult(2);ItemActivity.this.finish();}}});}}

特別說明:這個例子也是與之前講過的一講與SQLite知識相關的代碼中一個類,讀者需要用到之前的DBHelper類,請自行拷貝。

如需轉載引用請註明出處:http://blog.csdn.net/jiahui524

原始碼下載:http://download.csdn.net/detail/jiahui524/3847893 

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.