一、相关ContentProvider概念解析:
1、ContentProvider简介
在Android官方指出的Android的数据存储方式总共有五种,分别是:Shared Preferences、网络存储、文件存储、外储存储、SQLite。但是我们知道一般这些存储都只是在单独的一个应用程序之中达到一个数据的共享,有时候我们需要 *** 作其他应用程序的一些数据,例如我们需要 *** 作系统里的媒体库、通讯录等,这时我们就可能通过ContentProvider来满足我们的需求了。
2、为什么要选择ContentProvider?
ContentProvider向我们提供了我们在应用程序之前共享数据的一种机制,而我们知道每一个应用程序都是运行在不同的应用程序的,数据和文件在不同应用程序之间达到数据的共享不是没有可能,而是显得比较复杂,而正好Android中的ContentProvider则达到了这一需求,比如有时候我们需要 *** 作手机里的联系人,手机里的多媒体等一些信息,我们都可以用到这个ContentProvider来达到我们所需。
1)、ContentProvider为存储和获取数据提供了统一的接口。ContentProvide对数据进行封装,不用关心数据存储的细节。使用表的形式来组织数据。
2)、使用ContentProvider可以在不同的应用程序之间共享数据。
3)、Android为常见的一些数据提供了默认的ContentProvider(包括音频、视频、和通讯录等)。
总的来说使用ContentProvider对外共享数据的好处是统一了数据的访问方式。
3、Uri介绍
为系统的每一个资源给其一个名字,比方说通话记录。
1)、每一个ContentProvider都拥有一个公共的URI,这个URI用于表示这个ContentProvider所提供的数据。
2)、Android所提供的ContentProvider都存放在androidprovider包中。 将其分为A,B,C,D 4个部分:
A:标准前缀,用来说明一个Content Provider控制这些数据,无法改变的;"content://"
B:URI 的标识,用于唯一标识这个ContentProvider,外部调用者可以根据这个标识来找到它。它定义了是哪个Content Provider提供这些数据。对于第三方应用程序,为了保证URI标识的唯一性,它必须是一个完整的、小写的类名。这个标识在 元素的 authorities属性中说明:一般是定义该ContentProvider的包类的名称
C:路径(path),通俗的讲就是你要 *** 作的数据库中表的名字,或者你也可以自己定义,记得在使用的时候保持一致就可以了;"content://combingprovidermyprovider/tablename"
D:如果URI中包含表示需要获取的记录的ID;则就返回该id对应的数据,如果没有ID,就表示返回全部; "content://combingprovidermyprovider/tablename/#" #表示数据id。
PS:
路径(path)可以用来表示我们要 *** 作的数据,路径的构建应根据业务而定,如下:
1、要 *** 作person表中id为10的记录,可以构建这样的路径:/person/10
2、要 *** 作person表中id为10的记录的name字段, person/10/name
3、要 *** 作person表中的所有记录,可以构建这样的路径:/person
4、要 *** 作xxx表中的记录,可以构建这样的路径:/xxx
5、当然要 *** 作的数据不一定来自数据库,也可以是文件、xml或网络等其他存储方式,如下:
要 *** 作xml文件中person节点下的name节点,可以构建这样的路径:/person/name
6、如果要把一个字符串转换成Uri,可以使用Uri类中的parse()方法,如下:Uri uri = Uriparse("content://combingproviderpersonprovider/person")
4、UriMatcher类使用介绍
因为Uri代表了要 *** 作的数据,所以我们经常需要解析Uri,并从Uri中获取数据。Android系统提供了两个用于 *** 作Uri的工具类,分别为UriMatcher和ContentUris 。掌握它们的使用,会便于我们的开发工作。
UriMatcher类用于匹配Uri,它的用法如下:
首先第一步把你需要匹配Uri路径全部给注册上,如下:
//常量UriMatcherNO_MATCH表示不匹配任何路径的返回码UriMatcher sMatcher = new UriMatcher(UriMatcherNO_MATCH);//如果match()方法匹配content://combingprocvidepersonprovider/person路径,返回匹配码为1sMatcheraddURI("combingprocvidepersonprovider", "person", 1);//添加需要匹配uri,如果匹配就会返回匹配码//如果match()方法匹配content://combingproviderpersonprovider/person/230路径,返回匹配码为2sMatcheraddURI("combingproviderpersonprovider", "person/#", 2);//#号为通配符switch (sMatchermatch(Uriparse("content://comljqproviderpersonprovider/person/10"))) {
case 1 break; case 2 break; default://不匹配
break;
}
注册完需要匹配的Uri后,就可以使用sMatchermatch(uri)方法对输入的Uri进行匹配,如果匹配就返回匹配码,匹配码是调用addURI()方法传入的第三个参数,假设匹配content://comljqproviderpersonprovider/person路径,返回的匹配码为1
5、ContentUris类使用介绍
ContentUris类用于 *** 作Uri路径后面的ID部分,它有两个比较实用的方法:
withAppendedId(uri, id)用于为路径加上ID部分:
Uri uri = Uriparse("content://combingproviderpersonprovider/person")
Uri resultUri = ContentUriswithAppendedId(uri, 10);
//生成后的Uri为:content://combingproviderpersonprovider/person/10
parseId(uri)方法用于从路径中获取ID部分:
Uri uri = Uriparse("content://comljqproviderpersonprovider/person/10")long personid = ContentUrisparseId(uri);//获取的结果为:10
6、使用ContentProvider共享数据
1)ContentProvider类主要方法的作用:
public boolean onCreate():该方法在ContentProvider创建后就会被调用,Android开机后,ContentProvider在其它应用第一次访问它时才会被创建。
public Uri insert(Uri uri, ContentValues values):该方法用于供外部应用往ContentProvider添加数据。
public int delete(Uri uri, String selection, String[] selectionArgs):该方法用于供外部应用从ContentProvider删除数据。
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs):该方法用于供外部应用更新ContentProvider中的数据。
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder):该方法用于供外部应用从ContentProvider中获取数据。
public String getType(Uri uri):该方法用于返回当前Url所代表数据的MIME类型。
2)如果 *** 作的数据属于集合类型,那么MIME类型字符串应该以vndandroidcursordir/开头,
例如:要得到所有person记录的Uri为content://combingproviderpersonprovider/person,那么返回的MIME类型字符串应该为:"vndandroidcursordir/person"。
3)如果要 *** 作的数据属于非集合类型数据,那么MIME类型字符串应该以vndandroidcursoritem/开头,
例如:得到id为10的person记录,Uri为content://combingproviderpersonprovider/person/10,那么返回的MIME类型字符串为:"vndandroidcursoritem/person"。
7、ContentResolver *** 作ContentProvider中的数据
1)当外部应用需要对ContentProvider中的数据进行添加、删除、修改和查询 *** 作时,可以使用ContentResolver 类来完成,要获取ContentResolver 对象,可以使用Activity提供的getContentResolver()方法。
2)ContentResolver 类提供了与ContentProvider类相同签名的四个方法:
public Uri insert(Uri uri, ContentValues values):该方法用于往ContentProvider添加数据。
public int delete(Uri uri, String selection, String[] selectionArgs):该方法用于从ContentProvider删除数据。
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs):该方法用于更新ContentProvider中的数据。
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder):该方法用于从ContentProvider中获取数据。
这些方法的第一个参数为Uri,代表要 *** 作的ContentProvider和对其中的什么数据进行 *** 作,
其实和contentprovider里面的方法是一样的他们所对应的数据,最终是会被传到我们在之前程序里面定义的那个contentprovider类的方法,
假设给定的是:Uriparse("content://combingproviderspersonprovider/person/10"),那么将会对主机名为combingproviderspersonprovider的ContentProvider进行 *** 作, *** 作的数据为person表中id为10的记录。
使用ContentResolver对ContentProvider中的数据进行添加、删除、修改和查询 *** 作:
ContentResolver resolver = getContentResolver();
Uri uri = Uriparse("content://combingproviderpersonprovider/person");//添加一条记录ContentValues values = new ContentValues();
valuesput("name", "bingxin");
valuesput("age", 25);
resolverinsert(uri, values);
//获取person表中所有记录Cursor cursor = resolverquery(uri, null, null, null, "personid desc");while(cursormoveToNext()){
Logi("ContentTest", "personid="+ cursorgetInt(0)+ ",name="+ cursorgetString(1));
}//把id为1的记录的name字段值更改新为zhangsanContentValues updateValues = new ContentValues();
updateValuesput("name", "zhangsan");
Uri updateIdUri = ContentUriswithAppendedId(uri, 2);
resolverupdate(updateIdUri, updateValues, null, null);//删除id为2的记录Uri deleteIdUri = ContentUriswithAppendedId(uri, 2);
resolverdelete(deleteIdUri, null, null);
8、监听ContentProvider中数据的变化
如果ContentProvider的访问者需要知道ContentProvider中的数据发生变化,可以在ContentProvider发生数据变化时调用getContentResolver()notifyChange(uri, null)来通知注册在此URI上的访问者,例子如下:
public class PersonContentProvider extends ContentProvider { public Uri insert(Uri uri, ContentValues values) {
dbinsert("person", "personid", values);
getContext()getContentResolver()notifyChange(uri, null);
}
}
如果ContentProvider的访问者需要得到数据变化通知,必须使用ContentObserver对数据(数据采用uri描述)进行监听,当监听到数据变化通知时,系统就会调用ContentObserver的onChange()方法:
getContentResolver()registerContentObserver(Uriparse("content://comljqproviderspersonprovider/person"), true, new PersonObserver(new Handler()));public class PersonObserver extends ContentObserver{ public PersonObserver(Handler handler) { super(handler);
} public void onChange(boolean selfChange) { //此处可以进行相应的业务处理 }
}
二、ContentProvider的实现过程
1、定义一个CONTENT_URI常量,提供了访问ContentProvider的标识符。
public static final Uri CONTENT_URI = Uriparse("content://comexamplecodelabtransportationprovider");
其中:content是协议
Comexmaplecodelabtransportationprovider是类名,包含完整的包名。
Uriparse将一个字符串转换成Uri类型。
如果Provider包含子表,同样定义包含字表的CONTENT_URI。
content://comexamplecodelabtransportationprovider/train
content://comexamplecodelabtransportationprovider/air/domestic
content://comexamplecodelabtransportationprovider/air/international
然后定义列,确保里面包含一个_id的列。
2、定义一个类,继承ContentProvider。
public class FirstContentProvider extends ContentProvider
先介绍一下ContentProvider用到的UriMatcher。UriMatcher的一个重要的函数是match(Uri uri)。这个函数可以匹配Uri,根据传入的不同Uri返回不同的自定义整形值,以表明Uri访问的不同资源的类型。
三、实例
1、常量类
在创建UriMatcher对象uriMatcher时,我们传给构造函数的参数为UriMatcherNO_MATCH,它表示当uriMatcher不能匹配指定的URI时,就返回代码UriMatcherNO_MATCH。接下来增加了三个匹配规则,分别是uriMatcher = new UriMatcher(UriMatcherNO_MATCH); uriMatcheraddURI(ContentDataAUTHORITY, "teacher", TEACHERS); uriMatcheraddURI(ContentDataAUTHORITY, "teacher/#", TEACHER);
它们的匹配码分别是teacherITEM、teacherITEM_ID和teacherITEM_POS,其中,符号#表示匹配任何数字。
2、SQLite *** 作类DBOpenHelper
/
是一个回调函数,在ContentProvider创建的时候,就会运行,第二个参数为指定数据库名称,如果不指定,就会找不到数据库;
如果数据库存在的情况下是不会再创建一个数据库的。(当然首次调用 在这里也不会生成数据库必须调用SQLiteDatabase的 getWritableDatabase,getReadableDatabase两个方法中的一个才会创建数据库) /
// 下面的方法用于从URI中解析出id,对这样的路径content://comljqproviderpersonprovider/person/10
// 进行解析,返回值为10
long personid = ContentUrisparseId(uri);
String where = "_ID=" + personid;// 获取指定id的记录
where += !TextUtilsisEmpty(selection) " and (" + selection + ")" : "";// 把其它条件附加上
1、这里我们在ArticlesProvider类的内部中定义了一个DBHelper类,它继承于SQLiteOpenHelper类,它用是用辅助我们 *** 作数据库的。使用这个DBHelper类来辅助 *** 作数据库的好处是只有当我们第一次对数据库时行 *** 作时,系统才会执行打开数据库文件的 *** 作。拿我们这个例子来说,只有第三方应用程序第一次调用query、insert、update或者delete函数来 *** 作数据库时,我们才会真正去打开相应的数据库文件。这样在onCreate函数里,就不用执行打开数据库的 *** 作,因为这是一个耗时的 *** 作,而在onCreate函数中,要避免执行这些耗时的 *** 作。
2、我们在实现自己的Content Provider时,必须继承于ContentProvider类,并且实现以下六个函数:
-- onCreate(),用来执行一些初始化的工作。
-- query(Uri, String[], String, String[], String),用来返回数据给调用者。
-- insert(Uri, ContentValues),用来插入新的数据。
-- update(Uri, ContentValues, String, String[]),用来更新已有的数据。
-- delete(Uri, String, String[]),用来删除数据。
-- getType(Uri),用来返回数据的MIME类型。
4、manifest
这里用ContentProvider方法来定义数据库。。
public class AlarmProvider extends ContentProvider //
{
private static final String DB_NAME = "Alarmdb"; //数据库名
private static final int DB_VERSION = 1;//版本号,当程序第一次运行时,数据库被建立,如果
//你更改了数据库,如增加一个表,这时,这个值一般要改一下,这样程序再次安装运行
//时,数据库可自行升级。。如果不改通常要手动删除数据库。。
private static final String ALARM_TABLE_NAME = "alarm"; //一个表名
private static final int ALARM = 1; //与表对应的整数值,相当于id
private static UriMatcher mUriMathcer; //Uri匹配器,建立uri,表名,id三者之间的关系,如下:
static{
mUriMathcer = new UriMatcher(UriMatcherNO_MATCH);
mUriMathceraddURI(AlarmInfoAUTH, "alarm", ALARM);
}
private interface CreateTableInterface //表创建接口
{
public abstract void createAlarmTable(SQLiteDatabase db);
}
//内部类,数据库助手类,并实现表创建接口
private static class DatabaseHelper extends SQLiteOpenHelper implements CreateTableInterface
{
CreateTableInterface mCreateTableInterface = this;
Context mContext = null;
//构造函数,该函数调用后,数据库没有
//创建。。也就是下面的onCreate不会在它调用后就立即调用创建db
public DatabaseHelper(Context context)
{
super(context, DB_NAME, null, DB_VERSION);
// Logi(TAG, "DatabaseHelper be called!");
mContext = context;
}
@Override
public void onCreate(SQLiteDatabase db) //这个方法只在第一次db连接创建db时调用,只一次
{
//create db table
mCreateTableInterfacecreateAlarmTable(db);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) //db升级时调用
{
// Logi(TAG, "onUpgrade() be called!");
dbexecSQL("DROP TABLE IF EXISTS "+ALARM_TABLE_NAME);
onCreate(db);
}
@Override
public void createAlarmTable(SQLiteDatabase db)
{
// 创建表
dbexecSQL("CREATE TABLE "+ALARM_TABLE_NAME+" ("
+AlarmInfo_ID+" INTEGER PRIMARY KEY,"
+AlarmInfo_LABEL+" TEXT NOT NULL,"
+AlarmInfo_TIME+" TEXT NOT NULL,"
+AlarmInfo_ALERT+" TEXT NOT NULL,"
+AlarmInfo_REPEAT+" TEXT NOT NULL,"
+AlarmInfo_ACTIVE+" TEXT NOT NULL"
+");");
//在表中插入一些数据。。。
dbexecSQL("INSERT INTO "+ALARM_TABLE_NAME+"("+AlarmInfo_LABEL+","
+AlarmInfo_TIME+","+AlarmInfo_ALERT+","
+AlarmInfo_REPEAT+","+AlarmInfo_ACTIVE+
") VALUES('Lunch Alarm','11 : 45 AM','"+TagTONE+"','"+TagEVERY_DAY+"','false');");
dbexecSQL("INSERT INTO "+ALARM_TABLE_NAME+"("+AlarmInfo_LABEL+","
+AlarmInfo_TIME+","+AlarmInfo_ALERT+","
+AlarmInfo_REPEAT+","+AlarmInfo_ACTIVE
+") VALUES('Work Alarm','08 : 45 AM','"+TagTONE+"',"+"'Mon,Tue,Wed,Thu,Fri'"
+",'false');");
dbexecSQL("INSERT INTO "+ALARM_TABLE_NAME+"("+AlarmInfo_LABEL+","
+AlarmInfo_TIME+","+AlarmInfo_ALERT+","+AlarmInfo_REPEAT+","
+AlarmInfo_ACTIVE
+") VALUES('Work Alarm','09 : 00 AM','"+TagTONE+"',"
+"'"+TagWEEKENDS+"','false');");
dbexecSQL("INSERT INTO "+ALARM_TABLE_NAME+"("+AlarmInfo_LABEL+","
+AlarmInfo_TIME+","+AlarmInfo_ALERT+","+AlarmInfo_REPEAT+","
+AlarmInfo_ACTIVE
+") VALUES('Yoga','10 : 15 PM','"+TagTONE+"',"+"'Sun,Wed','false');");
}
}
}
private DatabaseHelper mDatabaseHelper; //定义helper
//以下重写insert,delete,update,query等方法
@Override
public synchronized int delete(Uri uri, String selection, String[] selectionArgs)
{
SQLiteDatabase db = null;
boolean success = false;
int count = 0;
try{
db = mDatabaseHelpergetWritableDatabase();
dbacquireReference();
success = true;
switch(mUriMathcermatch(uri)){
case ALARM:
count = dbdelete(ALARM_TABLE_NAME, selection, selectionArgs);
break;
}
}catch(SQLException e){
eprintStackTrace();
}finally{
if(success == true){
dbreleaseReference();
}
}
return count;
}
@Override
public String getType(Uri uri)
{
switch(mUriMathcermatch(uri)){
case ALARM:
return AlarmInfoCONTENT_TYPE;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
}
@Override
public synchronized Uri insert(Uri uri, ContentValues initValues)
{
SQLiteDatabase mSQLiteDatabase = null;
boolean success = false;
try{
mSQLiteDatabase = mDatabaseHelpergetWritableDatabase();
mSQLiteDatabaseacquireReference();
success = true;
long mRowId;
ContentValues values;
if(initValues == null){
values = new ContentValues();
}else{
values = initValues;
}
switch(mUriMathcermatch(uri)){
case ALARM:
mRowId = mSQLiteDatabaseinsert(ALARM_TABLE_NAME,
AlarmInfo_ID, values);
if(mRowId > 0){
return uri;
}else{
throw new SQLException("Failed to insert to "+uri);
}
}
}catch(SQLException e){
eprintStackTrace();
}finally{
if(success == true)
mSQLiteDatabasereleaseReference();
}
return null;
}
@Override
public boolean onCreate()
{
// Logi("alarm provider", "onCreate()");
mDatabaseHelper = new DatabaseHelper(getContext());
return true;
}
@Override
public synchronized Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder)
{
SQLiteQueryBuilder mSQLiteQueryBuilder = new SQLiteQueryBuilder();
switch(mUriMathcermatch(uri)){
case ALARM:
mSQLiteQueryBuildersetTables(ALARM_TABLE_NAME);
break;
}
SQLiteDatabase mSQLiteDatabase = mDatabaseHelpergetWritableDatabase();
mSQLiteDatabaseacquireReference();
Cursor mCursor = mSQLiteQueryBuilderquery(mSQLiteDatabase, projection,
selection, selectionArgs, null, null, sortOrder);
mSQLiteDatabasereleaseReference();
return mCursor;
}
@Override
public synchronized int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs)
{
SQLiteDatabase mSQLiteDatabase = null;
int count = 0;
boolean success = false;
try{
mSQLiteDatabase = mDatabaseHelpergetWritableDatabase();
mSQLiteDatabaseacquireReference();
success = true;
switch(mUriMathcermatch(uri)){
case ALARM:
count = mSQLiteDatabaseupdate(ALARM_TABLE_NAME, values,
selection, selectionArgs);
break;
default:
break;
}
}catch(SQLException e){
eprintStackTrace();
}finally{
if(success == true)
mSQLiteDatabasereleaseReference();
}
return count;
}
}
可以参考android alarm源码,query,update等方法写法基本不改什么,只替换表名。或增加一个case
以上就是关于请简要说明Contentprovider对外共享数据的好处全部的内容,包括:请简要说明Contentprovider对外共享数据的好处、android程序数据库问题... DBHelper helper = new DBHelper(this, DB_NAME, null, VERSION); 不懂啊、等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)