安卓存储数据和文件系列4:内容提供者(Content Provider)方式

时间:2022-08-23 09:18:07

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