Android四大组件(ContentProvider篇)
来源:互联网 发布:linux 文件共享服务器 编辑:程序博客网 时间:2024/06/07 12:33
什么是ContentProvider
ContentProvider,是自身APP开放给第三方APP的,用于访问自身数据库数据的接口。
第三方APP可以通过该接口,对指定的数据进行增删改查。
那么如何定义自身的ContentProvider接口呢?
在回答问题之前,先来关注一下Uri。
什么是Uri
原因在于,uri是ContentProvider解析外部请求(或者说是,第三方访问自身数据库)的关键参数。
Uri的字符串格式如下
content://package/table/id
例如
content://com.breakloop.sqlitehelperdemo/hero/1
从上方Uri示例中,可以获取到以下信息。
第三方APP想要
(1)访问com.breakloop.sqlitehelperdemo的数据库。至于哪个,由contentProvider内部映射指定。
(2)访问表hero。至于表名是不是真为hero,也由contentProvider说了算。
(3)访问id为1的数据。至于是不是id代表的具体含义,解释权也归contentProvider。
那么,第三方APP将Uri传入后,ContentProvider如何将其map为具体的数据库操作呢?
这便有了UriMatcher工具类的引入。
UriMatcher
该工具类,可以将Uri映射为int类型的行为代码。行为代码,可以看做是ContentProvider自定义的枚举类型。而不同的行为代码,绑定不同的数据库操作。
我们先来看一下,Uri与行为代码的映射关系
public class MatcherConst { public final static String AUTHORITY="com.breakloop.contentproviderdemo1"; public final static int BY_NAME=1; public final static int BY_AGE=2; public final static int BY_SEX=3; public final static int BY_NONE=0; public final static String PATH_BY_NAME=DBConst.TABLE_PERSON+"/ByName/*"; public final static String PATH_BY_AGE=DBConst.TABLE_PERSON+"/ByAge/#"; public final static String PATH_BY_SEX=DBConst.TABLE_PERSON+"/BySex/*";}
static UriMatcher matcher;static { matcher=new UriMatcher(UriMatcher.NO_MATCH); matcher.addURI(MatcherConst.AUTHORITY,MatcherConst.PATH_BY_NAME,MatcherConst.BY_NAME); matcher.addURI(MatcherConst.AUTHORITY,MatcherConst.PATH_BY_AGE,MatcherConst.BY_AGE); matcher.addURI(MatcherConst.AUTHORITY,MatcherConst.PATH_BY_SEX,MatcherConst.BY_SEX); matcher.addURI(MatcherConst.AUTHORITY,DBConst.TABLE_PERSON,MatcherConst.BY_NONE);}
在上面的示例中,UriMatch绑定了四个Uri,并将各个Uri映射为四个行为代码。
其中,用到了转义符。#代表任意数字,*代表任意字母。
那么如何将行为代码映射为具体的数据库操作呢?,换句话说,在哪儿使用UriMatcher呢?当然是ContentProvider中!!!在ContentProvider中的增删改查方法中,完成操作映射。
我们来看一下,ContentProvider的创建。
ContentProvider的创建
先用Android Studio 创建一个ContentProvider.
创建过程中,需要提供AUTHORITY,
ContentProvider生成后,Android Studio将自动帮助ContentProviderr在Manifest中进行注册。
接下来,我们看看ContentProvider的结构。
ContentProvider的结构
package com.breakloop.contentproviderdemo1;import android.content.ContentProvider;import android.content.ContentValues;import android.content.UriMatcher;import android.database.Cursor;import android.net.Uri;public class MyContentProvider extends ContentProvider { public MyContentProvider() { } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { // Implement this to handle requests to delete one or more rows. throw new UnsupportedOperationException("Not yet implemented"); } @Override public String getType(Uri uri) { // TODO: Implement this to handle requests for the MIME type of the data // at the given URI. throw new UnsupportedOperationException("Not yet implemented"); } @Override public Uri insert(Uri uri, ContentValues values) { // TODO: Implement this to handle requests to insert a new row. throw new UnsupportedOperationException("Not yet implemented"); } @Override public boolean onCreate() { // TODO: Implement this to initialize your content provider on startup. return false; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { // TODO: Implement this to handle query requests from clients. throw new UnsupportedOperationException("Not yet implemented"); } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { // TODO: Implement this to handle requests to update one or more rows. throw new UnsupportedOperationException("Not yet implemented"); }}
一共七个方法。包括一个构造方法,四个数据库方法(增删改查),一个初始化方法(onCreate),还有一个getType。
关于getType,我们之后解释。
关于构造方法,没什么可解释的。
关于初始化方法,当返回true时,表明初始化成功,否则,失败。由于我们要对数据库进行操作,因此,需要获取sqlite数据库对象。
private myHelper dbHelper;public boolean onCreate() { helper=new mySqliteHelper(getContext(),DBConst.DB_NAME,null,1); return true;}
关于数据库方法,我们看到传参中存在Uri,因此,这里需要用到UirMatcher了。我们将刚才的UriMatcher代码段,加入MyContentProvider.这样,我们就可以在各个数据库方法中,解析Uri了。同时,由于sqlite数据库对象的存在,进而可以对数据库进行相应操作。
行为代码Mapping数据库操作
我们先看一下最简单的插入操作。
@Override public Uri insert(Uri uri, ContentValues values) { Uri returnUri=null; SQLiteDatabase db=helper.getWritableDatabase(); switch (matcher.match(uri)){ case MatcherConst.BY_NONE: long recordID=db.insert(DBConst.TABLE_PERSON,null,values); returnUri=Uri.parse("content://"+MatcherConst.AUTHORITY+"/"+DBConst.TABLE_PERSON+"/"+recordID); break; default: break; } return returnUri; }
再来看一下稍微复杂的查询。
@Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { Cursor cursor=null; SQLiteDatabase db=helper.getReadableDatabase(); switch (matcher.match(uri)){ case MatcherConst.BY_NONE: cursor=db.query(DBConst.TABLE_PERSON,projection,selection,selectionArgs,null,null,sortOrder); break; case MatcherConst.BY_AGE: cursor=db.query(DBConst.TABLE_PERSON,projection,DBConst.COLUMN_AGE+"=?",new String[]{uri.getPathSegments().get(2)},null,null,sortOrder); break; case MatcherConst.BY_SEX: cursor=db.query(DBConst.TABLE_PERSON,projection,DBConst.COLUMN_SEX+"=?",new String[]{uri.getPathSegments().get(2)},null,null,sortOrder); break; case MatcherConst.BY_NAME: cursor=db.query(DBConst.TABLE_PERSON,projection,DBConst.COLUMN_NAME+"=?",new String[]{uri.getPathSegments().get(2)},null,null,sortOrder); break; default: break; } return cursor; }
这里需要注意的是,如何取Uri中的传入数据。使用的获取方法是uri.getPathSegments().get(index)。该方法获取的是AUTHORITY后面的String部分。
然后,以”/”为分隔符,生成String[]。可参照博文
https://www.cnblogs.com/myorange/p/5406364.html
其中的例子,比较清楚。
接着是更新操作。
@Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { int recordID=0; SQLiteDatabase db=helper.getWritableDatabase(); switch (matcher.match(uri)){ case MatcherConst.BY_NONE: recordID=db.update(DBConst.TABLE_PERSON,values,null,null); break; case MatcherConst.BY_AGE: recordID=db.update(DBConst.TABLE_PERSON,values,DBConst.COLUMN_AGE+"=?",new String[]{uri.getPathSegments().get(2)}); break; case MatcherConst.BY_SEX: recordID=db.update(DBConst.TABLE_PERSON,values,DBConst.COLUMN_SEX+"=?",new String[]{uri.getPathSegments().get(2)}); break; case MatcherConst.BY_NAME: recordID=db.update(DBConst.TABLE_PERSON,values,DBConst.COLUMN_NAME+"=?",new String[]{uri.getPathSegments().get(2)}); break; default: break; } return recordID; }
还有删除。
@Override public int delete(Uri uri, String selection, String[] selectionArgs) { int recordID=0; SQLiteDatabase db=helper.getWritableDatabase(); switch (matcher.match(uri)){ case MatcherConst.BY_NONE: recordID=db.delete(DBConst.TABLE_PERSON,null,null); break; case MatcherConst.BY_AGE: recordID=db.delete(DBConst.TABLE_PERSON,DBConst.COLUMN_AGE+"=?",new String[]{uri.getPathSegments().get(2)}); break; case MatcherConst.BY_SEX: recordID=db.delete(DBConst.TABLE_PERSON,DBConst.COLUMN_SEX+"=?",new String[]{uri.getPathSegments().get(2)}); break; case MatcherConst.BY_NAME: recordID=db.delete(DBConst.TABLE_PERSON,DBConst.COLUMN_NAME+"=?",new String[]{uri.getPathSegments().get(2)}); break; default: break; } return recordID; }
那么,第三方如何调用ContentProvider呢?
ContentProvider的使用
这里,我们新建一个工程contentproviderdemo2,在必要的位置使用方法
public ContentResolver getContentResolver()
获取ContentProvider实例,之后便可传入Uri,调用数据库相关方法了。
例如,我们插入四条记录。
Uri returnUri=null; ContentResolver resolver=getContentResolver(); Uri uri=Uri.parse("content://"+MatcherConst.AUTHORITY+"/"+DBConst.TABLE_PERSON); ContentValues values=new ContentValues(); values.put(DBConst.COLUMN_NAME,"A"); values.put(DBConst.COLUMN_AGE,10); values.put(DBConst.COLUMN_SEX,"Male"); returnUri=resolver.insert(uri,values); if(returnUri!=null) Log.i(TAG, "return Uri = "+returnUri.toString()); values.put(DBConst.COLUMN_NAME,"B"); values.put(DBConst.COLUMN_AGE,11); values.put(DBConst.COLUMN_SEX,"Male"); returnUri=resolver.insert(uri,values); if(returnUri!=null) Log.i(TAG, "return Uri = "+returnUri.toString()); values.put(DBConst.COLUMN_NAME,"C"); values.put(DBConst.COLUMN_AGE,12); values.put(DBConst.COLUMN_SEX,"Female"); returnUri=resolver.insert(uri,values); if(returnUri!=null) Log.i(TAG, "return Uri = "+returnUri.toString()); values.put(DBConst.COLUMN_NAME,"D"); values.put(DBConst.COLUMN_AGE,13); values.put(DBConst.COLUMN_SEX,"Female"); returnUri=resolver.insert(uri,values); if(returnUri!=null) Log.i(TAG, "return Uri = "+returnUri.toString());
我们看一下输出结果。
I/com.breakloop.contentproviderdemo2.MainActivity: return Uri = content://com.breakloop.contentproviderdemo1/PERSON/1I/com.breakloop.contentproviderdemo2.MainActivity: return Uri = content://com.breakloop.contentproviderdemo1/PERSON/2I/com.breakloop.contentproviderdemo2.MainActivity: return Uri = content://com.breakloop.contentproviderdemo1/PERSON/3I/com.breakloop.contentproviderdemo2.MainActivity: return Uri = content://com.breakloop.contentproviderdemo1/PERSON/4
既然,写入成功,那我们查询一下。
public void selectRecord(){ Uri uri; String name="A"; int age=11; String sex="Male"; Log.i(TAG, "Select by Name"); uri=Uri.parse("content://"+MatcherConst.AUTHORITY+"/"+DBConst.TABLE_PERSON+"/ByName/"+name); selectRecord(uri); Log.i(TAG, "Select by Age"); uri=Uri.parse("content://"+MatcherConst.AUTHORITY+"/"+DBConst.TABLE_PERSON+"/ByAge/"+age); selectRecord(uri); Log.i(TAG, "Select by Sex"); uri=Uri.parse("content://"+MatcherConst.AUTHORITY+"/"+DBConst.TABLE_PERSON+"/BySex/"+sex); selectRecord(uri); Log.i(TAG, "Select All"); uri=Uri.parse("content://"+MatcherConst.AUTHORITY+"/"+DBConst.TABLE_PERSON); selectRecord(uri); } private void selectRecord(Uri uri){ Cursor cursor; cursor=resolver.query(uri,new String[]{DBConst.COLUMN_AGE, DBConst.COLUMN_NAME, DBConst.COLUMN_SEX},null,null,null); if(cursor!=null){ while(cursor.moveToNext()){ Log.i(TAG, "name = "+cursor.getString(1)+ " age = "+cursor.getInt(0) +" "+cursor.getString(2)); } } }
输出结果如下
I/com.breakloop.contentproviderdemo2.MainActivity: Select by NameI/com.breakloop.contentproviderdemo2.MainActivity: name = A age = 10 MaleI/com.breakloop.contentproviderdemo2.MainActivity: Select by AgeI/com.breakloop.contentproviderdemo2.MainActivity: name = B age = 11 MaleI/com.breakloop.contentproviderdemo2.MainActivity: Select by SexI/com.breakloop.contentproviderdemo2.MainActivity: name = A age = 10 MaleI/com.breakloop.contentproviderdemo2.MainActivity: name = B age = 11 MaleI/com.breakloop.contentproviderdemo2.MainActivity: Select AllI/com.breakloop.contentproviderdemo2.MainActivity: name = A age = 10 MaleI/com.breakloop.contentproviderdemo2.MainActivity: name = B age = 11 MaleI/com.breakloop.contentproviderdemo2.MainActivity: name = C age = 12 FemaleI/com.breakloop.contentproviderdemo2.MainActivity: name = D age = 13 Female
我们再来更新一下。
public void updateRecord(){ Uri uri; String name="A"; int age=11; String sex="Female"; ContentValues values=new ContentValues(); Log.i(TAG, "Update by Name"); uri=Uri.parse("content://"+MatcherConst.AUTHORITY+"/"+DBConst.TABLE_PERSON+"/ByName/"+name); values.put(DBConst.COLUMN_NAME,name+name); update(uri,values); Log.i(TAG, "Update by Age"); uri=Uri.parse("content://"+MatcherConst.AUTHORITY+"/"+DBConst.TABLE_PERSON+"/ByAge/"+age); values.clear(); values.put(DBConst.COLUMN_AGE,14); update(uri,values); Log.i(TAG, "Update by Sex"); uri=Uri.parse("content://"+MatcherConst.AUTHORITY+"/"+DBConst.TABLE_PERSON+"/BySex/"+sex); values.clear(); values.put(DBConst.COLUMN_AGE,15); update(uri,values); Log.i(TAG, "Update All"); uri=Uri.parse("content://"+MatcherConst.AUTHORITY+"/"+DBConst.TABLE_PERSON); values.put(DBConst.COLUMN_SEX,"Male"); update(uri,values); Log.i(TAG, "Select All"); uri=Uri.parse("content://"+MatcherConst.AUTHORITY+"/"+DBConst.TABLE_PERSON); selectRecord(uri); } private void update(Uri uri,ContentValues values){ int count; count=resolver.update(uri,values,null,null); Log.i(TAG, "update "+count+" record"); }
结果如下
I/com.breakloop.contentproviderdemo2.MainActivity: Update by NameI/com.breakloop.contentproviderdemo2.MainActivity: update 1 recordI/com.breakloop.contentproviderdemo2.MainActivity: Update by AgeI/com.breakloop.contentproviderdemo2.MainActivity: update 1 recordI/com.breakloop.contentproviderdemo2.MainActivity: Update by SexI/com.breakloop.contentproviderdemo2.MainActivity: update 2 recordI/com.breakloop.contentproviderdemo2.MainActivity: Update AllI/com.breakloop.contentproviderdemo2.MainActivity: update 4 recordI/com.breakloop.contentproviderdemo2.MainActivity: Select AllI/com.breakloop.contentproviderdemo2.MainActivity: name = AA age = 15 MaleI/com.breakloop.contentproviderdemo2.MainActivity: name = B age = 15 MaleI/com.breakloop.contentproviderdemo2.MainActivity: name = C age = 15 MaleI/com.breakloop.contentproviderdemo2.MainActivity: name = D age = 15 Male
都不要了,删除!(这里是对更新前的数据库进行的操作!!)
public void deleteRecord(){ Uri uri; String name="A"; int age=11; String sex="Female"; Log.i(TAG, "Delete by Name"); uri=Uri.parse("content://"+MatcherConst.AUTHORITY+"/"+DBConst.TABLE_PERSON+"/ByName/"+name); delete(uri); Log.i(TAG, "Select All"); uri=Uri.parse("content://"+MatcherConst.AUTHORITY+"/"+DBConst.TABLE_PERSON); selectRecord(uri); Log.i(TAG, "Delete by Age"); uri=Uri.parse("content://"+MatcherConst.AUTHORITY+"/"+DBConst.TABLE_PERSON+"/ByAge/"+age); delete(uri); Log.i(TAG, "Select All"); uri=Uri.parse("content://"+MatcherConst.AUTHORITY+"/"+DBConst.TABLE_PERSON); selectRecord(uri); Log.i(TAG, "Delete by Sex"); uri=Uri.parse("content://"+MatcherConst.AUTHORITY+"/"+DBConst.TABLE_PERSON+"/BySex/"+sex); delete(uri); Log.i(TAG, "Select All"); uri=Uri.parse("content://"+MatcherConst.AUTHORITY+"/"+DBConst.TABLE_PERSON); selectRecord(uri); Log.i(TAG, "Delete All"); uri=Uri.parse("content://"+MatcherConst.AUTHORITY+"/"+DBConst.TABLE_PERSON); delete(uri); Log.i(TAG, "Select All"); uri=Uri.parse("content://"+MatcherConst.AUTHORITY+"/"+DBConst.TABLE_PERSON); selectRecord(uri); } private void delete(Uri uri){ int count; count=resolver.delete(uri,null,null); Log.i(TAG, "delete "+count+" record"); }
结果如下
I/com.breakloop.contentproviderdemo2.MainActivity: delete 1 recordI/com.breakloop.contentproviderdemo2.MainActivity: Select AllI/com.breakloop.contentproviderdemo2.MainActivity: name = B age = 11 MaleI/com.breakloop.contentproviderdemo2.MainActivity: name = C age = 12 FemaleI/com.breakloop.contentproviderdemo2.MainActivity: name = D age = 13 FemaleI/com.breakloop.contentproviderdemo2.MainActivity: Delete by AgeI/com.breakloop.contentproviderdemo2.MainActivity: delete 1 recordI/com.breakloop.contentproviderdemo2.MainActivity: Select AllI/com.breakloop.contentproviderdemo2.MainActivity: name = C age = 12 FemaleI/com.breakloop.contentproviderdemo2.MainActivity: name = D age = 13 FemaleI/com.breakloop.contentproviderdemo2.MainActivity: Delete by SexI/com.breakloop.contentproviderdemo2.MainActivity: delete 2 recordI/com.breakloop.contentproviderdemo2.MainActivity: Select AllI/com.breakloop.contentproviderdemo2.MainActivity: Delete AllI/com.breakloop.contentproviderdemo2.MainActivity: delete 0 recordI/com.breakloop.contentproviderdemo2.MainActivity: Select All
至此,ContentProvider的创建和使用便介绍完了。
如果,只是为了使用,可以只看到这里就好了!
我是华丽的分割线!
之后的部分,本文还未找到答案!因此,只是记录!
如果有知道的童鞋,还望指点。
那么,还有什么?
还记得ContentProvider中的getType吗?
到目前为止,我们并没有实现getType方法。而这并没有对ContentProvider的使用造成任何影响。那么问题来了。getType干嘛用的?什么时候用?
对于getType的解释,网上有两种。
(1)用于对返回数据的解析。判断是一条数据,还是多条数据。若getType方法被实现,则按照实现方法解析,提高了工作效率。否则,系统自动解析。
代表博文 https://www.2cto.com/kf/201512/452640.html
(2)避免new Intent(String action, Uri uri)方式无法启动activity。
代表博文http://blog.csdn.net/imyfriend/article/details/6589917
对于解释(1),并未从找到官方的出处。而对于解释(2),不太明白!我用ContentProvider碍activity何事?
关于getType方法的实现,其原型注释给出了答案。
方法返回的是MIME类型的String形式。根据Uri的结尾不同,输出也不同。
若Uri以Path结尾,则返回格式为
vnd.android.cursor.dir/vnd.<authority>.<path>
若Uri以id结尾,则返回格式为
vnd.android.cursor.item/vnd.<authority>.<path>
因此,我们实例中的getType()实现为
@Override public String getType(Uri uri) { Log.i(TAG, "getType: "); String authorityAndPath=MatcherConst.AUTHORITY+"."+DBConst.TABLE_PERSON; String handerPath="vnd.android.cursor.dir/vnd."; String handerID="vnd.android.cursor.item/vnd."; switch (matcher.match(uri)){ case MatcherConst.BY_NONE: return handerPath+authorityAndPath; case MatcherConst.BY_AGE: case MatcherConst.BY_SEX: case MatcherConst.BY_NAME: return handerID+authorityAndPath; default: return null; } }
至此,结文~
- Android四大组件(ContentProvider篇)
- Android四大组件-ContentProvider
- Android四大组件-ContentProvider
- android四大组件---ContentProvider
- android四大组件--ContentProvider
- android四大组件--ContentProvider
- Android四大组件ContentProvider
- 【Android】四大组件(4)ContentProvider
- Android学习-四大组件(ContentProvider)
- Android四大组件之ContentProvider(上)
- Android四大组件之ContentProvider(下)
- Android 四大组件(三)ContentProvider
- Android四大组件之ContentProvider
- android四大组件之ContentProvider
- android四大组件之 ContentProvider
- Android四大组件之ContentProvider
- Android四大组件之ContentProvider
- android 四大组件之ContentProvider
- 持久层mybatis的sql向sqlserver插入数据,带小数位的数字字符串自动四舍五入
- 输出一个菱形
- 控制反转(IOC)、依赖注入(DI)之通过构造函数注入对象
- mysql错误:1093-You can’t specify target table for update in FROM clause的解决方法
- 关于CSS编码规范的文章
- Android四大组件(ContentProvider篇)
- Java NIO入门与详解
- EBS开发常见问题及学习方向总结
- Java小应用日志级别异常处理最佳实践
- .NET代码混淆
- CSS常用选择器介绍
- opencv2 用imwrite 抽取并保存视频图像帧
- 无用代码
- Android 实现视屏播放器、边播边缓存功能、外加铲屎(IJKPlayer)