在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);
}
@Override
public boolean onCreate() {
System.out.println("---oncreate----");
dbHelper = new DBHelper(this.getContext());
return false;
}
// 查詢數據
@Override
public 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這個工具類解釋出ID
long 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
@Override
public 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());
}
}
// 插入數據
@Override
public 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;
}
// 刪除數據
@Override
public 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());
}
}
// 更新數據
@Override
public 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工具類得到ID
long 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() {
@Override
public 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() {
@Override
public 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() {
@Override
public void onClick(View v) {
MyThread thread = new MyThread(ContentProviderDemoActivity.this);
thread.start();
}
});
lvall.setOnItemClickListener(new OnItemClickListener() {
@Override
public 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);
}
});
}
@Override
protected 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;
}
@Override
public 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;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.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() {
@Override
public void onClick(View v) {
ContentResolver contentResolver = ItemActivity.this
.getContentResolver();
// 構建Uri
String 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() {
@Override
public void onClick(View v) {
ContentResolver contentResolver = ItemActivity.this
.getContentResolver();
// 構建Uri
String 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