数据共享之ContentReslover类精炼详解

一、前期基础知识储备

跨程序共享数据,跨程序共享数据,跨程序共享数据,重要的事情说三遍,不是跨线程,也不是跨进程,而是跨程序。可能,我们会有些疑惑,为什么要将我们程序中的数据共享给其他程序呢?当然,这个是要视情况决定的,像一些重要的数据,隐私数据是不能共享的。但是有一些可以让其他程序进行二次开发的基础性数据,我们还是可以选择共享的。

例如系统的电话簿程序,它的数据库中保存的很多联系人的数据,如果这些数据都不允许第三方程序进行访问的话,恐怕很多应用的功能都要大打折扣了。比如,现在很火的短视频软件——某抖音,某快手,某西瓜等等,这些应用在使用的时候都会请求运行时权限,向用户申请读取电话簿联系人的权限,以便更好的提供服务(发现你电话簿里的人的视频,然后推荐给你),更不用说一些社交软件某QQ早就申请好权限,读取你的联系人数据,然后定向添加好友。当然了除了电话簿之外,还有短息、媒体库等程序都实现了跨程序数据共享的功能,而使用的技术就是内容提供者ContentProvider内容解析者ContentReslover

二、内容解析者(ContentReslover)精炼详解

内容提供者(ContentProvider)主要用于在不同的应用程序之间实现数据共享的功能,它提供了一套完整的机子,允许一个程序访问另一个程序中的数据,同时还能保证被访数据的安全性。目前,使用内容提供器是Android实现跨程序共享数据的标准方式。

不同于文件存储和SharedPreferences存储中的两种全局可读写操作模式,内容提供器可以选择只对哪一部分数据进行共享,从而保证我们程序中的隐私数据不会有泄漏的风险。

(1)两个类的区分——ContentProvider类和ContentResolver作为AndroidF4君之一,普通的手机用户可能对其了解的不多,也使用的不多,但对于像笔者这种爱好学习的人(小吹一波)来说,内容提供者和内容解决者简直就是福音。比如,我用某百度网盘应用下载了一篇精彩的文章,但是我却想用某WPS应用(界面更加熟悉操作更加简便)来阅读它;又比如我用某迅雷下载了一部最新的电影,但是我又想用某优酷(实际上我肯定用的是某迅雷影音)打开它;像这种操作得以实现的基础就是Android四大组件——内容提供者的作用,与优质的用户体验相关。

仔细感受的读者,会发现其实上面是涉及到了两个应用,跨程序,一个应用提供内容,一个应用读取和操作内容,Android分别分别提供两个类来做以上的两件事,ContentProvider类用来作为内容提供者,提供内容,像上面举例的某百度网盘和某迅雷就是拥有这个类;而ContentResolver类用来作为内容读取者和操作者,像上面举例的某WPS和某优酷就是拥有这个类。

(2)本篇文章只对ContentResolver类进行详细讲解

①上官方文档,仔细看描述

ContentProvider可以理解为一个Android应用对外开放的接口,只要是符合它所定义的Uri格式的请求,均可以正常访问执行操作。其他的Android应用可以使用ContentResolver对象通过与ContentProvider同名的方法请求执行,被执行的就是ContentProvider中的同名方法。所以ContentProvider有很多对外可以访问的方法,在ContentResolver中均有同名的方法,是一一对应的,来看 下面这一张图:

 

②上代码,具体实现

public class MainActivity extends AppCompatActivity {

    private String newId;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button addData = (Button) findViewById(R.id.add_data);
        addData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 添加数据
                Uri uri = Uri.parse("content://com.example.databasetest.provider/book");
                ContentValues values = new ContentValues();
                values.put("name", "A Clash of Kings");
                values.put("author", "George Martin");
                values.put("pages", 1040);
                values.put("price", 55.55);
                Uri newUri = getContentResolver().insert(uri, values);
                newId = newUri.getPathSegments().get(1);
            }
        });
        Button queryData = (Button) findViewById(R.id.query_data);
        queryData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 查询数据
                Uri uri = Uri.parse("content://com.example.databasetest.provider/book");
                Cursor cursor = getContentResolver().query(uri, null, null, null, null);
                if (cursor != null) {
                    while (cursor.moveToNext()) {
                        String name = cursor.getString(cursor. getColumnIndex("name"));
                        String author = cursor.getString(cursor. getColumnIndex("author"));
                        int pages = cursor.getInt(cursor.getColumnIndex ("pages"));
                        double price = cursor.getDouble(cursor. getColumnIndex("price"));
                        Log.d("MainActivity", "book name is " + name);
                        Log.d("MainActivity", "book author is " + author);
                        Log.d("MainActivity", "book pages is " + pages);
                        Log.d("MainActivity", "book price is " + price);
                    }
                    cursor.close();
                }
            }
        });
        Button updateData = (Button) findViewById(R.id.update_data);
        updateData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 更新数据
                Uri uri = Uri.parse("content://com.example.databasetest.provider/book/" + newId);
                ContentValues values = new ContentValues();
                values.put("name", "A Storm of Swords");
                values.put("pages", 1216);
                values.put("price", 24.05);
                getContentResolver().update(uri, values, null, null);
            }
        });
        Button deleteData = (Button) findViewById(R.id.delete_data);
        deleteData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 删除数据
                Uri uri = Uri.parse("content://com.example.databasetest.provider/book/" + newId);
                getContentResolver().delete(uri, null, null);
            }
        });
    }

}

③上述代码解析:对于每一个具体的应用程序来说,如果想要访问内容提供者中共享的数据,就一定要借助ContentResolver类,可以通过Context中的getContentResolver()方法获取到该类的实例。ContentResolver类中提供了一系列的方法用于对数据进行CRUD操作,其中insert()方法用于添加数据,update()方法用于更新数据,delete()方法用于删除数据,query()方法用于查询数据,类似于SQLite数据库中对于数据的操作。然后在ContentProvider类中也对应的实现这四个方法,达到ContentReslover中调用时可以直接在ContentProvider中调用相对应的方法进行共享数据的操作。

不同于SQLiteDataBase,ContentReslover使用一个Uri参数来实现增删改查方法,这个参数被称为内容URI。内容URI给内容提供者中的数据建立了唯一标识符(ContentProvider中会通过URI定义可以共享出去的数据)。它主要由两部分组成:包名+路径名比如某个应用程序的包名是com.example.app,那么改程序对应的com.exampe.app.provider,路径则是用于对同个应用中的不同表作区分:table1/table2,组合一下就得到了需要访问共享数据的内容URIcom.exampe.app.provider/table1, com.exampe.app.provider/table2,最后在字符串的头部加上协议声明即可。内容URI的标准写法:contnet//com.exampe.app.provider/table1

contnet//com.exampe.app.provider/table2

在得到内容URI字符串之后,我们还需要将它解析成Uri对象才可以作为参数,参入上面的讲的CRUD四种方法里面,解析的方法也很简单:

Uri uri = Uri.parse(contnet//com.exampe.app.provider/table2);

得到uri对象之后,在分别传入insert(),update(),delete(),query()方法中,进行指定的操作。

小结:做到这里,ContentReslover类就定义好了,相当于调用程序中的内容解析者就定义好了,只要对应的应用程序中定义好了内容提供者,即实现了至少ContentReslover类中的方法,就可以将内容提供者和内容解析者定义的方法一一对应起来,最终达到通过内容解析者ContentReslover读取和操作内容提供者ContentProvider提供的共享数据的目的。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值