Android ContentProvider内容提供者详解

简介: Android ContentProvider内容提供者详解

前言:为什么要有ContentProvider?

ContentProvider 内容提供者:可以实现在不同程序之间数据共享的功能,同时还能够保证被访问的数据的安全性。

ContentProvider的理解

相关的API如下所示

两个重要知识点:

1.数据模型: ConentProvider使用基于数据模型的简单表格来提供其中的数据。 每一行代表一条记录,每一列代表特定类型,和含义的数据

2. Uri :统一资源标识符,比较笼统的定位了资源,不局限于客户端和服务器

结构如下:

下面创建一个应用A,提供数据并创建ContentProvider,供应用B进行增删改查的操作

应用A

1、创建PersonContentProvider类

/**
 * 操作person表的provider类
 */
public class PersonContentProvider extends ContentProvider {
    //用来存放所有合法的Uri容器
    private static UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
    //保存一些合法的Uri
    //content://com.example.customviewproject.personcontentprovider/person  不根据id操作
    //content://com.example.customviewproject.personcontentprovider/person/3 根据id操作
    static {
        uriMatcher.addURI("com.example.customviewproject.personcontentprovider", "/person", 1);
        uriMatcher.addURI("com.example.customviewproject.personcontentprovider", "/person/#", 2);//#匹配任意数字
    }
    private DBHelper dbHelper;
    public PersonContentProvider() {
        Log.i("TAG", "PersonContentProvider() ");
    }
    @Override
    public boolean onCreate() {
        Log.i("TAG", "onCreate() ");
        dbHelper = new DBHelper(getContext());
        return false;
    }
    /**
     * //content://com.example.customviewproject.personcontentprovider/person  不根据id查询
     * //content://com.example.customviewproject.personcontentprovider/person/3 根据id查询
     */
    @Nullable
    @Override
    public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
        Log.i("TAG", "query() ");
        //得到连接对象
        SQLiteDatabase database = dbHelper.getReadableDatabase();
        //1.匹配uri,返回code
        int code = uriMatcher.match(uri);
        //2.如果合法,进行查询
        if (code == 1) {//不根据id查询
            Cursor cursor = database.query("person", projection, selection, selectionArgs, null, null, null);
            return cursor;
        } else if (code == 2) {//根据id查询
            //得到id
            long id = ContentUris.parseId(uri);
            //查询
            Cursor cursor = database.query("person", projection, "_id=?", new String[]{id + ""}, null, null, null);
            return cursor;
        } else {//3.如果不合法,抛出异常
            throw new RuntimeException("查询的URI不合法");
        }
    }
    /**
     * //content://com.example.customviewproject.personcontentprovider/person  插入
     * //content://com.example.customviewproject.personcontentprovider/person/3 根据id插入(没有)
     */
    @Nullable
    @Override
    public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
        Log.i("TAG", "insert() ");
        //得到连接对象
        SQLiteDatabase database = dbHelper.getReadableDatabase();
        //1.匹配uri,返回code
        int code = uriMatcher.match(uri);
        //2.如果合法,进行插入
        if (code == 1) {
            long id = database.insert("person", null, values);
            //将id添加到uri中
            database.close();
            return ContentUris.withAppendedId(uri, id);
        } else {
            database.close();
            throw new RuntimeException("插入的URI不合法");
        }
    }
    /**
     * //content://com.example.customviewproject.personcontentprovider/person  不根据id删除
     * //content://com.example.customviewproject.personcontentprovider/person/3 根据id删除
     */
    @Override
    public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
        Log.i("TAG", "delete() ");
        //得到连接对象
        SQLiteDatabase database = dbHelper.getReadableDatabase();
        //1.匹配uri,返回code
        int code = uriMatcher.match(uri);
        int deleteCount = -1;
        //2.如果合法,进行删除
        if (code == 1) {
            deleteCount = database.delete("person", selection, selectionArgs);
        } else if (code == 2) {
            long id = ContentUris.parseId(uri);
            deleteCount = database.delete("person", "_id=" + id, null);
        } else {
            throw new RuntimeException("删除的URI不合法");
        }
        return deleteCount;
    }
    /**
     * //content://com.example.customviewproject.personcontentprovider/person  不根据id更新
     * //content://com.example.customviewproject.personcontentprovider/person/3 根据id更新
     */
    @Override
    public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
        Log.i("TAG", "update() ");
        //得到连接对象
        SQLiteDatabase database = dbHelper.getReadableDatabase();
        //1.匹配uri,返回code
        int code = uriMatcher.match(uri);
        int deleteCount = -1;
        //2.如果合法,进行更新
        if (code == 1) {//不根据id更新
            deleteCount = database.update("person", values, selection, selectionArgs);
        } else if (code == 2) {
            long id = ContentUris.parseId(uri);
            deleteCount = database.update("person", values, "_id=" + id, null);
        }
        return deleteCount;
    }
    @Nullable
    @Override
    public String getType(@NonNull Uri uri) {
        Log.i("TAG", "getType() ");
        return null;
    }
}

2、在AndroidManifest.xml中注册provider

<!--authorities 自定义:一般是内容提供者类的全类名,全部小写-->
    <!--enabled:表示是否启动内容提供者-->
    <!--exported:表示是否允许该内容提供者接收本程序以外的对数据的操作 默认不允许false-->
        <provider
            android:name=".content.PersonContentProvider"
            android:authorities="com.example.customviewproject.personcontentprovider"
            android:enabled="true"
            android:exported="true" />

当应用A启动后,就会创建PersonContentProvider类对象

打印的日志如下

I/TAG: PersonContentProvider() 
I/TAG: onCreate() 

应用B 通过ContentResolver对应用A中的数据进行增删改查操作

public class MainActivity extends AppCompatActivity {
    private Button btn_query;
    private Button btn_insert;
    private Button btn_delete;
    private Button btn_update;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btn_query = findViewById(R.id.btn_query);
        btn_insert = findViewById(R.id.btn_insert);
        btn_delete = findViewById(R.id.btn_delete);
        btn_update = findViewById(R.id.btn_update);
        btn_query.setOnClickListener(onClickListener);
        btn_insert.setOnClickListener(onClickListener);
        btn_delete.setOnClickListener(onClickListener);
        btn_update.setOnClickListener(onClickListener);
    }
    private final View.OnClickListener onClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            switch (view.getId()) {
                case R.id.btn_query:
                    query();
                    break;
                case R.id.btn_insert:
                    insert();
                    break;
                case R.id.btn_update:
                    update();
                    break;
                case R.id.btn_delete:
                    delete();
                    break;
                default:
                    break;
            }
        }
    };
    /**
     * 通过ContentResolver调用ContentProvider删除一条记录
     */
    private void delete() {
        //1.得到ContentResolver对象
        ContentResolver resolver = getContentResolver();
        //2.调用其insert
        Uri uri = Uri.parse("content://com.example.customviewproject.personcontentprovider/person/2");
        int deleteCount = resolver.delete(uri, null, null);
        Toast.makeText(this, "deleteCount=" + deleteCount, Toast.LENGTH_SHORT).show();
    }
    /**
     * 通过ContentResolver调用ContentProvider更新一条记录
     */
    private void update() {
        //1.得到ContentResolver对象
        ContentResolver resolver = getContentResolver();
        //2.调用其insert
        Uri uri = Uri.parse("content://com.example.customviewproject.personcontentprovider/person/3");
        ContentValues contentValues = new ContentValues();
        contentValues.put("name", "Jack2");
        int updateCount = resolver.update(uri, contentValues, null, null);
        Toast.makeText(this, "updateCount=" + updateCount, Toast.LENGTH_SHORT).show();
    }
    /**
     * 通过ContentResolver调用ContentProvider插入一条记录
     */
    private void insert() {
        //1.得到ContentResolver对象
        ContentResolver resolver = getContentResolver();
        //2.调用其insert
        Uri uri = Uri.parse("content://com.example.customviewproject.personcontentprovider/person");
        ContentValues contentValues = new ContentValues();
        contentValues.put("name", "Jack");
        uri = resolver.insert(uri, contentValues);
        Toast.makeText(this, uri.toString(), Toast.LENGTH_SHORT).show();
    }
    /**
     * 通过ContentResolver调用ContentProvider查询所有记录
     */
    private void query() {
        //1.得到ContentResolver对象
        ContentResolver resolver = getContentResolver();
        //2.调用其query,得到cursor
//        Uri uri = Uri.parse("content://com.example.customviewproject.personcontentprovider/person/1");
        //查询所有
        Uri uri = Uri.parse("content://com.example.customviewproject.personcontentprovider/person");
        Cursor cursor = resolver.query(uri, null, null, null, null);
        //3.取出cursor中的数据,并显示
        while (cursor.moveToNext()) {
            int id = cursor.getInt(0);
            String name = cursor.getString(1);
//            Toast.makeText(this, id + ":" + name, Toast.LENGTH_SHORT).show();
            Log.i("TAG", id + ":" + name);
        }
        cursor.close();
    }
}

效果就不展示了,能对应用A中的数据库表进行CRUD操作

接下来我们通过Content Provider 读取通讯录中所有的联系人姓名:

布局代码就不贴出来了。

主要是Activity代码:

详细注解已经在代码中给出

public class ContentProviderActivity extends AppCompatActivity {
    private TextView tv_phone;
    private String name = ContactsContract.Contacts.DISPLAY_NAME;//获得通讯录中的姓名
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_content_provider);
        tv_phone = findViewById(R.id.tv_phone);
        //显示获取的通讯录信息
        tv_phone.setText(getQueryData());
    }
    private CharSequence getQueryData(){
        //用于保存获取的联系人姓名
        StringBuilder stringBuilder = new StringBuilder();
        ContentResolver resolver = getContentResolver();
        //通过通讯录进行查询
        Cursor cursor = resolver.query(ContactsContract.Contacts.CONTENT_URI,null,null,null,null);
        //获得姓名记录的索引值
        int displayNameIndex = cursor.getColumnIndex(name);
        for (cursor.moveToFirst(); !cursor.isAfterLast() ; cursor.moveToNext()) {
            String display = cursor.getString(displayNameIndex);
            stringBuilder.append(display+"\n");
        }
        cursor.close();
        //返回查询的结果
        return stringBuilder.toString();
    }
}

从通讯录中便获取到了联系人姓名:


目录
相关文章
|
10月前
|
数据库 Android开发 开发者
Android Studio入门之内容共享ContentProvider讲解以及实现共享数据实战(附源码 超详细必看)
Android Studio入门之内容共享ContentProvider讲解以及实现共享数据实战(附源码 超详细必看)
421 0
|
9月前
|
SQL XML Java
Android 这 13 道 ContentProvider 面试题,你都会了吗?
Android 这 13 道 ContentProvider 面试题,你都会了吗?
|
9月前
|
安全 数据库 Android开发
45. 【Android教程】内容提供者 - Content Provider
45. 【Android教程】内容提供者 - Content Provider
116 2
|
10月前
|
存储 安全 Android开发
Android数据存储:请解释ContentProvider是什么,它的主要作用是什么?
ContentProvider是Android的四大组件之一,主要负责结构化数据的管理与共享。它封装数据并提供安全的访问接口,通过URI实现应用间数据的标准化共享。ContentResolver与ContentProvider协作,处理数据的CRUD操作,使得其他应用能方便地调用和操作数据。
75 0
|
10月前
|
数据库 Android开发 Kotlin
android开发,使用kotlin学习ContentProvider
android开发,使用kotlin学习ContentProvider
142 0
|
存储 API 数据库
Android:四大组件之 ContentProvider(外共享数据)
数据库在 Android 当中是私有的,不能将数据库设为 WORLD_READABLE,每个数据库都只能允许创建它的包访问。这意味着只有创建这个数据库的应用程序才可访问它。也就是说不能跨越进程和包的边界,直接访问别的应用程序的数据库。那么如何在应用程序间交换数据呢? 如果需要在进程间传递数据,可以使用 ContentProvider 来实现。
409 0
Android:四大组件之 ContentProvider(外共享数据)
|
Java Android开发
Android 四大组件之ContentProvider 访问通讯录进行增删改查操作
Android 四大组件之ContentProvider 访问通讯录进行增删改查操作
115 0
|
数据库 Android开发 开发者
Android 开发四大组件(Activity、Service、Broadcast Receiver、Content Provider)
Android 开发四大组件(Activity、Service、Broadcast Receiver、Content Provider)
196 0
|
SQL 存储 自然语言处理
Android | ContentProvider 筑基篇 | 牛气冲天新年征文
Android | ContentProvider 筑基篇 | 牛气冲天新年征文
125 0
Android | ContentProvider 筑基篇 | 牛气冲天新年征文
|
API Android开发 对象存储
Android | 使用 ContentProvider 无侵入获取 Context
Android | 使用 ContentProvider 无侵入获取 Context
512 0
Android | 使用 ContentProvider 无侵入获取 Context

热门文章

最新文章

  • 1
    Android历史版本与APK文件结构
  • 2
    【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
  • 3
    【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
  • 4
    【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
  • 5
    【03】微信支付商户申请下户到配置完整流程-微信开放平台创建APP应用-填写上传基础资料-生成安卓证书-获取Apk签名-申请+配置完整流程-优雅草卓伊凡
  • 6
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
  • 7
    Cellebrite UFED 4PC 7.71 (Windows) - Android 和 iOS 移动设备取证软件
  • 8
    escrcpy:【技术党必看】Android开发,Escrcpy 让你无线投屏新体验!图形界面掌控 Android,30-120fps 超流畅!🔥
  • 9
    Android实战经验之Kotlin中快速实现MVI架构
  • 10
    即时通讯安全篇(一):正确地理解和使用Android端加密算法
  • 1
    【03】微信支付商户申请下户到配置完整流程-微信开放平台创建APP应用-填写上传基础资料-生成安卓证书-获取Apk签名-申请+配置完整流程-优雅草卓伊凡
    65
  • 2
    android FragmentManager 删除所有Fragment 重建
    25
  • 3
    Android实战经验之Kotlin中快速实现MVI架构
    42
  • 4
    即时通讯安全篇(一):正确地理解和使用Android端加密算法
    42
  • 5
    escrcpy:【技术党必看】Android开发,Escrcpy 让你无线投屏新体验!图形界面掌控 Android,30-120fps 超流畅!🔥
    46
  • 6
    【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
    157
  • 7
    Cellebrite UFED 4PC 7.71 (Windows) - Android 和 iOS 移动设备取证软件
    55
  • 8
    【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    73
  • 9
    Android历史版本与APK文件结构
    182
  • 10
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    54