内容提供者(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>