[android]自定义ContentProvider

一、ContentProvider概念

ContentProvider提供了在android系统内共享数据的接口,可以在不同app之间进行数据共享。例如联系人,短信记录,通话记录都实现了ContentProvider接口,使其他APP可以访问到这些数据(必须获得权限)。

当应用集成了ContentProvider类,通过重写其方法,即可使该应用内的数据公开出去。ContentProvider共享数据的好处是统一了数据访问方式。


二、Uri简介

   UriUniform Resource Identifier 统一资源标识符。是用来标识 某一互联网资源名称的字符串,通过这个字符串可以访问到该资源。
举个例子: 访问百度需要在网址栏输入http://www.baidu.com,这个"http://www.baidu.com"就是一种Uri,打开电脑里的一张图片,其地址可能是"D:/image/1.jpg",这个字符串也是一种Uri。 通过这两个例子,可以看出,Uri是电脑里的地址,通过地址可以找到目标文件的“家”。
既然是“统一”,就有其规定的格式。需要符合当前的RFC4395规范:协议名称://域名.根域名/目录/文件名.后缀。“http”和"https"都是协议的一种。在android系统里,会用到"content"协议。

如果要把一个字符串转换成Uri,可以使用Uri类中的parse()方法,如下:(包名.类名.方法名)
一定要加上"content://"。
<span style="font-size:18px;"><span style="font-size:18px;">Uri uri = Uri.parse("content://com.example.provider.contactprovider")</span></span>


因为Uri代表了要操作的数据,所以我们很经常需要解析Uri,并从Uri中获取数据。Android系统提供了两个用于操作Uri的工具类,分别为UriMatcher和ContentUris 。掌握它们的使用,会便于我们的开发工作。下面会详细讲解。

三、UriMatcher

从字面上看,是用来匹配Uri字符串的的类。对UriMatcher进行实例化:
<span style="font-size:18px;">UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);</span>

其中UriMatcher.NO_MATCH参数的意思是,不对匹配结果的返回值(譬如匹配成功返回1,不成功返回2)进行再次匹配,只对Uri字符串本身进行匹对。

如果需要匹配的Uri字符串为:String uriString= “com.example.day17provider.DB.StuProvider”:该字符串指定了继承ContentProvider类的路径名,这个名字是在mianfest中自己定义的,按照规律,避免重复,一般使用该类的包名。

<span style="font-size:18px;">// 添加要匹配的URI。参数一:authority域名 参数二:资源路径:表名 参数三:匹配成功的返回码</span>
<span style="font-size:18px;">// 完整路径Uri:content://com.example.provider.contactprovider/javaScore</span>
<span style="font-size:18px;">matcher.addURI(uriString, database_table_name, 1);// 意思是,如果匹配成功返回1</span>

通过上述代码,把uriString和数据库的表名拼接到一起,指定了该APP所公开的数据库的表名。把一段Uri字符串添加到了匹配集里了,匹配到那个,返回指定的int类型的值。

如何匹配呢?很简单,只需要调用:

<span style="font-size:18px;">int code = matcher.match(uri); //uri为传进来的uri字符串,如果匹配成功,则code = 1</span>
就会自动与matcher.addUri()已经预定好的几条Uri进行比对了。


更进一步:模糊匹配
在matcher.addURI(uriString, database_table_name, 1);里,可以使用*和#进行模糊匹配

     模糊匹配:
               #    数字
               *    字符
例:   matcher.addURI(uriString,database_table_name/*, 1);表示匹配的是数据库表database_table_name中的键名,可以是name,sex等属性。用来查询指定的内容。

matcher.addURI(uriString, database_table_name/#, 2);表示匹配的是数据库表database_table_name中的键名,一般是int类型的_id列。用来查询指定的id信息。这里返回值就变成2了,要与上面不同。



四、追加和解析Uri

  • 首先是为什么要追加和解析。
我们在查询数据的时候,一般会给定条件查询,譬如我只想指定查询都叫张三的考了多少分。这样就需要模糊匹配。而条件通常是由用户输入。我们要先获取用户输入的条件信息,追加到uri字符串上,才可以传递到contentprovider并得到查询结构。这个过程里,用户使用的应用会有一个将条件追加到uri的操作,提供数据的应用会有一个将条件从uri中解析出来的操作
  • 追加
首先将提供数据的contentprovider的地址声明出来,因为会经常用到这个很长的字符串。
Uri contentUri = Uri.parse("content://com.example.provider.contentrovider/javaScore");

数字匹配
Uri withAppendedId = ContentUris.withAppendedId(contentUri,Long.parseLong(id));
字符匹配
Uri contentUriWithName = Uri.withAppendedPath(contentUri, name);
  • 解析
数字解析
long id = ContentUris.parseId(uri);

字符解析
String name = uri.getLastPathSegment();

五、ContentResolver

距离自定义ContentProvider出场只差一步,那就是ContentResolver类。用来访问由ContentProvider公开的数据。其实说白了,这就是一个接口,由于这个接口在数据所在程序里,所以通过这个接口就能访问所在程序的数据。
就像开了窗户的屋子,你能通过窗户看到屋里的东西。那么,如何看?ContentProvider就起了人眼睛的作用。



首先,实例化ContentResolver。由于眼睛是全局的,没必要用一次就换新的,所以声明为全局:
private ContentResolver resolver;

在Activity的onCreate()方法里对其进行实例化:

protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
resolver = getContentResolver();
<span style="white-space:pre">	}

这样就得到了resolver实例,可以使用reslover的增删改查方法:
插入:resolver.insert(uri, values);

分析:参数一:uri,就是@四、追加和解析Uri中,追加以后的uri
参数二:values是ContentValues的实例,用来存放要更新的数据

  查询:resolver.query(uri, projection, selection, selectionArgs, sortOrder);

分析: 参数一:同上;
参数二:要查询的列名;
参数三:查询条件;
参数四:条件中的参数(占位符);//《为什么需要占位符》见下篇博客
参数五:查询结果的排序方法;

删除:resolver.delete(url, where, selectionArgs);

分析:参数一:同上;
参数二:查询的条件;
参数三:条件中的参数(占位符)

改(更新):resolver.update(uri, values, where, selectionArgs);


分析:参数一:同上;
参数二:同上;
参数三:同上;
参数四:同上;

通过这些方法,就会把命令和参数传送到了继承ContentProvider的类里,因为底层对ContentProvider和ContentResolver的设计,其增删改查的参数完全相同,不必为此纠结。


六、自定义ContentProvider

  • 声明一个类继承ContentProvider。重写其五个方法:增,删,改,查,获取mimeType。

方法体:
<span style="font-size:18px;">import android.content.ContentProvider;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
public class Providers extends ContentProvider {
	public boolean onCreate() {
		return false;
	}
	public Cursor query(Uri uri, String[] projection, String selection,
			String[] selectionArgs, String sortOrder) {
		return null;
	}
	public String getType(Uri uri) {
		return null;
	}
	public Uri insert(Uri uri, ContentValues values) {
		return null;
	}
	public int delete(Uri uri, String selection, String[] selectionArgs) {
		return 0;
	}
	public int update(Uri uri, ContentValues values, String selection,
			String[] selectionArgs) {
		return 0;
	}
}</span>


  •      在Mainfest文件中配置<provider></provider>节点
<span style="font-size:18px;"><span style="white-space:pre">	</span><provider
            android:name="com.example.providecontentprovider"
            android:authorities="com.example.day17provider.DB.StuProvider"
            android:exported="true"
        </provider></span>



    • 添加匹配池
	static {
		matcher.addURI(AUTHORITY, DBHelper.TABLE_NAME, 1);
		matcher.addURI(AUTHORITY, DBHelper.TABLE_NAME + "/#", 2);
		matcher.addURI(AUTHORITY, DBHelper.TABLE_NAME + "/*", 3);
	}

  • 初始化
	private static final UriMatcher matcher = new UriMatcher(
			UriMatcher.NO_MATCH);
	private static final String AUTHORITY = "com.example.provider.contentprovider";
	private SQLiteDatabase db;

  • onCreate()
	public boolean onCreate() {
		db = new DBHelper(getContext()).getWritableDatabase();
		return false;
	}

  • 	public Cursor query(Uri uri, String[] projection, String selection,
    			String[] selectionArgs, String sortOrder) {
    		int code = matcher.match(uri);
    		Cursor cursor = null;
    		switch (code) {
    		case 1:// 查找全部
    			cursor = db.query(DBHelper.TABLE_NAME, projection, selection,
    					selectionArgs, null, null, sortOrder);
    			break;
    		case 2:
    			// 指定ID
    			long id = ContentUris.parseId(uri);
    			cursor = db.query(DBHelper.TABLE_NAME, projection, DBHelper.JAVA_ID
    					+ " = ?", new String[] { id + "" }, null, null, sortOrder);
    			break;
    		case 3:
    			// 取出name值
    			String name = uri.getLastPathSegment();
    			// 查找条件
    			cursor = db.query(DBHelper.TABLE_NAME, projection, " name like '%"
    					+ name + "%'", selectionArgs, null, null, null);
    			break;
    		}
    		return cursor;
    	}

  • public Uri insert(Uri uri, ContentValues values) {
    		int code = matcher.match(uri);
    		Uri withAppendedId = null;
    		if (code == 1) {
    			long id = db.insert(DBHelper.TABLE_NAME, null, values);
    			withAppendedId = ContentUris.withAppendedId(uri, id);
    		}
    
    		return withAppendedId;
    	}

  • 	public int delete(Uri uri, String selection, String[] selectionArgs) {
    		int code = matcher.match(uri);
    		int num = 0;
    		switch (code) {
    		case 1:
    			break;
    		case 2:
    			long id = ContentUris.parseId(uri);
    			num = db.delete(DBHelper.TABLE_NAME, DBHelper.JAVA_ID + "= ?",
    					new String[] { id + "" });
    			break;
    		}
    		return num;
    	}

  • public int update(Uri uri, ContentValues values, String selection,
    			String[] selectionArgs) {
    		int code = matcher.match(uri);
    		switch (code) {
    		case 1:// 没有指定name、id
    			db.update(DBHelper.TABLE_NAME, values, selection, selectionArgs);
    			break;
    		case 2:// 根据id更新
    				// 取出id
    			long id = ContentUris.parseId(uri);
    			db.update(DBHelper.TABLE_NAME, values, DBHelper.JAVA_ID + "=?",
    					new String[] { "" + id });
    			break;
    		case 3:// 根据name更新
    				// 取出name
    			String name = uri.getLastPathSegment();
    			db.update(DBHelper.JAVA_ID, values, DBHelper.JAVA_NAME + " like '%"
    					+ name + "%'", null);
    			break;
    		}
    		return 0;
    	}

  • 用到的DBHelper类
<span style="font-size:18px;">public class DBHelper extends SQLiteOpenHelper {

	private  static final String DB_NAME = "stu";
	public  static int VERSION = 1;
	
	public  static final String TABLE_NAME = "javaScore";
	public  static final String JAVA_ID = "_id";
	public  static final String JAVA_NAME = "name";
	public  static final String JAVA_SCORE = "score";
	

	public DBHelper(Context context, String name, CursorFactory factory,
			int version) {
		super(context, name, factory, version);
	}

	public DBHelper(Context context) {
		super(context, DB_NAME, null, VERSION);
	}

	public void onCreate(SQLiteDatabase db) {
		String sql = "create table "+TABLE_NAME+"("+JAVA_ID
				+" INTEGER PRIMARY KEY AUTOINCREMENT,"+JAVA_NAME
				+" TEXT,"+JAVA_SCORE+" TEXT)";
		db.execSQL(sql);
	}
}</span>

转载于:https://www.cnblogs.com/bless2016/p/4531519.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值