当前位置:

首页 > 系统应用 > 4.4.1 ContentProvider初探

4.4.1 ContentProvider初探

Process Lasso 专业版
Process Lasso 专业版

Process Lasso是一款功能Windows进程管理工具,可有效避免电脑出现蓝屏、假死等情况。它更偏向把系统状态查看和常用调节动作放在一起,适合需要持续观察和微调设备状态的场景。

立即下载
¥59
Windows 2026-08-17
正版软件 Windows Process 系统优化工具 专业版 进程管理
本文目录

    本节引言: 这一节要聊的,是 Android 四大组件里的最后一位——ContentProvider(内容提供者)。可能有读者会马上想到:"Android 不是常说有五大组件吗?还有个 Intent 呢?" 这个疑问很正常。没错,Intent 同样非常关键,不过它更像是串联几个组件之间的那条“线”,

    本节引言:

    这一节要聊的,是 Android 四大组件里的最后一位——ContentProvider(内容提供者)。可能有读者会马上想到:"Android 不是常说有五大组件吗?还有个 Intent 呢?" 这个疑问很正常。没错,Intent 同样非常关键,不过它更像是串联几个组件之间的那条“线”,负责把彼此连接起来。至于 Intent,下一章再单独展开。先把话题拉回 ContentProvider,那么,它通常会在什么场景下派上用场?主要有下面这两种:

    • 1.我们想在自己的应用中访问别的应用,或者说一些ContentProvider暴露给我们的一些数据, 比如手机联系人,信息等!我们想对这些数据进行读取或者修改,这就需要用到ContentProvider了!
    • 2.我们自己的应用,想把自己的一些数据暴露出来,给其他的应用进行读取或操作,我们也可以用 到ContentProvider,另外我们可以选择要暴露的数据,就避免了我们隐私数据的的泄露!

    看起来像是个挺“高阶”的东西,其实真上手了并不复杂,接下来就顺着这个思路,把ContentProvider好好梳理一遍。官方文档:ContentProvider。本节会先把ContentProvider的基本概念讲清楚,再结合几个常见的系统ContentProvider使用示例来展开,最后再说到如何自定义ContentProvider。

    1.ContentProvider概念讲解:

    2.使用系统提供的ContentProvider

    其实很多时候我们用到ContentProvider并不是自己暴露自己的数据,更多的时候通过 ContentResolver来读取其他应用的信息,最常用的莫过于读取系统APP,信息,联系人, 多媒体信息等!如果你想来调用这些ContentProvider就需要自行查阅相关的API资料了! 另外,不同的版本,可能对应着不同的URL!这里给出如何获取URL与对应的数据库表的字段, 这里以最常用的联系人为例,其他自行google~
    ①来到系统源码文件下:all-src.rar -> TeleponeProvider -> AndroidManifest.xml查找对应API
    ②打开模拟器的file exploer/data/data/com.android.providers.contacts/databases/contact2.db 导出后使用SQLite图形工具查看,三个核心的表:raw_contact表,data表,mimetypes表!
    下面演示一些基本的操作示例:

    1)简单的读取收件箱信息:

    核心代码:

    private void getMsgs(){
        Uri uri = Uri.parse("content://sms/");
        ContentResolver resolver = getContentResolver();
        //获取的是哪些列的信息
        Cursor cursor = resolver.query(uri, new String[]{"address","date","type","body"}, null, null, null);
        while(cursor.moveToNext())
        {
            String address = cursor.getString(0);
            String date = cursor.getString(1);
            String type = cursor.getString(2);
            String body = cursor.getString(3);
            System.out.println("地址:" + address);
            System.out.println("时间:" + date);
            System.out.println("类型:" + type);
            System.out.println("内容:" + body);
            System.out.println("======================");
        }
        cursor.close();
    }

    别忘了,往AndroidManifest.xml加入读取收件箱的权限:

    运行结果:

    部分运行结果如下:

    2)简单的往收件箱里插入一条信息

    核心代码:

    private void insertMsg() {
        ContentResolver resolver = getContentResolver();
        Uri uri = Uri.parse("content://sms/");
        ContentValues conValues = new ContentValues();
        conValues.put("address", "123456789");
        conValues.put("type", 1);
        conValues.put("date", System.currentTimeMillis());
        conValues.put("body", "no zuo no die why you try!");
        resolver.insert(uri, conValues);
        Log.e("HeHe", "信息插入完毕~");
    }

    运行结果:

    注意事项:

    上述代码在4.4以下都可以实现写入信息的功能,而5.0上就无法写入,原因是: 从5.0开始,默认信息应用外的软件不能以写入信息数据库的形式发信息!

    3)简单的读取手机联系人

    核心代码:

    private void getContacts(){
        //①查询raw_contacts表获得联系人的id
        ContentResolver resolver = getContentResolver();
        Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
        //查询联系人数据
        cursor = resolver.query(uri, null, null, null, null);
        while(cursor.moveToNext())
        {
            //获取联系人姓名,手机号码
            String cName = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
            String cNum = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
            System.out.println("姓名:" + cName);
            System.out.println("号码:" + cNum);
            System.out.println("======================");
        }
        cursor.close();
    }

    别忘了加读联系人的权限:

    运行结果:

    部分运行结果如下:

    4)查询指定电话的联系人信息

    核心代码:

    private void queryContact(String number){
            Uri uri = Uri.parse("content://com.android.contacts/data/phones/filter/" + number);
            ContentResolver resolver = getContentResolver();
            Cursor cursor = resolver.query(uri, new String[]{"display_name"}, null, null, null);
            if (cursor.moveToFirst()) {
                String name = cursor.getString(0);
                System.out.println(number + "对应的联系人名称:" + name);
            }
        cursor.close();
    }

    运行结果:

    5)添加一个新的联系人

    核心代码:

    private void AddContact() throws RemoteException, OperationApplicationException {
        //使用事务添加联系人
        Uri uri = Uri.parse("content://com.android.contacts/raw_contacts");
        Uri dataUri =  Uri.parse("content://com.android.contacts/data");
    ContentResolver resolver = getContentResolver();
        ArrayList operations = new ArrayList();
        ContentProviderOperation op1 = ContentProviderOperation.newInsert(uri)
                .withValue("account_name", null)
                .build();
        operations.add(op1);
    //依次是姓名,号码,邮编
        ContentProviderOperation op2 = ContentProviderOperation.newInsert(dataUri)
                .withValueBackReference("raw_contact_id", 0)
                .withValue("mimetype", "vnd.android.cursor.item/name")
                .withValue("data2", "Coder-pig")
                .build();
        operations.add(op2);
    ContentProviderOperation op3 = ContentProviderOperation.newInsert(dataUri)
                .withValueBackReference("raw_contact_id", 0)
                .withValue("mimetype", "vnd.android.cursor.item/phone_v2")
                .withValue("data1", "13798988888")
                .withValue("data2", "2")
                .build();
        operations.add(op3);
    ContentProviderOperation op4 = ContentProviderOperation.newInsert(dataUri)
                .withValueBackReference("raw_contact_id", 0)
                .withValue("mimetype", "vnd.android.cursor.item/email_v2")
                .withValue("data1", "779878443@qq.com")
                .withValue("data2", "2")
                .build();
        operations.add(op4);
        //将上述内容添加到手机联系人中~
        resolver.applyBatch("com.android.contacts", operations);
        Toast.makeText(getApplicationContext(), "添加成功", Toast.LENGTH_SHORT).show();
    }

    运行结果:

    别忘了权限:

    
    

    3.自定义ContentProvider

    我们很少会自己来定义ContentProvider,因为我们很多时候都不希望自己应用的数据暴露给 其他应用,虽然这样,学习如何ContentProvider还是有必要的,多一种数据传输的方式,是吧~
    这是之前画的一个流程图:

    接下来我们就来一步步实现:

    在开始之前我们先要创建一个数据库创建类(数据库内容后面会讲~):

    DBOpenHelper.ja va

    public class DBOpenHelper extends SQLiteOpenHelper {
    final String CREATE_SQL = "CREATE TABLE test(_id INTEGER PRIMARY KEY AUTOINCREMENT,name)";
    public DBOpenHelper(Context context, String name, CursorFactory factory,
                int version) {
            super(context, name, null, 1);
        }
    @Override
        public void onCreate(SQLiteDatabase db) {
            db.execSQL(CREATE_SQL);
        }
    @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            // TODO Auto-generated method stub
    }
    }

    Step 1:自定义ContentProvider类,实现onCreate(),getType(),根据需求重写对应的增删改查方法:

    NameContentProvider.ja va

    public class NameContentProvider extends ContentProvider {
    //初始化一些常量
         private static UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);        
         private DBOpenHelper dbOpenHelper;
    //为了方便直接使用UriMatcher,这里addURI,下面再调用Matcher进行匹配
    static{  
             matcher.addURI("com.jay.example.providers.myprovider", "test", 1);
         }  
    @Override
        public boolean onCreate() {
            dbOpenHelper = new DBOpenHelper(this.getContext(), "test.db", null, 1);
            return true;
        }
    @Override
        public Cursor query(Uri uri, String[] projection, String selection,
                String[] selectionArgs, String sortOrder) {
            return null;
        }
    @Override
        public String getType(Uri uri) {
            return null;
        }
    @Override
        public Uri insert(Uri uri, ContentValues values) {
    switch(matcher.match(uri))
            {
            //把数据库打开放到里面是想证明uri匹配完成
            case 1:
                SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
                long rowId = db.insert("test", null, values);
                if(rowId > 0)
                {
                    //在前面已有的Uri后面追加ID
                    Uri nameUri = ContentUris.withAppendedId(uri, rowId);
                    //通知数据已经发生改变
                    getContext().getContentResolver().notifyChange(nameUri, null);
                    return nameUri;
                }
            }
            return null;
        }
    @Override
        public int delete(Uri uri, String selection, String[] selectionArgs) {
            return 0;
        }
    @Override
        public int update(Uri uri, ContentValues values, String selection,
                String[] selectionArgs) {
            return 0;
        }
    }

    Step 2:AndroidManifest.xml中为ContentProvider进行注册:

    
    

    好的,作为ContentProvider的部分就完成了!

    接下来,创建一个新的项目,我们来实现ContentResolver的部分,我们直接通过按钮点击插入一条数据:

    MainActivity.ja va

    public class MainActivity extends Activity {
    private Button btninsert;
    @Override
        protected void onCreate(Bundle sa vedInstanceState) {
            super.onCreate(sa vedInstanceState);
            setContentView(R.layout.activity_main);
    btninsert = (Button) findViewById(R.id.btninsert);
    //读取contentprovider 数据  
            final ContentResolver resolver = this.getContentResolver();
    btninsert.setOnClickListener(new OnClickListener() {
    @Override
                public void onClick(View v) {
                     ContentValues values = new ContentValues();
                     values.put("name", "测试");
                     Uri uri = Uri.parse("content://com.jay.example.providers.myprovider/test");
                    resolver.insert(uri, values);
                    Toast.makeText(getApplicationContext(), "数据插入成功", Toast.LENGTH_SHORT).show();
    }
            });
    }
    }

    如何使用? 好吧,代码还是蛮简单的,先运行作为ContentProvider的项目,接着再运行ContentResolver的项目, 点击按钮插入一条数据,然后打开file exploer将ContentProvider的db数据库取出,用图形查看工具 查看即可发现插入数据,时间关系,就不演示结果了~

    4.通过ContentObserver监听ContentProvider的数据变化

    使用指南:

    运行程序后,晾一边,收到信息后,可以在logcat上看到该条信息的内容,可以根据自己的需求 将Activtiy改做Service,而在后台做这种事情~

    本节小结:

    好的,关于ContentProvider的初探就到这里,本节我们学习了: ContentProvider的概念以及流程,使用系统提供的一些ContentProvider,以及定制自己的ContentProvider, 最后还讲解了通过ContentObserver监听ContentProvider的数据变化,ContentProvider的内容就掌握得差不多 了,下一节我们来走走文档看下有什么不知道的~谢谢

    本文内容来源于网友投稿,如有侵权请联系删除。
    作者最新文章
    系统应用 Pro
    相关文章 更多
    win10系统更新推送频繁怎么减少更新提示
    win10系统更新推送频繁怎么减少更新提示

    Windows 10更新弹窗频繁影响工作?无需禁用服务,只需调整活动时间、安排重启和优化通知设置,即可有效减少干扰并保持系统安全。

    win10怎么查看当前系统自动更新有没有被关闭
    win10怎么查看当前系统自动更新有没有被关闭

    想知道Win10自动更新是否被关闭?不要只看任务栏。本文教你通过“设置-更新和安全”、“高级选项”及“services.msc服务”三处位置,准确判断系统更新状态是暂停、运行还是受组织策略管理。

    win10休眠唤醒和开机登录密码可以分开取消吗?
    win10休眠唤醒和开机登录密码可以分开取消吗?

    想知道Win10能否只取消休眠唤醒密码而保留开机密码?本教程详解如何通过系统设置和netplwiz工具,分别控制开机登录与睡眠唤醒后的验证要求,实现灵活的安全策略。

    win10取消开机密码之后如何恢复密码登录
    win10取消开机密码之后如何恢复密码登录

    Win10取消开机密码后想恢复?本教程详解如何通过netplwiz恢复开机输入框、重新设置空密码账户、配置PIN码及调整睡眠唤醒登录策略,步骤清晰,即改即验。

    win10注册表修改怎么取消开机自动登录密码
    win10注册表修改怎么取消开机自动登录密码

    想恢复Win10开机密码保护?本文详解如何通过注册表修改AutoAdminLogon值取消自动登录,配合netplwiz工具复核,避免凭据泄露风险,适合家用及办公场景参考。

    win10电脑一开机就下载更新怎么关闭
    win10电脑一开机就下载更新怎么关闭

    Win10一开机就占用网速下载更新?本文教你通过设置暂停更新、调整活动时间及标记计费网络来缓解干扰。区分家庭版与专业版操作差异,避免强制停止服务带来的系统风险,让更新在合适的时间进行。

    win10取消开机密码时输入密码验证失败怎么解决
    win10取消开机密码时输入密码验证失败怎么解决

    Win10取消开机密码时提示验证失败?可能是因为输错了Microsoft账户密码或误用了PIN码。本文详解如何确认账户类型、正确输入凭据及检查自动登录设置,帮你解决验证报错问题。

    win10忘记当前密码了怎么处理完整方法
    win10忘记当前密码了怎么处理完整方法

    Windows 10忘记开机密码如何处理?本文根据账户类型(Microsoft账户/本地账户/PIN)提供官方支持的恢复步骤,包括在线重置、安全问题回答及管理员重置方法,避免数据丢失风险。

    win10更新提示不断弹出如何永久关闭通知
    win10更新提示不断弹出如何永久关闭通知

    Windows 10更新提示频繁弹窗怎么办?本文详解如何通过Windows更新高级选项、系统通知设置及暂停更新功能,精准关闭不必要的重启提醒和横幅通知,同时确保系统安全更新不受影响。适用于家庭及个人用户,区分个人设置与企业策略管理。

    win10家庭版能不能取消开机密码,操作步骤是什么
    win10家庭版能不能取消开机密码,操作步骤是什么

    Win10家庭版如何取消开机密码?本文详解本地账户清空密码步骤及Microsoft账户自动登录设置方法,分析安全风险与例外情况,帮助用户在便捷与安全间做出合理选择。

    查看更多
    精品专题 更多
    装机必备
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows
    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    macOS软件
    macOS软件

    正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

    Mac软件 更多
    photoshop
    photoshop
    Windows、macOS 、 iPad

    Photoshop 2026 是 Adobe 推出的专业图像处理与视觉设计软件,支持 Windows、macOS 和 iPad 等平台,广泛应用于摄影修图、电商设计、平面海报、数字绘画及视觉合成等创作场景。

    Blender
    Blender
    Windows、macOS 和 Linux

    Blender 是一款免费开源、跨平台的专业 3D 创作软件,集建模、动画、渲染、视频编辑与视觉合成等功能于一体,广泛应用于影视动画、游戏设计和建筑可视化等领域。软件支持 Cycles 物理渲染器与 Eevee 实时渲染引擎,并提供多边形建模、骨骼绑定、物理模拟等专业工具。Blender 兼容 Windows、macOS 和 Linux 系统,安装包轻巧、运行流畅,依托活跃的全球开发者社区持续更新,是从初学者到专业创作者都值得选择的正版 3D 创作工具。

    灵活计算器
    灵活计算器
    macOS/iOS/Android

    灵活计算器是一款笔记式算数应用,支持实时计算、动态关联和云端同步功能。记录、整理和输出之间的过渡会更自然,适合长期写作、做笔记或持续沉淀个人内容。

    WINDOWS 更多
    3dmax(3ds max)
    3dmax(3ds max)
    Windows

    Autodesk 3ds Max 是一款专业的三维建模、动画与渲染软件,广泛应用于建筑可视化、游戏开发、影视动画、广告设计和产品展示等领域。

    photoshop
    photoshop
    Windows、macOS 、 iPad

    Photoshop 2026 是 Adobe 推出的专业图像处理与视觉设计软件,支持 Windows、macOS 和 iPad 等平台,广泛应用于摄影修图、电商设计、平面海报、数字绘画及视觉合成等创作场景。

    Blender
    Blender
    Windows、macOS 和 Linux

    Blender 是一款免费开源、跨平台的专业 3D 创作软件,集建模、动画、渲染、视频编辑与视觉合成等功能于一体,广泛应用于影视动画、游戏设计和建筑可视化等领域。软件支持 Cycles 物理渲染器与 Eevee 实时渲染引擎,并提供多边形建模、骨骼绑定、物理模拟等专业工具。Blender 兼容 Windows、macOS 和 Linux 系统,安装包轻巧、运行流畅,依托活跃的全球开发者社区持续更新,是从初学者到专业创作者都值得选择的正版 3D 创作工具。

    即将离开本站
    您即将前往第三方网站,请确认是否继续?