您的位置:首页 > 移动开发 > Android开发

Android学习十九:ContentProvider初步

2014-08-25 17:43 323 查看
一、Content Provider基本概念

1、ContentProvider为存储和获取数据提供了统一的接口。ContentProvide对数据进行封装,不用关心数据存储的细节。使用表的形式来组织数据。



2、使用ContentProvider可以在不同的应用程序之间共享数据。
3、Android为常见的一些数据提供了默认的ContentProvider(包括音频、视频、图片和通讯录等)。

ContentProvider所提供的函数:
query(),insert(),update(),delete(),getType(),onCreate()等。
二、URI(统一资源标识符)的使用方法

为系统的每一个资源给其一个名字,比方说通话记录。
1、每一个ContentProvider都拥有一个公共的URI,这个URI用于表示这个ContentProvider所提供的数据。
2、Android所提供的ContentProvider都存放在android.provider包中。 将其分为A,B,C,D
4个部分:



A:标准前缀,用来说明一个Content Provider控制这些数据,无法改变的;"content://"
B:URI 的标识,它定义了是哪个Content Provider提供这些数据。对于第三方应用程序,为了保证URI标识的唯一性,它必须是一个完整的、小写的
类名。这个标识在 元素的 authorities属性中说明:一般是定义该ContentProvider的包.类的名称;"content://hx.android.text.myprovider"
C:路径,不知道是不是路径,通俗的讲就是你要操作的数据库中表的名字,或者你也可以自己定义,记得在使用的时候保持一致就ok了;"content://hx.android.text.myprovider/tablename"
D:如果URI中包含表示需要获取的记录的ID;则就返回该id对应的数据,如果没有ID,就表示返回全部;
"content://hx.android.text.myprovider/tablename/#" #表示数据id
三、ContentProvider的实现过程

自己实现ContentProvider不常见,因为可能不需要和别的应用程序交换数据。使用内置的ContentProvider比较多。
1、定义一个CONTENT_URI常量,提供了访问ContentProvider的标识符。

public static final Uri CONTENT_URI = Uri.parse("content://com.example.codelab.transportationprovider");

其中:content是协议
Com.exmaple.codelab.transportationprovider是类名,包含完整的包名。
Uri.parse将一个字符串转换成Uri类型。

如果Provider包含子表,同样定义包含字表的CONTENT_URI。

content://com.example.codelab.transportationprovider/train

content://com.example.codelab.transportationprovider/air/domestic

content://com.example.codelab.transportationprovider/air/international


然后定义列,确保里面包含一个_id的列。
2、定义一个类,继承ContentProvider。

public class FirstContentProvider extends ContentProvider

先介绍一下ContentProvider用到的UriMatcher。UriMatcher的一个重要的函数是match(Uri uri)。这个函数可以匹配Uri,根据传入的不同Uri返回不同的自定义整形值,以表明Uri访问的不同资源的类型。

例如:

public static final UriMatcher uriMatcher;

static {

uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

uriMatcher.addURI(Book.AUTHORITY, "item", Book.ITEM);

uriMatcher.addURI(Book.AUTHORITY, "item/#", Book.ITEM_ID);

}


这里UriMatcher类型的静态字段是用来匹配传入到ContentProvider中的Uri的类。其构造方法传入的匹配码是使用match()方法匹配根路径时返回的值,这个匹配码可以为一个大于零的数表示匹配根路径或传入-1,即常量UriMatcher.NO_MATCH表示不匹配根路径。
addURI()方法是用来增加其他URI匹配路径的,第一个参数传入标识ContentProvider的AUTHORITY字符串。第二个参数传入需要匹配的路径,这里的#号为通配符,代表匹配任意数字,另外还可以用*来匹配任意文本。第三个参数必须传入一个大于零的匹配码,用于match()方法对相匹配的URI返回相对应的匹配码。
例如:sMatcher.addURI(“com.test.provider.personprovider”, “person”, 1);如果match()方法匹配content://com.test.provider.personprovider/person路径,返回匹配码为1。

3、实现query,insert,update,delete,getType和onCreate方法。

4、在AndroidManifest.xml当中进行声明。

<!-- android:name是完成ContentProvider类的全称

android:authorities是和FirstProvidermetaData中的常量AUTHORITY的值一样,否则会报错

-->

<provider android:name="com.bj.FirstContentProvider"

android:authorities="com.bj.firstcontentprovider"

/>


四、具体代码

Activity19Activity.java

public
class

Activity19Activity
extends

Activity {

private
Button
queryButton =
null
;

private
Button
insertButton =
null
;

@Override

public
void

onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);
setContentView(R.layout.main);

queryButton
= (Button) this.findViewById(R.id.query);

queryButton.setOnClickListener(newQueryListener());

insertButton
= (Button) this.findViewById(R.id.insert);

insertButton.setOnClickListener(newInsertListener());

System.out.println(getContentResolver().getType(FirstProvidermetaData.UserTableMetaData.CONTENT_URI));
}

class
InsertListener
implements
OnClickListener {

@Override

public
void

onClick(View v) {

//
TODOAuto-generated method stub
ContentValues values =
new
ContentValues();
values.put(FirstProvidermetaData.UserTableMetaData.USER_NAME,

"michal");
Uri uri = getContentResolver()
.insert(
FirstProvidermetaData.UserTableMetaData.CONTENT_URI,
values);
System.out.println("uri--->"
+ uri.toString());
}

}

class
QueryListener
implements
OnClickListener {

public
void

onClick(View v) {

Cursor c = getContentResolver().query(
FirstProvidermetaData.UserTableMetaData.CONTENT_URI,
null,

null,
null,
null);

while
(c.moveToNext()) {
System.out.println(c.getString(c.getColumnIndex("username")));

}

}
}
}

FirstContentProvider.java

public
class

FirstContentProvider
extends
ContentProvider {

//
当别的程序来访问这个ContentProvider,是通过Uri来访问的,UriMatcher检查是否符合标准

//
uri起一个规则,返回数字


public
static
final

UriMatcher uriMatcher;

//
下面定义两个规则


public
static
final
int

INCOMING_USER_COLLECTION
= 1;

public
static
final
int

INCOMING_USER_SINGLE
= 2;

private
DatabaseHelper
dh;

static
{//下面的users前面不能加/

uriMatcher
= new
UriMatcher(UriMatcher.NO_MATCH);

uriMatcher.addURI(FirstProvidermetaData.AUTHORITY,
"users",

INCOMING_USER_COLLECTION);

uriMatcher.addURI(FirstProvidermetaData.AUTHORITY,
"users/#",

INCOMING_USER_SINGLE);
}

//有点类似于sql里面表的别名,这个也是给列其别名,必须要用
//列的别名还是原来的名,没必要修改

public
static

HashMap<String,String>
userProjectionMap;

static{

userProjectionMap
= newHashMap<String,String>();

userProjectionMap.put(UserTableMetaData._ID,
UserTableMetaData._ID
);

userProjectionMap.put(UserTableMetaData.USER_NAME,
UserTableMetaData.USER_NAME);
}

@Override

public
int

delete(Uri uri, String selection, String[] selectionArgs) {

//
TODOAuto-generated method stub
System.out.println("delete");

return
0;
}

//
根据传入的URI,返回该URI所表示的数据类型

//
也就是说,我们通过URI要访问的数据,返回什么类型


@Override

public
String getType(Uri uri) {

//
TODOAuto-generated method stub
System.out.println("getType");

switch
(uriMatcher.match(uri)) {

case
INCOMING_USER_COLLECTION:

// UserTableMetaData是FirstProvidermetaData的内部类

return
UserTableMetaData.CONTENT_TYPE;

case
INCOMING_USER_SINGLE:

return
UserTableMetaData.CONTENT_TYPE_ITEM;

default:

throw
new

IllegalArgumentException("Unknown uri"
+ uri);
}
}

@Override

public
Uri insert(Uri uri, ContentValues values) {

//
TODOAuto-generated method stub
System.out.println("insert");
SQLiteDatabase db =
dh.getWritableDatabase();

//返回表中自动增长的列的值,否则返回-1

long
rowId = db.insert(UserTableMetaData.TABLE_NAME,null,
values);

if(rowId>0){

//将rowId追加到后面
//contentUris:用来处理Uri的工具类
Uri insertedUserUri = ContentUris.withAppendedId(UserTableMetaData.CONTENT_URI,
rowId);

//通知监听器,数据已经改变
getContext().getContentResolver().notifyChange(insertedUserUri,
null);

return
insertedUserUri;
}

throw
new

SQLException("Failed to insert row into "+uri);
}

//是一个回调方法,所以说在ContentProvider创建的时候执行
//也就是创建这个DatabaseHelper对象

@Override

public
boolean

onCreate() {

//
TODOAuto-generated method stub

//getContext得到当前正在运行着的context

dh
= new
DatabaseHelper(getContext(),FirstProvidermetaData.DATABASE_NAME);
System.out.println("on
create");
SQLiteDatabase
db =
dh.getReadableDatabase();

return
true
;
}

//projection:查询的列有哪些
//selection:where子句的内容,可以用?
//selectionArgs:占位符对应的参数
//sortOrder:排序

@Override

public
Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {

//
TODOAuto-generated method stub
System.out.println("query");

//创建一个查询的语句
SQLiteQueryBuilder qb =
new
SQLiteQueryBuilder();

switch(uriMatcher.match(uri)){

case
INCOMING_USER_COLLECTION:

//设置查询哪张表
qb.setTables(UserTableMetaData.TABLE_NAME);
qb.setProjectionMap(userProjectionMap);

break;

case
INCOMING_USER_SINGLE:
qb.setTables(UserTableMetaData.TABLE_NAME);
qb.setProjectionMap(userProjectionMap);

//添加where条件,getPathSegments:得到uri的path部分content:XXX/user/1,get(1)得到1
qb.appendWhere(UserTableMetaData._ID+"="+uri.getPathSegments().get(1));

break;
}

String orderBy;

if(TextUtils.isEmpty(sortOrder)){
orderBy = UserTableMetaData.DEFAULT_SORT_ORDER;
}

else
{
orderBy = sortOrder;
}
SQLiteDatabase db =
dh.getWritableDatabase();

//下面的query使用qb这个对象
Cursor c = qb.query(db, projection, selection, selectionArgs,
null,
null, orderBy);

//也是通知下
c.setNotificationUri(getContext().getContentResolver(), uri);
System.out.println("query");

return
c;
}

@Override

public
int

update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {

//
TODOAuto-generated method stub

return
0;
}

}
FirstProvidermetaData.java

public
class

FirstProvidermetaData {

public
static
final

String AUTHORITY="com.bj.firstcontentprovider";
//继承了contentprovider的类的全名
//数据库名称

public
static
final

String DATABASE_NAME
=
"FirstProvider.db";

//数据库的版本

public
static
final
int

DATABASE_VERSION
= 1;

//表名

public
static
final

String USERS_TABLE_NAME
=
"users";

public
static
final
class

UserTableMetaData
implements

BaseColumns{

//表名

public
static
final

String TABLE_NAME="users";

//访问该ContentProvider的URI

public
static
final

Uri CONTENT_URI=Uri.parse("content://"+AUTHORITY+"/users");

public
static
final

String CONTENT_TYPE="vnd.android.cursor.dir/vnd.firstprovider.user";

public
static
final

String CONTENT_TYPE_ITEM="vnd.android.cursor.item/vnd.firstprovider.user";

//列名,在users表中添加一个名为name的列

public
static
final

String USER_NAME="name";

//默认排序方式

public
static
final

String DEFAULT_SORT_ORDER="_id
desc";
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: