一.ContentProvider实例
1.创建ContentProvider
package com.example.testapplication.ContentProvider;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.example.testapplication.db.MyDataBaseHelper;
public class MyProvider extends ContentProvider {
//定义上下文
private Context mContext;
//创建数据库操作工厂
MyDataBaseHelper mDbHelper = null;
//创建数据库操作对象
SQLiteDatabase db = null;
//设置ContentProvider的唯一标识
//采用包名的形式创建contentprovider的唯一标识
public static final String AUTOHORITY = "com.example.testapplication.ContentProvider";
//创建user表的编号
public static final int User_Code = 1;
//创建job表的编号
public static final int Job_Code = 2;
//UriMatcher类使用:在ContentProvider中注册URI
//创建UriMatcher对象用于注册uri来暴漏contentprovider的对外接口
private static final UriMatcher mMatcher;
static{
//初始化
mMatcher = new UriMatcher(UriMatcher.NO_MATCH);
//若URI资源路径 = content://com.example.testapplication.ContentProvider/user ,则返回注册码User_Code
//param1:自己定义的唯一标识,param2:“表名”,param3:区分uri的代码
mMatcher.addURI(AUTOHORITY,"user", User_Code);
//若URI资源路径 = content://com.example.testapplication.ContentProvider/job ,则返回注册码Job_Code
mMatcher.addURI(AUTOHORITY, "job", Job_Code);
}
//初始化ContentProvider
@Override
public boolean onCreate() {
//获取上下文
mContext = getContext();
//在ContentProvider创建时对数据库进行初始化
//运行在主线程,故不能做耗时操作,此处仅作展示
mDbHelper = new MyDataBaseHelper(mContext);
db = mDbHelper.getWritableDatabase();
//先清空user表,然后再向user表中插入两条数据
db.execSQL("delete from user");
db.execSQL("insert into user values(1,'Carson');");
db.execSQL("insert into user values(2,'Kobe');");
//先清空job表,然后再向job表中插入两条信息
db.execSQL("delete from job");
db.execSQL("insert into job values(1,'Android');");
db.execSQL("insert into job values(2,'iOS');");
return true;
}
@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection,
@Nullable String[] selectionArgs, @Nullable String sortOrder) {
//根据URI匹配 URI_CODE,从而匹配ContentProvider中相应的表名
String table = getTableName(uri);
//table:表名,如果是多表联查,可以将两个表之间加逗号,projection:查询表的对应字段
//projection:查询表中的字段
//selectionArgs:对应于selection语句中的占位符的值,值在数组中的位置与占位符在语句中的位置必须一致,否则报异常
//groupBy:相当于select语group by 后面的关键字
//having:相当于select语句having关键字后面的部分
//orderBy:相当于order by关键字后面的部分
//limit:指定偏移量和获取的记录数,相当于select语句limit关键字后面的部分
return db.query(table,projection,selection,
selectionArgs,null,null,sortOrder,null);
}
@Nullable
@Override
public String getType(@NonNull Uri uri) {
return null;
}
@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
//根据URI匹配 URI_CODE,从而匹配ContentProvider中对应的表名
String table = getTableName(uri);
//向该表中添加数据
db.insert(table,null,values);
//当该UIR的ContentProvider数据发生变化时,通知外界(即访问该ContentProvider数据的访问者)
//其他使用该uri的应用可以通过getContentRes
mContext.getContentResolver().notifyChange(uri,null);
return uri;
}
@Override
public int delete(@NonNull Uri uri, @Nullable String selection,
@Nullable String[] selectionArgs) {
return 0;
}
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection,
@Nullable String[] selectionArgs) {
return 0;
}
/*
*根据URI匹配 URI_CODE,从而匹配ContentProvider中相应的表名
* */
private String getTableName(Uri uri){
String tableName = null;
//mMatcher.match(uri)返回值为注册uri时对应的代码
switch (mMatcher.match(uri)){
case User_Code:
//自己在数据库创建类中自己定义的表名
tableName = mDbHelper.USER_TABLE_NAME;
break;
case Job_Code:
//自己在数据库创建类中自己定义的表名
tableName = mDbHelper.JOB_TABLE_NAME;
break;
}
return tableName;
}
}
2.注册ContentProvider
<!--创建自己的provider-->
<!--authorities是自己在创建ContentProvider中自定义的唯一标识,通常是包名+类名-->
<provider android:name=".ContentProvider.MyProvider"
android:authorities="com.example.testapplication.ContentProvider"
/>
3.通过uri调用处理数据
//获取指向数据库中user表的uri
Uri uri_user = Uri.parse("content://com.example.testapplication.ContentProvider/user");
//创建与数据库进行数据传递的容器
ContentValues contentValues = new ContentValues();
contentValues.put("_id",3);
contentValues.put("name","zhangyi");
//获取连接ContentProvider暴漏接口的操作对象ContentResolver
ContentResolver contentResolver = getContentResolver();
//通过contentResolver向数据库里插入一条数据
contentResolver.insert(uri_user,contentValues);
//定义查询user表的字段
String[] columns = {"_id","name"};
//通过contentResolver从数据库中查询数据
Cursor users = contentResolver.query(uri_user, columns,
null, null, null);
//打印获取到的信息
//getInt("索引"),索引是表字段的索引位置,从"0"开始,获取字段值
while (users.moveToNext()){
Log.d(TAG, "onClick: "+"\n"+users.getInt(0)+"\n"+users.getString(1));
}
4.总结
相关联的类:
SQLiteOpenHelper ContentProvider UriMatcher Uri
ContentValues ContentResolver Cursor
SQLiteOpenHelper:db操作的核心对象,主要用途,创建数据库,创建表,对表进行一系列的操作
ContentProvider:让不同进程之间共享数据,通过Uri暴露出接口,不同进程之间访问相同的uri接口,
实现数据共享。
UriMatcher:对uri进行注册,将接口暴露出来
Uri:是统一资源路径,通过uri指定到对应共享数据的位置
ContentValues:与共享数据交换信息的容器,类似于map,数据是以键值对的形式存储到容器当中的
ContentResolver:其他线程访问数据的核心类,通过这个类,再连接到ContentProvider类中,
实现对数据的操作,通过uri进行定位数据位置
Cursor:游标,通过contentResolver查询数据后的返回值,默认位置不在第一个索引,在-1,
所以每次获取数据时需要将游标指到指定的位置,使用moveToNext()方法将初始的游标移到0索引处,
moveToFirst()方法将游标指向第一个索引处