Hi,大家好!
今天我们主要来讲解下,Android的数据共享机制Content Provider。
轻松下:
应 聘
人事总监:您对电脑懂多少?
应聘者A:略懂一二:我用过计算器,戴过电子表,喜欢玩电子游戏机,我还用电视机 和机顶盒上网跟国外的朋友联系呢......还有,我看过同学用DOS删除文件......
人事总监:下一位!
人事总监:您对电脑懂多少?
应聘者B:在我头脑里没有“电脑”这个词,只有微型计算机这样一个概念!一般地 超级掌上型硅单晶片时钟脉冲输出计算机(电子表)比较简单,我小时候常使用它 的编解码运行程序(闹钟功能);至于多功能虚拟现实模拟器(电子游戏机)就复 杂多了,不过我曾经完整测试过多静态资料单元(只玩过关游戏卡);长大后我开 始对多频道超高频无线多媒体接收器(电视机)产生兴趣,每天晚上会追踪特定频 道的资料;至于传统的微型计算机,最近我还用调制解调器通过ISP服务商跟国外的 朋友进行多格式多字节实时传输(上网聊天),还有,我手下的一个工作伙伴(同学) 经常在我的监控下进行主存储器与磁化资料存储器之间的信号转化或信号取消(用DOS 开机和删除文件).....
人事总监:ok!明天开始上班。你的配车在地下二层,这是钥匙......
1 什么是Content Provider?
2 什么是URI?
3 如何使用Content Provider?
1 Android中的Content provider机制可支持在多个应用中存储和读取数据。这也是跨应用共享数据的唯一方式。在android系统中,没有一个公共的内存区域,供多个应用共享存储数据。
Android提供了一些主要数据类型的Content provider,比如音频、视频、图片和私人通讯录等。可在android.provider包下面找到一些android提供的Content provider。可以获得这些Content provider,查询它们包含的数据,当然前提是已获得适当的读取权限。
2 通用资源标志符
(Universal Resource Identifier, 简称"URI")。
Uri代表要操作的数据,Android上可用的每种资源 - 图像、视频片段等都可以用Uri来表示。
每一个Content Provider都有一个公共URI,这个URI表示Content Provider所提供的数据。
3 使用Content Provider
1 首先,当前应用中,需要有数据库,上篇博文已经对操作数据库进行了讲解,在这里不再赘述。
2 需要创建一个类并且继承Content Provider类,并实现这个抽象类中的六个方法。
public int delete(Uri uri, String selection, String[] selectionArgs){}
public String getType(Uri uri) {}
public Uri insert(Uri uri, ContentValues values) {}
public boolean onCreate() {}
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {}public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {}3 需要给当前应用中的Content Provider定义一个URI,并且定义查询的类型,下边是一个常量类
package TSD.Jason.DB;
import android.net.Uri;
public class CPFinal {
public final static String DATABASE_NAME="StudentDB"; //数据库名称
public final static String TABLE_NAME="StudentInfo"; //数据表名称
/*定义ContentProvide的名称,一般以项目包名+CP类名
* 注意:规范CP名称
* */
public final static String CPNAME = "TSD.Jason.CPDemo.StudentCP";
//定义访问此CP的路径 格式: content:// + 路径 + 子表名称
public final static Uri CONTENT_URI = Uri.parse("content://" + CPNAME + "/" + TABLE_NAME);
/*定义查询数据类型
* 如果要查询所有
* 格式 vnd.android.cursor.dir + 定义的名字
* */
public final static String CONTENT_TYPE="vnd.android.cursor.dir/selectAll";
public final static String CONTENT_TYPE_ITEM ="vnd.android.cursor.item/selectItem";
}4 回到自定义的Content Provider类中,我们需要使用到一个UriMatcher的类,这个类主要是在调用查询函数query()函数时,会用到。
大家都知道,查询分为两大块,一块是不带条件的查询整表,一块是带有一定条件,查询此条件下的数据。
例如: select * from Table 和 select * from Table where t_id = 1
UriMatcher正是用来规定我们这个Content Provider有哪一些查询类型和检查传入的URI是否符合我们的规定
我们定义了这两种查询方式,自然需要将这两种查询方式放到UriMatcher中,定义我们查询的规则
代码如下
//检查传入的uri是否符合我们设置的标准
private final static UriMatcher uriMatcher;
private final static int SELECT_ALL = 1;
private final static int SELECT_ITEM= 2;
static{
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(CPFinal.CPNAME, "StudentInfo", SELECT_ALL);
uriMatcher.addURI(CPFinal.CPNAME, "StudentInfo/#", SELECT_ITEM);
}这里可以看到,我们addURI了两种规则,
一种就是查询StudentInfo表中的所有数据的,一种是查询StudentInfo表中ID为什么的数据,#代表表中的ID列当我们需要调用时,需要传递的字符串就是 当前定义的ContentProvider的名字,这里我们叫做
public final static String CPNAME = "TSD.Jason.CPDemo.StudentCP";
查询所有的字符串就是 TSD.Jason.CPDemo.StudentCP/StudentInfo
查询某条数据的字符串就是 TSD.Jason.CPDemo.StudentCP/StudentInfo/1
检查URI
需要用到uriMatcher.match(uri)中的match函数
应为我们上边add了两个URI规则,并对应两个int常量,所以如果使用的是
TSD.Jason.CPDemo.StudentCP/StudentInfo 那么match函数返回SELECT_ALL
TSD.Jason.CPDemo.StudentCP/StudentInfo/1 返回SELECT_ITEM
实现下边的增删改成函数即可。
package TSD.Jason.CPDemo;
import java.util.HashMap;
import TSD.Jason.DB.CPFinal;
import TSD.Jason.DB.DBColumns;
import TSD.Jason.DB.DBHelp;
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.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
public class StudentCP extends ContentProvider {
//检查传入的uri是否符合我们设置的标准
private final static UriMatcher uriMatcher;
private final static int SELECT_ALL = 1;
private final static int SELECT_ITEM= 2;
static{
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(CPFinal.CPNAME, "StudentInfo", SELECT_ALL);
uriMatcher.addURI(CPFinal.CPNAME, "StudentInfo/#", SELECT_ITEM);
}
//TSD.Jason.CPTest.StudentCP/StudentInfo
/**
* 需要给数据表中的列,定义一个别名
*/
private static HashMap<String, String> columnName;
static{
columnName = new HashMap<String, String>();
columnName.put(DBColumns.S_NAME, DBColumns.S_NAME);
columnName.put(DBColumns.S_AGE, DBColumns.S_AGE);
columnName.put(DBColumns.S_SEX, DBColumns.S_SEX);
columnName.put(DBColumns.S_ADDRESS, DBColumns.S_ADDRESS);
}
DBHelp dbHelp;
/**
* 根据传入的URI,返回所传入的URI所表示的查询数据类型
* 此函数用来匹配 此类的静态代码段中所定义的规则
*/
@Override
public String getType(Uri uri) {
System.out.println(uri.toString()+" -----------gettype");
switch (uriMatcher.match(uri)) {
case SELECT_ALL:
return CPFinal.CONTENT_TYPE;
case SELECT_ITEM:
return CPFinal.CONTENT_TYPE_ITEM;
default:
return null;
}
}
@Override
public boolean onCreate() {
dbHelp = new DBHelp(getContext(), CPFinal.DATABASE_NAME);
System.out.println("create---------------");
return false;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
System.out.println("insert -----------------" + uri.toString());
SQLiteDatabase db = dbHelp.getWritableDatabase();
long result = db.insert(CPFinal.TABLE_NAME, null, values);
System.out.println("insert ------------" + result);
if(result > 0)
{
Uri resultUri = ContentUris.withAppendedId(CPFinal.CONTENT_URI, result);
//通知监听器,数据已经发生改变
getContext().getContentResolver().notifyChange(resultUri, null);
return resultUri;
}
return null;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
SQLiteDatabase db = dbHelp.getWritableDatabase();
return db.delete(CPFinal.TABLE_NAME, selection, selectionArgs);
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
SQLiteDatabase db = dbHelp.getReadableDatabase();
qb.setTables(CPFinal.TABLE_NAME);
Cursor c = qb.query(db, projection, selection, null, null, null, sortOrder);
c.setNotificationUri(getContext().getContentResolver(), uri);
return c;
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
// TODO Auto-generated method stub
return 0;
}
}调用
btn1.setOnClickListener(new Button.OnClickListener() {
@Override
public void onClick(View v) {
ContentValues contentvalues = new ContentValues();
contentvalues.put(DBColumns.S_NAME, "张三");
contentvalues.put(DBColumns.S_AGE, "23");
contentvalues.put(DBColumns.S_SEX, "男");
contentvalues.put(DBColumns.S_ADDRESS, "北京市海淀区");
Uri uri =getContentResolver().insert(CPFinal.CONTENT_URI, contentvalues);
System.out.println(uri.toString()+"------------activity");
}
});此处调用了增加函数,剩下的删除、修改、查询,依次类推。
最后在AndroidManifest.xml中需要注册provider
<provider android:name=".StudentCP"
android:authorities="TSD.Jason.CPDemo.StudentCP"></provider>