ContentProvider 在android中的作用是对外共享数据,也就是说你可以通过ContentProvider把应用中的数据共享给其他应用访问,其他应用可以通过ContentProvider 对你应用中的数据进行添删改查,当程序关闭的时候,其他程序一样可以操作共享数据,如果采用文件操作模式对外共享数据,数据的访问方式会因数据存储的方式而不同,导致数据的访问方式无法统一,使用ContentProvider对外共享数据的好处是统一了数据的访问方式。
1、配置AndroidManifest.xml 注册内容提供者
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- 清单文件会被android平台扫描访问,无论该应用是否启动,所以当该程序关闭之后
通过其他进程使用内容提供者还是能操作数据库或文件
-->
<!-- 注册内容提供者 -->
<provider
android:name=".PersonContentProvider"
android:authorities="com.zlz.androidpro.PersonContentProvider" />
</application>
2、定义一个ContentProviderr的实现类
package com.zlz.androidpro;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.net.Uri;
import android.util.Log;
public class PersonContentProvider extends ContentProvider {
private static final String AUTHORITY = "com.zlz.androidpro.PersonContentProvider";
private CustomerDao dao;
//uri匹配器,验证uri符合哪种uri形式,如果没一个匹配返回UriMatcher.NO_MATCH 即-1
private static UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
static{
// content://com.zlz.androidpro.PersonContentProvider/customers 匹配1
matcher.addURI(AUTHORITY, "customers", 1);
// content://com.zlz.androidpro.PersonContentProvider/customers/任意数 匹配2
matcher.addURI(AUTHORITY, "customers/#", 2);
}
public PersonContentProvider() {
super();
}
@Override
public boolean onCreate() {
//在onCreate 里面创建dao,这时this.getContext才能获取到context对象
this.dao = new CustomerDao(this.getContext());
return false;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
int res = matcher.match(uri);
//判断是否匹配1
if(res == 1){
long id = dao.insertCustomer(values);
//通知 观察者有人修改库了
this.getContext().getContentResolver().notifyChange(uri,null );
//需要将新插入的id附加在uri后,直接返回uri
return ContentUris.withAppendedId(uri, id);
}else{
Log.i("Other", "this uri is not invalid for insert");
}
return null;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
int res = matcher.match(uri);
//判断是否匹配1,查询全部
Cursor cursor = null;
if(res == 1){
cursor = dao.query(new String[] { "id,name,age" },null,null,null);
}else if(res == 2){//按照id查询
//将uri中的id解析出来
long id = ContentUris.parseId(uri);
cursor = dao.query(new String[] { "id,name,age" },"id = ?",new String[]{id+""},null);
}else{
Log.i("Other", "this uri is not invalid for query");
}
return cursor;
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
int res = matcher.match(uri);
//判断是否匹配2
if(res == 2){
long id = ContentUris.parseId(uri);
int val = dao.updateCustomer(values,"id = ?",new String[]{id+""});
//需要将新插入的id附加在uri后,直接返回uri
return val;
}else{
Log.i("Other", "this uri is not invalid for update");
}
//非法返回-1
return -1;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
int res = matcher.match(uri);
//判断是否匹配2
if(res == 2){
long id = ContentUris.parseId(uri);
int val = dao.delete("id = ?",new String[]{id+""});
//需要将新插入的id附加在uri后,直接返回uri
return val;
}else{
Log.i("Other", "this uri is not invalid for delete");
}
//非法返回-1
return -1;
}
@Override
public String getType(Uri uri) {
return null;
}
}
package com.zlz.androidpro;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
public class CustomerDao {
private DBHelper helper;
public CustomerDao(Context context) {
this.helper = new DBHelper(context);
}
// 添加
public long insertCustomer(ContentValues values) {
SQLiteDatabase db = helper.getWritableDatabase();
// values.put("name", c.name);
// values.put("age", c.age);
// db.close();
return db.insert("customers", null, values);
}
// 更新
public int updateCustomer(ContentValues values, String selection,
String[] selectionArgs) {
SQLiteDatabase db = helper.getWritableDatabase();
int update = db.update("customers", values, selection, selectionArgs);
// db.close();
return update;
}
// 查询
public Cursor query(String[] columns, String selection,
String[] selectionArgs, String sortOrder) {
SQLiteDatabase db = helper.getWritableDatabase();
Cursor cursor = db.query("customers", columns, selection,
selectionArgs, null, null, sortOrder);
return cursor;
}
// 删除
public int delete(String selection,
String[] selectionArgs) {
SQLiteDatabase db = helper.getWritableDatabase();
int delete = db.delete("customers", selection, selectionArgs);
// db.close();
return delete;
}
}
package com.zlz.androidpro;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
public class DBHelper extends SQLiteOpenHelper {
//将数据库名称申明
private static final String DB_NAME = "zlz.db";
private static final int VERSION = 1;
public DBHelper(Context context, String name, CursorFactory factory,
int version) {
//第三个参数CursorFactory指定在执行查询时获得一个游标实例的工厂类,设置为null,代表使用系统默认的工厂类
super(context, name, factory, version);
}
public DBHelper(Context context){
this(context, DB_NAME, null, VERSION);
}
//提供接受版本号的构造方法
public DBHelper(Context context,int version){
this(context, DB_NAME, null, version);
}
/**
* 首次创建库时使用
*/
@Override
public void onCreate(SQLiteDatabase db) {
String sql = "create table customers (id INTEGER primary key autoincrement, " +
"name varchar(20),age INTEGER)";
db.execSQL(sql);
}
/**
* 升级库时使用
*/
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL(" ALTER TABLE customers ADD phone VARCHAR(12) NULL "); //往表中增加一列
}
}
3、在activity里面模拟其他进程访问共享数据
package com.zlz.androidpro;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.EditText;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity implements OnClickListener {
EditText idText;
EditText nameText;
EditText ageText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
idText = (EditText) findViewById(R.id.etId);
nameText = (EditText) findViewById(R.id.etName);
ageText = (EditText) findViewById(R.id.etAge);
findViewById(R.id.insert).setOnClickListener(this);
findViewById(R.id.query).setOnClickListener(this);
findViewById(R.id.delete).setOnClickListener(this);
//注册内容观察者
registryMyContentProviderObserver();
}
/**
* 注册观察者,接收通知getContentResolver().notifyChange(uri,null )
*/
private void registryMyContentProviderObserver() {
String uristr = "content://com.zlz.androidpro.PersonContentProvider/customers";
Uri uri = Uri.parse(uristr);
//notifyForDescendents是否是开头一样就匹配?
this.getContentResolver().registerContentObserver(uri, false, new ContentObserver(new Handler()){
@Override
public void onChange(boolean selfChange) {
Toast.makeText(MainActivity.this, "有人操作数据库了", 3).show();
}
});
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.insert) {// 添加数据
// 获取内容解析器,和内容提供者配合使用
ContentResolver resolver = this.getContentResolver();
String uriStr = "content://com.zlz.androidpro.PersonContentProvider/customers";
// 将uri字符串编译为uri对象
Uri uri = Uri.parse(uriStr);
ContentValues values = new ContentValues();
values.put("name", nameText.getText().toString());
values.put("age", Integer.parseInt(ageText.getText().toString()));
resolver.insert(uri, values);
Toast.makeText(this, "添加数据成功", 1).show();
} else if (v.getId() == R.id.query) {// 查询
// 获取内容解析器,和内容提供者配合使用
ContentResolver resolver = this.getContentResolver();
String uriStr = "content://com.zlz.androidpro.PersonContentProvider/customers";
// 将uri字符串编译为uri对象
Uri uri = Uri.parse(uriStr);
Cursor cursor = resolver.query(uri, null, null, null, null);
toTalbe(cursor);
}
else if (v.getId() == R.id.delete) {// 删除
// 获取内容解析器,和内容提供者配合使用
ContentResolver resolver = this.getContentResolver();
String uriStr = "content://com.zlz.androidpro.PersonContentProvider/customers/"+idText.getText().toString();
// 将uri字符串编译为uri对象
Uri uri = Uri.parse(uriStr);
int val = resolver.delete(uri,null,null);
Toast.makeText(this, val == 1?"删除成功":"删除失败", 1).show();
}
}
private void toTalbe(Cursor cursor) {
TableLayout tl = (TableLayout) findViewById(R.id.tlLayout);
int childrenCount = tl.getChildCount();
// 防止每次查询重复添加,所以每次拼装为table时,除了表头,其他的全部干掉
for (int i = childrenCount - 1; i > 0; i--) {
View view = tl.getChildAt(i);
tl.removeView(view);
}
while (cursor.moveToNext()) {
TableRow row = new TableRow(this);
TextView idView = new TextView(this);
idView.setText(cursor.getString(cursor.getColumnIndex("id")));
row.addView(idView);
TextView nameView = new TextView(this);
nameView.setText(cursor.getString(cursor.getColumnIndex("name")));
row.addView(nameView);
TextView ageView = new TextView(this);
ageView.setText(cursor.getString(cursor.getColumnIndex("age")));
row.addView(ageView);
// 将每一行添加到table上
tl.addView(row);
}
}
}
如果ContentProvider的访问者需要知道ContentProvider中的数据发生了变化,可以在ContentProvider 发生数据变化时调用getContentResolver().notifyChange(uri, null)来通知注册在此URI上的访问者,例子如下:
public class PersonContentProvider extends ContentProvider {
public Uri insert(Uri uri, ContentValues values) {
db.insert("person", "personid", values);
getContext().getContentResolver().notifyChange(uri, null);
}
}
如果ContentProvider的访问者需要得到数据变化通知,必须使用ContentObserver对数据(数据采用uri描述)进行监听,当监听到数据变化通知时,系统就会调用ContentObserver的onChange()方法:
getContentResolver().registerContentObserver(Uri.parse("content://cn.itcast.providers.personprovider/person"),
true, new PersonObserver(new Handler()));
public class PersonObserver extends ContentObserver{
public PersonObserver(Handler handler) {
super(handler);
}
public void onChange(boolean selfChange) {
//此处可以进行相应的业务处理
}
}
用户使用系统自带的短信程序发送短信,程序会通过ContentProvider把短信保存进数据库,并且发出一个数据变化通知,使用ContentObserver对数据变化进行监听,在用户发送短信时,就会被ContentObserver窃听到短信:
注册监听:
getContentResolver().registerContentObserver(Uri.parse("content://sms"), true, new SmsObserver(new Handler()));
//监听类:
private final class SmsObserver extends ContentObserver{
public SmsObserver(Handler handler) {
super(handler);
}
public void onChange(boolean selfChange) {//查询发送箱中的短信(处于正在发送状态的短信放在发送箱)
Cursor cursor = getContentResolver().query(Uri.parse("content://sms"),null, null, null, null);
while(cursor.moveToNext()){
StringBuilder sb = new StringBuilder();
sb.append("_id=").append(cursor.getInt(cursor.getColumnIndex("_id")));
sb.append(",address=").append(cursor.getString(cursor.getColumnIndex("address")));
sb.append(";body=").append(cursor.getString(cursor.getColumnIndex("body")));
sb.append(";time=").append(cursor.getLong(cursor.getColumnIndex("date")));
Log.i("ReceiveSendSMS", sb.toString());
} }
}