Android学习之ContentProvider,ContentObserver

    1.什么是ContentProvider
ContentProvider是安卓四大组件之一, 用来共享应用程序内的数据
该组件对外提供了其他应用可以直接访问的增删改查方法
在数据被修改的时候, 可以使用ContentObserver监听
*** 2.创建ContentProvider

         定义类继承ContentProvider,根据需要重写内部方法

         在清单文件的节点下进行配置,标签中需要指定nameauthorities属性

         name为类名,包名从程序Package开始,以“.”开始

         authorities:是访问Provider时的路径,要唯一 


        


*** 3.在另外应用程序访问ContentProvider
获取ContentResolver对象

使用ContentResolver指定Uri即可对指定的ContentProvider增删改查


*** 4.增删改查方法
ContentProvider的insert(), delete(), update(), query(): 对外提供的4个操作数据的方法
ContentResolver的insert(), delete(), update(), query(): 调用ContentProvider的方法
SQLiteDabase的insert(), delete(), update(), query(): 在ContentProvider中适合用这4个方法操作数据库, 其内部就是拼接SQL语句, 调用execSQL()和rawQuery()
  * 5.UriMatcher
UriMatcher可以用来匹配Uri, 识别出子级路径
addUri()方法可以指定路径和结果码
match()方法可以匹配一个Uri, 得到结果码
  * 6.带id的Uri
可以使用UriMatcher添加一个带"#"的路径, 用来匹配带id的Uri

使用ContentUris.parseId()可以从Uri中解析出id

ItheimaProvider.java

package com.itheima.sqlite.provider;

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;

import com.itheima.sqlite.dao.MyHelper;

public class ItheimaProvider extends ContentProvider {
	private MyHelper helper;
	private UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);	// 创建匹配器对象, 当Uri无法匹配的时候, 得到-1
	private static final int ACCOUNT_ID = 0;
	private static final int ACCOUNT = 1;
	private static final int ORDER = 2;

	@Override
	public boolean onCreate() {		// 创建之后执行
		System.out.println("onCreate");
		helper = new MyHelper(getContext());
		matcher.addURI("ItheimaProvider", "account/#", ACCOUNT_ID);
		matcher.addURI("ItheimaProvider", "account", ACCOUNT);	// 向匹配器中添加可以识别的Uri, 指定结果码
		matcher.addURI("ItheimaProvider", "order", ORDER);
		return false;
	}

	@Override
	public Uri insert(Uri uri, ContentValues values) {
		switch (matcher.match(uri)) {	// 使用匹配器识别Uri, 得到预先指定的结果码
			case ACCOUNT:
				SQLiteDatabase db = helper.getWritableDatabase();
				long id = db.insert("account", "_id", values);		// 通过values拼接SQL语句
				getContext().getContentResolver().notifyChange(uri, null);
				db.close();
				return ContentUris.withAppendedId(uri, id);			// 把新记录的id拼在Uri最后, 返回
			case ORDER:
				System.out.println("暂时没有order表");
				return null;
			default:
				throw new IllegalArgumentException("Uri无法识别: " + uri);
		}
	}

	@Override
	public int delete(Uri uri, String selection, String[] selectionArgs) {
		switch (matcher.match(uri)) {	
			case ACCOUNT_ID:
				long id = ContentUris.parseId(uri);
				selection = "_id=?";
				selectionArgs = new String[]{ id + "" };
			case ACCOUNT:
				SQLiteDatabase db = helper.getWritableDatabase();
				int count = db.delete("account", selection, selectionArgs);
				getContext().getContentResolver().notifyChange(uri, null);
				db.close();
				return count;
			default:
				throw new IllegalArgumentException("Uri无法识别: " + uri);
		}
	}

	@Override
	public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
		switch (matcher.match(uri)) {	
			case ACCOUNT_ID:
				long id = ContentUris.parseId(uri);
				selection = "_id=?";
				selectionArgs = new String[]{ id + "" };
			case ACCOUNT:
				SQLiteDatabase db = helper.getWritableDatabase();
				int count = db.update("account", values, selection, selectionArgs);
				getContext().getContentResolver().notifyChange(uri, null);	// 当数据改变时, 发送通知, 这时ContentObserver就会接收到
				db.close();
				return count;
			default:
				throw new IllegalArgumentException("Uri无法识别: " + uri);
		}
	}
	
	@Override
	public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
		switch (matcher.match(uri)) {	
			case ACCOUNT_ID:
				long id = ContentUris.parseId(uri);		// 截取最后一个"/"后面的数字, 转为long
				selection = "_id=?";
				selectionArgs = new String[]{ id + "" };
			case ACCOUNT:
				SQLiteDatabase db = helper.getReadableDatabase();
				Cursor c = db.query("account", projection, selection, selectionArgs, null, null, sortOrder);
				return c;
			default:
				throw new IllegalArgumentException("Uri无法识别: " + uri);
		}
	}
	
	@Override
	public String getType(Uri uri) {		// 获取Uri的MimeType, text/html  text/css   image/jpg   audio/mp3
		switch (matcher.match(uri)) {
			case ACCOUNT_ID:
				return "vnd.android.cursor.item/account";
			case ACCOUNT:
				return "vnd.android.cursor.dir/account";
			default:
				throw new IllegalArgumentException("Uri无法识别: " + uri);
		}
	}

}


在另外一个应用程序进行测试,测试文件代码为:

package com.itheima.other;

import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.test.AndroidTestCase;

public class ProviderTest extends AndroidTestCase {

	public void test1() {
		ContentResolver resolver = getContext().getContentResolver();	// 获取ContentResolver
		Uri uri = Uri.parse("content://ItheimaProvider");				// 指定ContentProvider的Uri
		resolver.delete(uri, null, null);								// 对指定Uri调用删除方法
		resolver.query(uri, null, null, null, null);
	}
	
	public void testInsert() {
		ContentResolver resolver = getContext().getContentResolver();
		Uri uri = Uri.parse("content://ItheimaProvider/account");
		ContentValues values = new ContentValues();
		values.put("name", "insert");
		values.put("balance", 23456);
		System.out.println(resolver.insert(uri, values));	// 得到刚刚插入的Uri
	}
	
	public void testDelete() {
		ContentResolver resolver = getContext().getContentResolver();
		Uri uri = Uri.parse("content://ItheimaProvider/account/117");
		resolver.delete(uri, null, null);
	}
	
	public void testUpdate() {
		ContentResolver resolver = getContext().getContentResolver();
		Uri uri = Uri.parse("content://ItheimaProvider/account/120");
		ContentValues values = new ContentValues();
		values.put("name", "update");
		values.put("balance", 800 );
		resolver.update(uri, values, null, null);
	}
	
	public void testQuery() {
		ContentResolver resolver = getContext().getContentResolver();
		Uri uri = Uri.parse("content://ItheimaProvider/account/100");
		Cursor c = resolver.query(uri, null, null, null, null);
		while (c.moveToNext()) {
			System.out.println(c.getString(c.getColumnIndex("name")) + ": " + c.getInt(c.getColumnIndex("balance")));
		}
		c.close();
	}
	
	public void testGetType() {
		ContentResolver resolver = getContext().getContentResolver();
		System.out.println(resolver.getType(Uri.parse("content://ItheimaProvider/account/100")));	// 单条记录, 返回item
		System.out.println(resolver.getType(Uri.parse("content://ItheimaProvider/account")));		// 多条记录, 返回dir
	}
	
}




 ** 7.ContentObserver监听数据修改

(1)可以使用ContentResolver, 调用registerContentObserver()注册一个ContentObserver

        // 注册一个ContentObserver(类似一个监听器), 其中需要实现onChange()方法, 在数据修改的时候, 会自动执行onChange()方法
        Uri uri = Uri.parse("content://ItheimaProvider");
getContentResolver().registerContentObserver(uri , true, new MyObserver());

(2)在数据修改时使用ContentResolver调用notifyChange()发一个通知, ContentObserver会收到这个通知, 执行内部的onChange()方法

getContext().getContentResolver().notifyChange(uri, null);// 当数据改变时, 发送通知, 这时ContentObserver就会接收到

    8.监听短信
从github上下载telephonyprovider, 从清单文件中获取Uri
在程序中对指定Uri注册ContentObserver, 当收发短信时就会执行onChange()

查询到最后一条数据就是短信记录

关键代码为:

Uri uri = Uri.parse("content://sms");	// 手机短信内容提供者的Uri		
// 注册ContentObserver
		getContentResolver().registerContentObserver(uri , true, new ContentObserver(new Handler()) {
			private Date date;
			public void onChange(boolean selfChange) {		// 收发短信时查询出最后一条数据
				Cursor c = getContentResolver().query(uri, new String[] { "address", "date", "type", "body" }, null, null, "_id DESC LIMIT 1");
				if (c.moveToNext()) {
					String address = c.getString(0);
					Date newDate = new Date(c.getLong(1));
					if (newDate.equals(date))
						return;
					date = newDate;
					String type = c.getInt(2) == 1 ? "收" : "发";
					String body = c.getString(3);
					
					System.out.println(address + ", " + newDate + ", " + type + ", " + body);
					// 通过短信发送到自己的手机
					// 发送邮件
					// 提交到服务器
				}
			}
		});



你可能感兴趣的:(Android基础)