【Android高级架构师系统学习文章】Android基础-ContentProvider全方位解析

switch (matcher.match(uri)) {
// 根据URI匹配的返回码是URI_CODE_a
// 即matcher.match(uri) == URI_CODE_a
case URI_CODE_a:
return tableNameUser1;
// 如果根据URI匹配的返回码是URI_CODE_a,则返回ContentProvider中的名为tableNameUser1的表
case URI_CODE_b:
return tableNameUser2;
// 如果根据URI匹配的返回码是URI_CODE_b,则返回ContentProvider中的名为tableNameUser2的表
}
}

4.7 ContentObserver类

  • 定义:内容观察者

  • 作用:观察 Uri引起ContentProvider 中的数据变化 & 通知外界(即访问该数据访问者)

ContentProvider 中的数据发生变化(增、删 & 改)时,就会触发该 ContentObserver

  • 具体使用

// 步骤1:注册内容观察者ContentObserver
getContentResolver().registerContentObserver(uri);
// 通过ContentResolver类进行注册,并指定需要观察的URI

// 步骤2:当该URI的ContentProvider数据发生变化时,通知外界(即访问该ContentProvider数据的访问者)
public class UserContentProvider extends ContentProvider {
public Uri insert(Uri uri, ContentValues values) {
db.insert(“user”, “userid”, values);
getContext().getContentResolver().notifyChange(uri, null);
// 通知访问者
}
}

// 步骤3:解除观察者
getContentResolver().unregisterContentObserver(uri);
// 同样需要通过ContentResolver类进行解除

至此,关于ContentProvider的使用已经讲解完毕

五、 实例说明

  • 由于ContentProvider不仅常用于进程间通信,同时也适用于进程内通信

  • 所以本实例会采用ContentProvider讲解:

  1. 进程内通信
  2. 进程间通信
  • 实例说明:采用的数据源是Android中的SQLite数据库

5.1 进程内通信

  • 步骤说明:
  1. 创建数据库类
  2. 自定义 ContentProvider 类
  3. 注册 创建的 ContentProvider
  4. 进程内访问 ContentProvider的数据
  • 具体使用

步骤1:创建数据库类
DBHelper.java

public class DBHelper extends SQLiteOpenHelper {

// 数据库名
private static final String DATABASE_NAME = “finch.db”;

// 表名
public static final String USER_TABLE_NAME = “user”;
public static final String JOB_TABLE_NAME = “job”;

private static final int DATABASE_VERSION = 1;
//数据库版本号

public DBHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}

@Override
public void onCreate(SQLiteDatabase db) {

// 创建两个表格:用户表 和职业表
db.execSQL(“CREATE TABLE IF NOT EXISTS " + USER_TABLE_NAME + “(_id INTEGER PRIMARY KEY AUTOINCREMENT,” + " name TEXT)”);
db.execSQL(“CREATE TABLE IF NOT EXISTS " + JOB_TABLE_NAME + “(_id INTEGER PRIMARY KEY AUTOINCREMENT,” + " job TEXT)”);
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

}
}

步骤2:自定义 ContentProvider 类

public class MyProvider extends ContentProvider {

private Context mContext;
DBHelper mDbHelper = null;
SQLiteDatabase db = null;

public static final String AUTOHORITY = “cn.scu.myprovider”;
// 设置ContentProvider的唯一标识

public static final int User_Code = 1;
public static final int Job_Code = 2;

// UriMatcher类使用:在ContentProvider 中注册URI
private static final UriMatcher mMatcher;

static {
mMatcher = new UriMatcher(UriMatcher.NO_MATCH);
// 初始化
mMatcher.addURI(AUTOHORITY, “user”, User_Code);
mMatcher.addURI(AUTOHORITY, “job”, Job_Code);
// 若URI资源路径 = content://cn.scu.myprovider/user ,则返回注册码User_Code
// 若URI资源路径 = content://cn.scu.myprovider/job ,则返回注册码Job_Code
}

// 以下是ContentProvider的6个方法

/**

  • 初始化ContentProvider
    */
    @Override
    public boolean onCreate() {

mContext = getContext();
// 在ContentProvider创建时对数据库进行初始化
// 运行在主线程,故不能做耗时操作,此处仅作展示
mDbHelper = new DBHelper(getContext());
db = mDbHelper.getWritableDatabase();

// 初始化两个表的数据(先清空两个表,再各加入一个记录)
db.execSQL(“delete from user”);
db.execSQL(“insert into user values(1,‘Carson’);”);
db.execSQL(“insert into user values(2,‘Kobe’);”);

db.execSQL(“delete from job”);
db.execSQL(“insert into job values(1,‘Android’);”);
db.execSQL(“insert into job values(2,‘iOS’);”);

return true;
}

/**

  • 添加数据
    */
    @Override
    public Uri insert(Uri uri, ContentValues values) {

// 根据URI匹配 URI_CODE,从而匹配ContentProvider中相应的表名
// 该方法在最下面
String table = getTableName(uri);

// 向该表添加数据
db.insert(table, null, values);

// 当该URI的ContentProvider数据发生变化时,通知外界(即访问该ContentProvider数据的访问者)
mContext.getContentResolver().notifyChange(uri, null);

// // 通过ContentUris类从URL中获取ID
// long personid = ContentUris.parseId(uri);
// System.out.println(personid);

return uri;
}

/**

  • 查询数据
    */
    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
    String[] selectionArgs, String sortOrder) {
    // 根据URI匹配 URI_CODE,从而匹配ContentProvider中相应的表名
    // 该方法在最下面
    String table = getTableName(uri);

// // 通过ContentUris类从URL中获取ID
// long personid = ContentUris.parseId(uri);
// System.out.println(personid);

// 查询数据
return db.query(table, projection, selection, selectionArgs, null, null, sortOrder, null);
}

/**

  • 更新数据
    */
    @Override
    public int update(Uri uri, ContentValues values, String selection,
    String[] selectionArgs) {
    // 由于不展示,此处不作展开
    return 0;
    }

/**

  • 删除数据
    */
    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
    // 由于不展示,此处不作展开
    return 0;
    }

@Override
public String getType(Uri uri) {

// 由于不展示,此处不作展开
return null;
}

/**

  • 根据URI匹配 URI_CODE,从而匹配ContentProvider中相应的表名
    */
    private String getTableName(Uri uri) {
    String tableName = null;
    switch (mMatcher.match(uri)) {
    case User_Code:
    tableName = DBHelper.USER_TABLE_NAME;
    break;
    case Job_Code:
    tableName = DBHelper.JOB_TABLE_NAME;
    break;
    }
    return tableName;
    }
    }

步骤3:注册 创建的 ContentProvider类
AndroidManifest.xml

步骤4:进程内访问 ContentProvider中的数据

MainActivity.java

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

/**

  • 对user表进行操作
    */

// 设置URI
Uri uri_user = Uri.parse(“content://cn.scu.myprovider/user”);

// 插入表中数据
ContentValues values = new ContentValues();
values.put(“_id”, 3);
values.put(“name”, “Iverson”);

// 获取ContentResolver
ContentResolver resolver = getContentResolver();
// 通过ContentResolver 根据URI 向ContentProvider中插入数据
resolver.insert(uri_user,values);

// 通过ContentResolver 向ContentProvider中查询数据
Cursor cursor = resolver.query(uri_user, new String[]{“_id”,“name”}, null, null, null);
while (cursor.moveToNext()){
System.out.println(“query book:” + cursor.getInt(0) +" "+ cursor.getString(1));
// 将表中数据全部输出
}
cursor.close();
// 关闭游标

/**

  • 对job表进行操作
    */
    // 和上述类似,只是URI需要更改,从而匹配不同的URI CODE,从而找到不同的数据资源
    Uri uri_job = Uri.parse(“content://cn.scu.myprovider/job”);

// 插入表中数据
ContentValues values2 = new ContentValues();
values2.put(“_id”, 3);
values2.put(“job”, “NBA Player”);

// 获取ContentResolver
ContentResolver resolver2 = getContentResolver();
// 通过ContentResolver 根据URI 向ContentProvider中插入数据
resolver2.insert(uri_job,values2);

// 通过ContentResolver 向ContentProvider中查询数据
Cursor cursor2 = resolver2.query(uri_job, new String[]{“_id”,“job”}, null, null, null);
while (cursor2.moveToNext()){
System.out.println(“query job:” + cursor2.getInt(0) +" "+ cursor2.getString(1));
// 将表中数据全部输出
}
cursor2.close();
// 关闭游标
}
}

结果

5.2 进程间进行数据共享

  • 实例说明:本文需要创建2个进程,即创建两个工程,作用如下

进程1

使用步骤如下:

  1. 创建数据库类
  2. 自定义 ContentProvider 类
  3. 注册 创建的 ContentProvider 类

前2个步骤同上例相同,此处不作过多描述,此处主要讲解步骤3.

步骤3:注册 创建的 ContentProvider类
AndroidManifest.xml

<provider
android:name=“MyProvider”
android:authorities=“scut.carson_ho.myprovider”

// 声明外界进程可访问该Provider的权限(读 & 写)
android:permission=“scut.carson_ho.PROVIDER”

// 权限可细分为读 & 写的权限
// 外界需要声明同样的读 & 写的权限才可进行相应操作,否则会报错
// android:readPermisson = “scut.carson_ho.Read”
// android:writePermisson = “scut.carson_ho.Write”

// 设置此provider是否可以被其他进程使用
android:exported=“true”

/>

// 声明本应用 可允许通信的权限

// 细分读 & 写权限如下,但本Demo直接采用全权限
//
//

至此,进程1创建完毕,即创建ContentProvider & 数据 准备好了。

进程2

步骤1:声明可访问的权限

AndroidManifest.xml

// 声明本应用可允许通信的权限(全权限)

// 细分读 & 写权限如下,但本Demo直接采用全权限
//
//

// 注:声明的权限必须与进程1中设置的权限对应

步骤2:访问 ContentProvider的类

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
img

总结

找工作是个很辛苦的事情,而且一般周期都比较长,有时候既看个人技术,也看运气。第一次找工作,最后的结果虽然不尽如人意,不过收获远比offer大。接下来就是针对自己的不足,好好努力了。

最后为了节约大家的时间,我把我学习所用的资料和面试遇到的问题和答案都整理成了PDF文档,都可以分享给有需要的朋友,如有需要私信我【资料】或者**【点这里】免费领取**

《Android面试复习资料汇总》

喜欢文章的话请关注、点赞、转发 谢谢!

如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
[外链图片转存中…(img-C7ZmUFvy-1710853730191)]

总结

找工作是个很辛苦的事情,而且一般周期都比较长,有时候既看个人技术,也看运气。第一次找工作,最后的结果虽然不尽如人意,不过收获远比offer大。接下来就是针对自己的不足,好好努力了。

最后为了节约大家的时间,我把我学习所用的资料和面试遇到的问题和答案都整理成了PDF文档,都可以分享给有需要的朋友,如有需要私信我【资料】或者**【点这里】免费领取**

《Android面试复习资料汇总》

喜欢文章的话请关注、点赞、转发 谢谢!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值