Android四大组件之ContentProvider:诞生缘由,ContentProvider内容提供者,ContentResolver内容解析器

简介

诞生缘由

功能需求: 一个应用需要访问另一个应用的数据库表数据
实际情况: 一个应用的数据库文件是应用私有的, 其它应用不能直接访问
比如最直观的的手机联系人和短信两个应用:
	很多时候我们发短信,接收者不是我们自己输入的,而是从联系人里面进行读取的
	但是这样就出现问题了,联系人里面的数据是私有的,其他的应用是无法读取的
	但是这样的功能又是经常性的需求,所以Android就在联系人这个应用里面
	增加一个ContentProvider组件,这个组件暴露接口提供其他的应用访问
	然后其他的应用就使用ContentResolver来调用ContentProvider提供的接口方法
	来访问其他应用的数据
ContentProvider是四大应用组件之一
当前应用使用ContentProvider将数据库表数据操作暴露给其它应用访问
其它应用需要使用ContentResolver来调用ContentProvider的方法
它们之间的调用是通过Uri来进行交流的

API

ContentProvider  : 内容提供者类

//provider对象创建后调用(应用安装成功或手机启动完成)
public abstract boolean onCreate();

//查询表数据
Cursor query(Uri uri, String[] projection,String selection, String[] selectionArgs)

//插入表数据
Uri insert(Uri uri, ContentValues values);

//删除表数据
int delete(Uri uri, String selection, String[] selectionArgs)

//更新表数据
update(Uri uri, ContentValues values, String selection,String[] selectionArgs);
ContentResolver:  内容提供者的解析类

//得到它的对象
context.getContentResolver() 

//调用provider进行数据库CRUD操作
Insert()、delete()、update()、query()

//注册uri的监听
registerContentObserver(Uri uri, boolean notify,ContentObserver observer)

//解注册uri的监听
unregisterContentObserver(ContentObserver observer)

//通知监听器
notifyChange(Uri uri, ContentObserver observer)
Uri: 包含请求地址数据的类

//得到这个对象
Uri static parse(String uriString)

注意这个uriString的格式:
	<standard_prefix>://<authority>/<data_path>/<id>
	<standard_prefix>://
	<authority>
	<data_path>
	<id>
	分别对应四部分
	<standard_prefix>://
			是一个前缀,表示是由ContentProvider提供,固定不变  content://
	<authority>
			authority, 标识是哪个Provider,不同的Provider此部分必须不同。就是Provider全类名
	<data_path>
			对应于哪张表
	<id>
			id值, 对应表中的哪条记录
这些是工具类:
UriMatcher : 用于匹配Uri的容器
		//添加一个合法的URI
		void addURI(String authority, String path, int code) 
		
		//匹配指定的uri, 返回匹配码
		int match(Uri uri) 
	上面两个方法,比如实际情况,A想向B访问数据,传过来一个uri
	但是B接收到A传过来的uri不一定是合法的,所以B先自己添加
	一些合法的uri,后面的code就是合法uri的标识,然后利用match进行匹配
	如果是合法的uri就会匹配成功,返回合法uri的标识code
	
ContentUris : 解析uri的工具类

		//解析uri, 得到其中的id
		long parseId(Uri contentUri) 
		
		//添加id到指定的uri中
		Uri withAppendedId(Uri contentUri, long id) 

例子

ContentProvider

前期准备好数据
package com.jane.provider;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

public class DBHelper extends SQLiteOpenHelper
{

	public DBHelper(Context context)
	{
		super(context, "atguigu.db", null, 1);
	}

	@Override
	public void onCreate(SQLiteDatabase db)
	{
		Log.e("TAG", "onCreate()...");
		// 建表
		db.execSQL("create table person(_id integer primary key autoincrement, name varchar)");
		// 插入初始化数据
		db.execSQL("insert into person (name) values ('Tom')");
	}

	@Override
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
	{

	}

}

编写ContentProvider子类
package com.jane.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 android.util.Log;

/**
 * 操作person表的provider类
 */
public class PersonProvider extends ContentProvider
{
	// 用来存放所有合法的Uri的容器
	private static UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
	// 保存一些合法的uri
	// content://com.jane.provider.personprovider/person 不根据id操作
	// content://com.jane.provider.personprovider/person/3 根据id操作
	static
	{
		matcher.addURI("com.jane.provider.personprovider", "/person", 1);
		matcher.addURI("com.jane.provider.personprovider", "/person/#",2); // #匹配任意数字
	}
	private DBHelper dbHelper;

	public PersonProvider()
	{
		Log.e("TAG", "PersonProvider()");
	}

	@Override
	public boolean onCreate()
	{
		Log.e("TAG", "PersonProvider onCreate()");
		dbHelper = new DBHelper(getContext());
		return false;
	}

	/**
	 * content://com.jane.provider.personprovider/person 不根据id查询
	 * content://com.jane.provider.personprovider/person/3 根据id查询
	 */
	@Override
	public Cursor query(Uri uri, String[] projection, String selection,String[] selectionArgs, String sortOrder)
	{
		Log.e("TAG", "PersonProvider query()");

		// 得到连接对象
		SQLiteDatabase database = dbHelper.getReadableDatabase();

		// 1.匹配uri, 返回code
		int code = matcher.match(uri);
		// 如果合法, 进行查询
		if (code == 1)
		{// 不根据id查询
			Cursor cursor = database.query("person", projection, selection,selectionArgs, null, null, null);
			return cursor;
		} else if (code == 2)
		{// 根据id查询
			// 得到id
			long id = ContentUris.parseId(uri);
			// 查询
			Cursor cursor = database.query("person", projection, "_id=?",new String[]{ id + "" }, null, null, null);
			return cursor;
		} else
		{// 如果不合法, 抛出异常
			throw new RuntimeException("查询的uri不合法");
		}
	}

	/**
	 * content://com.jane.provider.personprovider/person 插入
	 * content://com.jane.provider.personprovider/person/3 根据id插入(没有)
	 */
	@Override
	public Uri insert(Uri uri, ContentValues values)
	{
		Log.e("TAG", "PersonProvider insert()");
		// 得到连接对象
		SQLiteDatabase database = dbHelper.getReadableDatabase();
		// 匹配uri, 返回code
		int code = matcher.match(uri);
		// 如果合法, 进行插入
		if (code == 1)
		{
			long id = database.insert("person", null, values);
			// 将id添加到uri中
			uri = ContentUris.withAppendedId(uri, id);
			database.close();
			return uri;
		} else
		{
			// 如果不合法, 抛出异常
			database.close();
			throw new RuntimeException("插入的uri不合法");
		}
	}

	/**
	 * content://com.jane.provider.personprovider/person 不根据id删除
	 * content://com.jane.provider.personprovider/person/3 根据id删除
	 */
	@Override
	public int delete(Uri uri, String selection, String[] selectionArgs)
	{
		Log.e("TAG", "PersonProvider delete()");
		// 得到连接对象
		SQLiteDatabase database = dbHelper.getReadableDatabase();
		// 匹配uri, 返回code
		int code = matcher.match(uri);
		int deleteCount = -1;
		// 如果合法, 进行删除
		if (code == 1)
		{
			deleteCount = database.delete("person", selection, selectionArgs);
		} else if (code == 2)
		{
			long id = ContentUris.parseId(uri);
			deleteCount = database.delete("person", "_id=" + id, null);
		} else
		{
			// 如果不合法, 抛出异常
			database.close();
			throw new RuntimeException("删除的uri不合法");
		}

		database.close();
		return deleteCount;
	}

	/**
	 * content://com.jane.provider.personprovider/person 不根据id更新
	 * content://com.jane.provider.personprovider/person/3 根据id更新
	 */
	@Override
	public int update(Uri uri, ContentValues values, String selection,String[] selectionArgs)
	{
		Log.e("TAG", "PersonProvider update()");
		// 得到连接对象
		SQLiteDatabase database = dbHelper.getReadableDatabase();
		// 匹配uri, 返回code
		int code = matcher.match(uri);
		int updateCount = -1;
		// 如果合法, 进行更新
		if (code == 1)
		{
			updateCount = database.update("person", values, selection,
					selectionArgs);
		} else if (code == 2)
		{
			long id = ContentUris.parseId(uri);
			updateCount = database.update("person", values, "_id=" + id, null);
		} else
		{
			// 如果不合法, 抛出异常
			database.close();
			throw new RuntimeException("更新的uri不合法");
		}

		database.close();
		return updateCount;
	}

	@Override
	public String getType(Uri uri)
	{
		return null;
	}
}
然后将ContentProvider注册到文件清单里面
      <provider
          android:name="com.jane.provider.PersonProvider"
          android:authorities="com.jane.provider.personprovider"
          android:exported="true" />
      <!-- 
      	android:exported : 是否可以让其它应用访问
      	android:authorities是给这个内容提供者一个唯一的标识	
       -->
注意:
第一次调用getWritableDatabase()或getReadableDatabase()方法后,
SQLiteOpenHelper会缓存当前的SQLiteDatabase实例,
SQLiteDatabase实例正常情况下会维持数据库的打开状态,
所以在你不再需要SQLiteDatabase实例时,请及时调用close()方法释放资源。
一旦SQLiteDatabase实例被缓存,
多次调用getWritableDatabase()或getReadableDatabase()方法得到的都是同一实例。

ContentResolver

package com.jane.resolver;

import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

public class MainActivity extends Activity
{
	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
	}

	/*
	 * 通过ContentResolver调用ContentProvider插入一条记录
	 */
	public void insert(View v)
	{
		// 1. 得到ContentResolver对象
		ContentResolver resolver = getContentResolver();
		// 2. 调用其insert
		Uri uri = Uri.parse("content://com.jane.provider.personprovider/person");
		// uri =
		// Uri.parse("content://com.jane.provider.personprovider/person/3");
		ContentValues values = new ContentValues();
		values.put("name", "JACK");
		uri = resolver.insert(uri, values);

		Toast.makeText(this, uri.toString(), 1).show();
	}

	/*
	 * 通过ContentResolver调用ContentProvider更新一条记录
	 */
	public void update(View v)
	{
		// 1. 得到ContentResolver对象
		ContentResolver resolver = getContentResolver();
		// 2. 执行update
		Uri uri = Uri.parse("content://com.jane.provider.personprovider/person/2");
		ContentValues values = new ContentValues();
		values.put("name", "JACK2");
		int updateCount = resolver.update(uri, values, null, null);

		Toast.makeText(this, "updateCount=" + updateCount, 1).show();
	}

	/*
	 * 通过ContentResolver调用ContentProvider删除一条记录
	 */
	public void delete(View v)
	{
		// 1. 得到ContentResolver对象
		ContentResolver resolver = getContentResolver();
		// 2. 执行delete
		Uri uri = Uri.parse("content://com.jane.provider.personprovider/person/2");
		int deleteCount = resolver.delete(uri, null, null);
		Toast.makeText(this, "deleteCount=" + deleteCount, 1).show();
	}

	/*
	 * 通过ContentResolver调用ContentProvider查询所有记录
	 */
	public void query(View v)
	{
		// 1. 得到ContentResolver对象
		ContentResolver resolver = getContentResolver();
		// 2. 调用其query, 得到cursor
		Uri uri = Uri.parse("content://com.jane.provider.personprovider/person/1");
		uri = Uri.parse("content://com.jane.provider.personprovider/person");
		Cursor cusor = resolver.query(uri, null, null, null, null);
		// 3. 取出cursor中的数据, 并显示
		while (cusor.moveToNext())
		{
			int id = cusor.getInt(0);
			String name = cusor.getString(1);
			Toast.makeText(this, id + " : " + name, 1).show();
		}
		cusor.close();
	}
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ReflectMirroring

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值