ContentProvider

Android程序的主要4部分:

1、Activiyt

2、Broadcast Intent Receiver

3、Service

4、Content Provider

一个ContentProvider类实现了一组标准的方法接口,从而能够让其他的应用保存或读取此ContentProvider的各种数据类型。

下面列举一些常用的接口:

1、query(Uri uri,String[] projection,String selection,String[] selectionArgs,String sortOrder):通过Uri进行查询,返回一个Cursor.

2、insert(Uri uri,ContentValues values):将一组数据插入到Uri指定的地方。

3、update(Uri uri,ContentValues values,String where,String[] selectionArgs):更新Uri指定位置的数据。

4、deleteUri uri,String where,String[] selectionArgs:删除指定Uri并且符合一定条件的数据。

52、ContentResolver

外界程序通过ContentResolver接口可以访问ContentProvider提供的数据,在Activity当中通过getContentResolver()可以得到当前应用ContentResolver实例。其提供的接口与ContentProvider提供的接口对应:

1query(Uri uri,String[] projection,String selection,String[] selectionArgs,String sortOrder):通过Uri进行查询,返回一个Cursor.

2insert(Uri uri,ContentValues values):将一组数据插入到Uri指定的地方。

3update(Uri uri,ContentValues values,String where,String[] selectionArgs):更新Uri指定位置的数据。

4deleteUri uri,String where,String[] selectionArgs:删除指定Uri并且符合一定条件的数据。

【实例】

提供ContentProvider的程序:TestSQLite_2_ContentProvider

对其进行访问访问的程序:TestContentProvider_useStudentData

下面进行分析:

1】要为当前应用程序的私有数据定义URI,就需要专门定义个继承自ContentProvider的类,然后实现各个不同的操作所调用的方法。

首先在该应用程序的某个类中定义所有与数据库操作有关的静态字段,以便打包成jar文件供其他应用程序调用(本例中引用打包好的jar包后会有找不到类的错误,故直接将该类,连同包名一同复制到另一个程序中.

此例子没有新定义一个专门的类来存放这些字段,而是在继承了SQLiteOpenHelper的类StudentData中定义:

package com.shutao.testsqlite2;
public class StudentData extends SQLiteOpenHelper {
/*
 * 分别定义了数据库和表的名称、表中各个字段的名称、数据库的版本号
 */
public final static String DB_NAME = "student";
public final static String TABLE_NAME = "hero";
public final static String SNAME = "name";
public final static String SID = "_id";
public final static int DB_VERSION = 1;
/*
 * AUTHORITY:定义了标识ContentProvider的字符串 ;
 * ITEM和ITEM_ID分别用于UriMatcher(资源标识符匹配器)中对路径item和item/id的匹配号码
 * CONTENT_TYPE和CONTENT_ITEM_TYPE定义了数据的MIME类型。需要注意的是: 单一数据的MIME 类型字符串应该以
 * vnd.android.cursor.item/开头,数据集的MIME类型字符串应该以vnd.android.cursor.dir开头
 * CONTENT_URI定义的是查询当前表数据的content://样式URI
 */
public static final String AUTHORITY = "com.shutao.testsqlite2.provider.studentdata";
public static final int ITEM = 1;
public static final int ITEM_ID = 2;
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.shutao.testsqlite2.studentdata";
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.shutao.testsqlite2.studentdata";
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY
+ "/item");
public StudentData(Context context) {
super(context, DB_NAME, null, DB_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + TABLE_NAME + "(" + SID
+ " VARCHAR PRIMARY KEY," + SNAME + " VARCHAR NOT NULL);");
}
@Override
public void onUpgrade(SQLiteDatabase db, int arg1, int arg2) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
}
}


2】接下来定义一个继承自ContentProvider的类:MyProvider.java,来实现对数据进行操作的各个方法。这里将用到StudentData来辅助得到SQLiteDatabase对象:

package com.shutao.testsqlite2;
public class MyProvider extends ContentProvider {
StudentData sd;
private static final UriMatcher sMatcher;
static {
// 传入匹配码如果大于0表示匹配根路径或传入-1,即常量UriMatcher.NO_MATCH表示不匹配根路径
// addURI()方法是用来增加其他URI匹配路径的:
// 第一个参数代表传入标识ContentProvider的AUTHORITY字符串
// 第二个参数是要匹配的路径,#代表任意数字,另外还可以用*来匹配任意文本
// 第三个参数必须传入一个大于零的匹配码,用于match()方法对相匹配的URI返回相对应的匹配码
sMatcher = new UriMatcher(UriMatcher.NO_MATCH);
sMatcher.addURI(StudentData.AUTHORITY, "item", StudentData.ITEM);
sMatcher.addURI(StudentData.AUTHORITY, "item/#", StudentData.ITEM_ID);
}
/*
 * 每当ContentProvider启动时都会回调onCreate()方法。此方法主要执行一些ContentProvider初始化
 * 的工作,返回true表示初始化成功,返回false则初始化失败。
 */
@Override
public boolean onCreate() {
sd = new StudentData(this.getContext());
return true;
}
// getType()是用来返回数据的MIME类型的方法。使用sMatcher对URI进行匹配,并返回相应的MIME类型字符串
@Override
public String getType(Uri uri) {
switch (sMatcher.match(uri)) {
case StudentData.ITEM:
return StudentData.CONTENT_TYPE;
case StudentData.ITEM_ID:
return StudentData.CONTENT_ITEM_TYPE;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
}
/*
 * 插入数据,返回新插入数据的URI,只接受数据集的URI,即指向表的URI
 */
@Override
public Uri insert(Uri uri, ContentValues values) {
SQLiteDatabase sdb = sd.getWritableDatabase();
long rowId;
if (sMatcher.match(uri) != StudentData.ITEM) {
throw new IllegalArgumentException("Unknow URI " + uri);
}
rowId = sdb.insert(StudentData.TABLE_NAME, StudentData.SID, values);
if (rowId > 0) {
Uri noteUri = ContentUris.withAppendedId(StudentData.CONTENT_URI,
rowId);
this.getContext().getContentResolver().notifyChange(noteUri, null);
return noteUri;
}
throw new SQLException("Failed to insert row into " + uri);
}
/*
 * 用于数据的删除,返回的是所影响数据的数目,首先利用数据库辅助对象获取一个SQLiteDatabase对象
 * 然后根据传入Uri用sMatcher进行匹配,对单个数据或数据集进行删除或修改。notifyChange()方法
 * 用来通知注册在次URI上的观察者(observer)数据发生了改变。
 */
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
SQLiteDatabase sdb = sd.getWritableDatabase();
int count;
switch (sMatcher.match(uri)) {
case StudentData.ITEM:
count = sdb.delete(StudentData.DB_NAME, selection, selectionArgs);
break;
case StudentData.ITEM_ID:
String id = uri.getPathSegments().get(1);
count = sdb.delete(StudentData.DB_NAME, StudentData.SID
+ "="
+ id
+ (!TextUtils.isEmpty(selection) ? " AND (" + selection
+ ")" : ""), selectionArgs);
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
this.getContext().getContentResolver().notifyChange(uri, null);
return count;
}
/*
 * 查询数据,将数据装入一个Cursor对象并返回
 */
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
SQLiteDatabase sdb = sd.getReadableDatabase();
Cursor c;
switch (sMatcher.match(uri)) {
case StudentData.ITEM:
c = sdb.query(StudentData.TABLE_NAME, projection, selection,
selectionArgs, null, null, sortOrder);
break;
case StudentData.ITEM_ID:
String id = uri.getPathSegments().get(1);
c = sdb.query(StudentData.TABLE_NAME, projection, StudentData.SID
+ "="
+ id
+ (!TextUtils.isEmpty(selection) ? " AND (" + selection
+ ")" : ""), selectionArgs, null, null, sortOrder);
break;
default:
Log.i("sMatcher.match(uri)", String.valueOf(sMatcher.match(uri)));
throw new IllegalArgumentException("Query with unknown URI: " + uri);
}
c.setNotificationUri(getContext().getContentResolver(), uri);
return c;
}
// 更新,与删除类方法类似
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
SQLiteDatabase sdb = sd.getWritableDatabase();
int count;
switch (sMatcher.match(uri)) {
case StudentData.ITEM:
count = sdb.update(StudentData.TABLE_NAME, values, selection,
selectionArgs);
break;
case StudentData.ITEM_ID:
String id = uri.getPathSegments().get(1);
count = sdb.update(StudentData.DB_NAME, values, StudentData.SID
+ "="
+ id
+ (!TextUtils.isEmpty(selection) ? " AND (" + selection
+ ")" : ""), selectionArgs);
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
this.getContext().getContentResolver().notifyChange(uri, null);
return count;
}
}


【3】完成以上方法以后,还要AndroidManifest.xml中对这个ContentProvider声明:

<provider

android:name="MyProvider"

android:authorities="com.shutao.testsqlite2.provider.studentdata"/>

 <!-- 其中 android:name必须跟定义的ContentProvider的类名一样

 android:authorities则指定了content://样式的URI中标识这个ContentProvider的字符串-->

【4】接下来在另一个程序中使用ContentResolver来操作数据:

package com.shutao.contentprovider;
public class TestContentProvider extends Activity {
private EditText stu_name;
private EditText stu_sid;
Button commit;
ListView studList;
ContentResolver resolver;
// 由于在AlertDialog中用到,所以定义为全局变量。
String sid = "";
private final int DIALOG_IN_USED = 1;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
stu_name = (EditText) this.findViewById(R.id.edit_name);
stu_sid = (EditText) this.findViewById(R.id.edit_sid);
commit = (Button) this.findViewById(R.id.butt_add);
studList = (ListView) this.findViewById(R.id.show_stud);
//【重要】得到ContentResolver()
resolver = this.getContentResolver();
String[] projection = { StudentData.SNAME, StudentData.SID };
Cursor c = resolver.query(StudentData.CONTENT_URI, null, null, null,
StudentData.SID);
CursorAdapter adapter = new SimpleCursorAdapter(this,
android.R.layout.simple_list_item_2, c, projection, new int[] {
android.R.id.text1, android.R.id.text2 });
studList.setAdapter(adapter);
commit.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (!(stu_name.getText().length() > 0)) {
Toast.makeText(TestContentProvider.this,
"Please input the student's name!",
Toast.LENGTH_LONG).show();
} else if (!(stu_sid.getText().length() > 0)) {
Toast
.makeText(TestContentProvider.this,
"Please input the student's ID!",
Toast.LENGTH_LONG).show();
} else {
String name = stu_name.getText().toString();
sid = stu_sid.getText().toString();
Uri quri = Uri.parse(StudentData.CONTENT_URI + "/" + sid);
Cursor c = resolver.query(quri, null, null, null, null);
if (c.moveToFirst()) {
// 采用Toast方式提醒
/*
 * Toast.makeText(TestContentProvider.this,
 * "Fail to add!This ID is already in used!",
 * Toast.LENGTH_LONG).show();
 */
// 采用AlertDialog方式提醒
TestContentProvider.this.showDialog(DIALOG_IN_USED);
} else {
ContentValues values = new ContentValues();
values.put(StudentData.SNAME, name);
values.put(StudentData.SID, sid);
resolver.insert(StudentData.CONTENT_URI, values);
}
}
}
});
}
//如果插入的Id已经存在则用提示框进行提示
@Override
protected Dialog onCreateDialog(int id, Bundle args) {
// // TODO Auto-generated method stub
// return super.onCreateDialog(id, args);
switch (id) {
case DIALOG_IN_USED:
return new AlertDialog.Builder(this).setTitle("Fail to add!")
.setIcon(R.drawable.fail).setMessage(
"This ID:" + sid + " is already in used!")
.setPositiveButton("确定",
// 特别注意:必须为:new DialogInterface.OnClickListener()
// 不能为new
// OnClickListener(),否则会跟View.OnClickListener冲突。
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog,
int which) {
// TODO Auto-generated method stub
}
}).create();
default:
return super.onCreateDialog(id, args);
}
}
}


53ContentProviderContentResolver中用到的Uri

【注】:ContentProviderContentResolver当中用到了Uri的形式通常有两种,一种是指定全部数据,另一种是指定某个ID的数据,如:

1、content://contacts/people/:这个Uri指定的就是全部联系人的数据。

2、content://contacts/people/1:这个Uri指定的就是ID1的联系人的数据。

Uri一般由3部分组成:

1、"content://"

2、要获得数据的一个字符串片段

3、最后就是ID,如果没有ID则返回全部数据。

但因为URI通常比较长,容易出错,所以在Android当中定义了一些辅助类,并定义了一些常量来代替这些这些字符串的使用,如:

Contacts.People.CONTENT_URI:联系人的URI.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值