ContentProvider 内容提供者 共享数据

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());
	             } }    	
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值