内容提供者(Content Provider)是android的四大组件之一,重要性可想而知,一个进程的数据可以被另外一个进程访问(在不同的apk之间可以访问),内容提供者可以跨应用,数据库跨应用的使用场景:一个应用中提供数据给其他应用;允许用户从一个应用中拷贝数据到另一个应用;在整个框架中提供一种自定义的查询建议。如果只在一个应用中使用数据的话使用SQLite,不需要使用Content Provider。
整体思路:创建一个继承SQLiteOpenHelper的DbHelper类,在这个类中声明数据库名称和版本号码,在onCreate方法中写创建表的sql语句并执行,onUpgrade方法中暂时不做任何操作(目前不涉及升级数据库的操作)。创建一个继承ContentProvider的StudentProvider类,在这个类中定义一个默认不匹配的UriMatcher对象,声明两个标志位,声明一个静态代码块,在这个代码块中定义两个匹配规则,定义一个getType方法,在这个方法中根据不同的标记返回不同的类型,在这个类中定义增删改查操作对应的方法,在这些方法中根据不同的标记来执行单条记录和多条记录的操作。创建一个继承AndroidTestCase的MyTest单元测试类,在这个类中定义增删改查方法,在这些方法中定义一个内容解析者,使用内容解析者调用操作数据库的方法。注意:在清单文件AndroidManifest.xml文件中注册内容提供者和注册测试单元。创建另一个工程,在这个工程中将MyTest类复制过来,运行里面的各个方式进行测试。这样就完成了从一个工程向另一个工程中访问数据的操作。
DbHelper.java文件:
public class DbHelper extends SQLiteOpenHelper {
private static String name="mydb.db";
private static int version=1;//初始的版本号是1
public DbHelper(Context context) {
super(context, name, null, version);
// TODO Auto-generated constructor stub
}
@Override
public void onCreate(SQLiteDatabase database) {
// TODO Auto-generated method stub
String sql="create table student (id integer primary key autoincrement ,name varchar(64),address varchar(64))";
database.execSQL(sql);//对数据库表的创建
}
@Override
public void onUpgrade(SQLiteDatabase arg0, int arg1, int arg2) {
// TODO Auto-generated method stub
}
}
StudentProvider.java文件:
//ContentProvider是一个抽象类,需要声明一个类去继承它,分别去重写增删改查的方法
public class StudentProvider extends ContentProvider {
private final String TAG = "StudentProvider";
private DbHelper helper = null;
// 默认是不匹配
private static final UriMatcher URI_MATCHER = new UriMatcher(
UriMatcher.NO_MATCH);
// 声明两个标志位
private static final int STUDENT = 1;// 表示操作单条记录
private static final int STUDENTS = 2;// 表示操作多条记录
// 声明一个静态的代码模块
static {
// 定义了两个匹配规则
URI_MATCHER.addURI(
"com.example.android_contentprovider.StudentProvider",
"student", STUDENTS);
URI_MATCHER.addURI(
"com.example.android_contentprovider.StudentProvider",
"student/#", STUDENT);
}
public StudentProvider() {
// TODO Auto-generated constructor stub
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
// TODO Auto-generated method stub
int count = -1;// 表示影响数据库的行数
try {
int flag = URI_MATCHER.match(uri);
SQLiteDatabase database = helper.getWritableDatabase();
switch (flag) {
case STUDENT:// 单条记录
// delete from student where id=? id是通过客户端传递过来的
long id = ContentUris.parseId(uri);
String where_value = "id=" + id;
if (selection != null && !selection.equals("")) {
where_value += " and " + selection;
}
count = database.delete("student", where_value, selectionArgs);
break;
case STUDENTS:// 多条记录
count = database.delete("student", selection, selectionArgs);
break;
}
} catch (Exception e) {
// TODO: handle exception
}
return count;
}
@Override
public String getType(Uri uri) {
// TODO Auto-generated method stub
int flag = URI_MATCHER.match(uri);
switch (flag) {
case STUDENT:
return "vnd.android.cursor.item/student";
case STUDENTS:
return "vnd.android.cursor.dir/students";
}
return null;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
// TODO Auto-generated method stub
// insert into student() (?,?);
Uri resultUri = null;
int flag = URI_MATCHER.match(uri);// 外部传递进来的uri来匹配内部的规则
switch (flag) {
case STUDENTS:
SQLiteDatabase database = helper.getWritableDatabase();
// 返回插入当前行的行号
long id = database.insert("student", null, values);
resultUri = ContentUris.withAppendedId(uri, id);
break;
}
Log.i(TAG, "-->>" + resultUri.toString());
return resultUri;
}
@Override
public boolean onCreate() {
// TODO Auto-generated method stub
helper = new DbHelper(getContext());
return false;
}
@Override
public Cursor query(Uri uri, String[] arg1, String selection,
String[] selectionArgs, String arg4) {
// TODO Auto-generated method stub
Cursor cursor = null;
try {
SQLiteDatabase database = helper.getReadableDatabase();
int flag = URI_MATCHER.match(uri);// 匹配路径
switch (flag) {
case STUDENT:// 查询返回单条记录
long id = ContentUris.parseId(uri);
String where_value = " id = " + id;
if (selection != null && !selection.equals("")) {
where_value += " and " + selection;
}
cursor = database.query("student", null, where_value,
selectionArgs, null, null, null, null);
break;
case STUDENTS:// 查询返回多条记录
cursor = database.query("student", null, selection,
selectionArgs, null, null, null, null);
break;
}
} catch (Exception e) {
// TODO: handle exception
}
return cursor;
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
// TODO Auto-generated method stub
int count = -1;
try {
// update table set name= ?,address= ? where id = ?
SQLiteDatabase database = helper.getWritableDatabase();
long id = ContentUris.parseId(uri);
int flag = URI_MATCHER.match(uri);
switch (flag) {
case STUDENT:
String where_value = " id= " + id;
if (selection != null && !selection.equals("")) {
where_value += " and " + selection;
}
count = database.update("student", values, where_value,
selectionArgs);
break;
}
} catch (Exception e) {
// TODO: handle exception
}
return count;
}
}
MyTest.java文件:
public class MyTest extends AndroidTestCase {
public MyTest() {
// TODO Auto-generated constructor stub
}
public void insert(){
// 访问内容提供者的步骤:
// 1.需要一个内容解析者
ContentResolver contentResolver=getContext().getContentResolver();
// 使用content://+授权路径 来访问一个内容提供者
Uri url=Uri.parse("content://com.example.android_contentprovider.StudentProvider/student");
ContentValues values=new ContentValues();
values.put("name", "吴孟达");
values.put("address", "香港");
contentResolver.insert(url, values);
}
public void delete(){
// 内容解析者
ContentResolver contentResolver=getContext().getContentResolver();
// 删除第一条记录,在后面需要加/1
// 删除多条记录,后面不加任何东西
Uri url=Uri.parse("content://com.example.android_contentprovider.StudentProvider/student/1");
contentResolver.delete(url, null, null);
}
public void update(){
// 得到一个内容解析者
ContentResolver contentResolver=getContext().getContentResolver();
Uri uri=Uri.parse("content://com.example.android_contentprovider.StudentProvider/student/2");
ContentValues values=new ContentValues();
values.put("name", "美人鱼");
values.put("address", "香港");
contentResolver.update(uri, values, null, null);
}
public void query(){
ContentResolver contentResolver=getContext().getContentResolver();
// 查询单条记录(查询id为2的那条记录):content://com.example.android_contentprovider.StudentProvider/student/2
// 查询多条记录:content://com.example.android_contentprovider.StudentProvider/student
// Uri uri=Uri.parse("content://com.example.android_contentprovider.StudentProvider/student/2");
Uri uri=Uri.parse("content://com.example.android_contentprovider.StudentProvider/student");
// 相当于这样的sql语句:select * from student where id =2;
Cursor cursor=contentResolver.query(uri, null, null, null, null);
while (cursor.moveToNext()) {
System.out.println("-->>"+cursor.getString(cursor.getColumnIndex("name"))+" "+cursor.getString(cursor.getColumnIndex("address")));
}
}
}
AndroidManifest.xml文件:
<instrumentation android:targetPackage="com.example.android_contentprovider" android:name="android.test.InstrumentationTestRunner"></instrumentation>
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<uses-library android:name="android.test.runner"/>
<activity
android:name="com.example.android_contentprovider.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- 定义了一个内容提供者 authorities是授权:包名加类名 android:exported="true"-->
<provider
android:exported="true"
android:name=".StudentProvider" android:authorities="com.example.android_contentprovider.StudentProvider"
></provider>
</application>