深入分析 Android ContentProvider (六)

news2024/11/18 13:31:03

文章目录

    • 深入分析 Android ContentProvider (六)
    • ContentProvider 的性能优化和实践案例(续)
      • 1. 性能优化技巧(续)
        • 1.6. 使用批量插入优化性能
          • 示例:批量插入实现
        • 1.7. 使用 Projections 优化查询
          • 示例:使用 Projections
        • 1.8. 减少频繁通知
          • 示例:减少频繁通知
        • 1.9. 优化查询语句
          • 示例:优化查询语句
      • 2. 实践案例(续)
        • 2.3 案例三:联系人应用的数据管理
          • 联系人 ContentProvider 实现
        • 2.4 案例四:日历应用的数据管理
          • 日历 ContentProvider 实现
      • 3. 总结

深入分析 Android ContentProvider (六)

ContentProvider 的性能优化和实践案例(续)

在上一节中,我们介绍了 ContentProvider 的性能优化技巧和两个实际案例。本节将继续深入探讨更多的优化技巧,并提供更详细的实际案例分析。

1. 性能优化技巧(续)

1.6. 使用批量插入优化性能

在需要插入大量数据时,逐行插入会非常低效。可以使用 ContentProviderbulkInsert 方法进行批量插入,从而显著提升性能。

示例:批量插入实现
@Override
public int bulkInsert(@NonNull Uri uri, @NonNull ContentValues[] values) {
    final SQLiteDatabase db = dbHelper.getWritableDatabase();
    switch (uriMatcher.match(uri)) {
        case MEDIA:
            db.beginTransaction();
            try {
                for (ContentValues value : values) {
                    db.insertOrThrow(DatabaseHelper.TABLE_MEDIA, null, value);
                }
                db.setTransactionSuccessful();
            } finally {
                db.endTransaction();
            }
            getContext().getContentResolver().notifyChange(uri, null);
            return values.length;
        default:
            return super.bulkInsert(uri, values);
    }
}
1.7. 使用 Projections 优化查询

当查询数据库时,如果只需要部分字段,可以使用 Projections 来指定需要的列,以减少数据传输和内存消耗。

示例:使用 Projections
String[] projection = {
    DatabaseHelper.COLUMN_ID,
    DatabaseHelper.COLUMN_NAME
};

Cursor cursor = getContentResolver().query(
    CONTENT_URI,    // Uri
    projection,     // Projection
    null,           // Selection
    null,           // Selection arguments
    null            // Sort order
);
1.8. 减少频繁通知

在数据变化时,ContentProvider 会通知所有监听该 URI 的内容观察者。频繁的通知可能会导致性能问题。可以通过合并通知或使用 ContentResolver#notifyChange(Uri, ContentObserver, boolean) 的第三个参数控制通知范围。

示例:减少频繁通知
public int bulkUpdate(@NonNull Uri uri, @NonNull ContentValues[] values) {
    final SQLiteDatabase db = dbHelper.getWritableDatabase();
    db.beginTransaction();
    try {
        for (ContentValues value : values) {
            db.update(DatabaseHelper.TABLE_MEDIA, value, selection, selectionArgs);
        }
        db.setTransactionSuccessful();
    } finally {
        db.endTransaction();
    }
    getContext().getContentResolver().notifyChange(uri, null, false);
    return values.length;
}
1.9. 优化查询语句

复杂查询可能会降低性能,可以通过优化 SQL 语句,避免不必要的嵌套查询和表连接来提升性能。

示例:优化查询语句
Cursor cursor = db.query(
    DatabaseHelper.TABLE_MEDIA,
    projection,
    DatabaseHelper.COLUMN_NAME + " LIKE ?",
    new String[]{"%keyword%"},
    null,
    null,
    DatabaseHelper.COLUMN_NAME + " ASC"
);

2. 实践案例(续)

2.3 案例三:联系人应用的数据管理

在联系人应用中,管理联系人数据需要高效的数据存储和检索。ContentProvider 可以提供统一的接口来管理联系人数据,并通过批量操作和异步任务优化性能。

联系人 ContentProvider 实现
public class ContactsProvider extends ContentProvider {
    private static final String AUTHORITY = "com.example.contactsprovider";
    private static final String BASE_PATH = "contacts";
    public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + BASE_PATH);

    private static final int CONTACTS = 1;
    private static final int CONTACT_ID = 2;
    private static final UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

    static {
        uriMatcher.addURI(AUTHORITY, BASE_PATH, CONTACTS);
        uriMatcher.addURI(AUTHORITY, BASE_PATH + "/#", CONTACT_ID);
    }

    private SQLiteDatabase database;

    @Override
    public boolean onCreate() {
        DatabaseHelper dbHelper = new DatabaseHelper(getContext());
        database = dbHelper.getWritableDatabase();
        return true;
    }

    @Nullable
    @Override
    public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection,
                        @Nullable String[] selectionArgs, @Nullable String sortOrder) {
        switch (uriMatcher.match(uri)) {
            case CONTACTS:
                return database.query(DatabaseHelper.TABLE_CONTACTS, projection, selection, selectionArgs, null, null, sortOrder);
            case CONTACT_ID:
                selection = DatabaseHelper.COLUMN_ID + "=?";
                selectionArgs = new String[]{String.valueOf(ContentUris.parseId(uri))};
                return database.query(DatabaseHelper.TABLE_CONTACTS, projection, selection, selectionArgs, null, null, sortOrder);
            default:
                throw new IllegalArgumentException("Unknown URI: " + uri);
        }
    }

    @Nullable
    @Override
    public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
        long id = database.insert(DatabaseHelper.TABLE_CONTACTS, null, values);
        getContext().getContentResolver().notifyChange(uri, null);
        return ContentUris.withAppendedId(CONTENT_URI, id);
    }

    @Override
    public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
        int rowsDeleted;
        switch (uriMatcher.match(uri)) {
            case CONTACTS:
                rowsDeleted = database.delete(DatabaseHelper.TABLE_CONTACTS, selection, selectionArgs);
                break;
            case CONTACT_ID:
                selection = DatabaseHelper.COLUMN_ID + "=?";
                selectionArgs = new String[]{String.valueOf(ContentUris.parseId(uri))};
                rowsDeleted = database.delete(DatabaseHelper.TABLE_CONTACTS, selection, selectionArgs);
                break;
            default:
                throw new IllegalArgumentException("Unknown URI: " + uri);
        }
        getContext().getContentResolver().notifyChange(uri, null);
        return rowsDeleted;
    }

    @Override
    public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
        int rowsUpdated;
        switch (uriMatcher.match(uri)) {
            case CONTACTS:
                rowsUpdated = database.update(DatabaseHelper.TABLE_CONTACTS, values, selection, selectionArgs);
                break;
            case CONTACT_ID:
                selection = DatabaseHelper.COLUMN_ID + "=?";
                selectionArgs = new String[]{String.valueOf(ContentUris.parseId(uri))};
                rowsUpdated = database.update(DatabaseHelper.TABLE_CONTACTS, values, selection, selectionArgs);
                break;
            default:
                throw new IllegalArgumentException("Unknown URI: " + uri);
        }
        getContext().getContentResolver().notifyChange(uri, null);
        return rowsUpdated;
    }

    @Nullable
    @Override
    public String getType(@NonNull Uri uri) {
        switch (uriMatcher.match(uri)) {
            case CONTACTS:
                return "vnd.android.cursor.dir/vnd.com.example.contactsprovider.contacts";
            case CONTACT_ID:
                return "vnd.android.cursor.item/vnd.com.example.contactsprovider.contact";
            default:
                throw new IllegalArgumentException("Unknown URI: " + uri);
        }
    }
}
2.4 案例四:日历应用的数据管理

在日历应用中,管理事件和提醒需要高效的数据存储和检索。通过 ContentProvider,可以方便地管理日历数据,并通过缓存机制和异步操作优化性能。

日历 ContentProvider 实现
public class CalendarProvider extends ContentProvider {
    private static final String AUTHORITY = "com.example.calendarprovider";
    private static final String BASE_PATH = "events";
    public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + BASE_PATH);

    private static final int EVENTS = 1;
    private static final int EVENT_ID = 2;
    private static final UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

    static {
        uriMatcher.addURI(AUTHORITY, BASE_PATH, EVENTS);
        uriMatcher.addURI(AUTHORITY, BASE_PATH + "/#", EVENT_ID);
    }

    private SQLiteDatabase database;

    @Override
    public boolean onCreate() {
        DatabaseHelper dbHelper = new DatabaseHelper(getContext());
        database = dbHelper.getWritableDatabase();
        return true;
    }

    @Nullable
    @Override
    public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection,
                        @Nullable String[] selectionArgs, @Nullable String sortOrder) {
        switch (uriMatcher.match(uri)) {
            case EVENTS:
                return database.query(DatabaseHelper.TABLE_EVENTS, projection, selection, selectionArgs, null, null, sortOrder);
            case EVENT_ID:
                selection = DatabaseHelper.COLUMN_ID + "=?";
                selectionArgs = new String[]{String.valueOf(ContentUris.parseId(uri))};
                return database.query(DatabaseHelper.TABLE_EVENTS, projection, selection, selectionArgs, null, null, sortOrder);
            default:
                throw new IllegalArgumentException("Unknown URI: " + uri);
        }
    }

    @Nullable
    @Override
    public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
        long id = database.insert(DatabaseHelper.TABLE_EVENTS, null, values);
        getContext().getContentResolver().notifyChange(uri, null);
        return ContentUris.withAppendedId(CONTENT_URI, id);
    }

    @Override
    public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
        int

 rowsDeleted;
        switch (uriMatcher.match(uri)) {
            case EVENTS:
                rowsDeleted = database.delete(DatabaseHelper.TABLE_EVENTS, selection, selectionArgs);
                break;
            case EVENT_ID:
                selection = DatabaseHelper.COLUMN_ID + "=?";
                selectionArgs = new String[]{String.valueOf(ContentUris.parseId(uri))};
                rowsDeleted = database.delete(DatabaseHelper.TABLE_EVENTS, selection, selectionArgs);
                break;
            default:
                throw new IllegalArgumentException("Unknown URI: " + uri);
        }
        getContext().getContentResolver().notifyChange(uri, null);
        return rowsDeleted;
    }

    @Override
    public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
        int rowsUpdated;
        switch (uriMatcher.match(uri)) {
            case EVENTS:
                rowsUpdated = database.update(DatabaseHelper.TABLE_EVENTS, values, selection, selectionArgs);
                break;
            case EVENT_ID:
                selection = DatabaseHelper.COLUMN_ID + "=?";
                selectionArgs = new String[]{String.valueOf(ContentUris.parseId(uri))};
                rowsUpdated = database.update(DatabaseHelper.TABLE_EVENTS, values, selection, selectionArgs);
                break;
            default:
                throw new IllegalArgumentException("Unknown URI: " + uri);
        }
        getContext().getContentResolver().notifyChange(uri, null);
        return rowsUpdated;
    }

    @Nullable
    @Override
    public String getType(@NonNull Uri uri) {
        switch (uriMatcher.match(uri)) {
            case EVENTS:
                return "vnd.android.cursor.dir/vnd.com.example.calendarprovider.events";
            case EVENT_ID:
                return "vnd.android.cursor.item/vnd.com.example.calendarprovider.event";
            default:
                throw new IllegalArgumentException("Unknown URI: " + uri);
        }
    }
}

3. 总结

ContentProvider 是 Android 中用于数据共享和管理的核心机制,特别适用于跨进程数据访问。在开发中,通过合理设计和优化,可以充分利用 ContentProvider 的优势,实现高效的数据操作。实践中,通过批量操作、异步任务、缓存机制等手段,可以显著提升 ContentProvider 的性能,确保应用的稳定性和用户体验。结合实际场景,选择合适的优化技巧和设计模式,是开发高性能 Android 应用的关键。

欢迎点赞|关注|收藏|评论,您的肯定是我创作的动力

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1955583.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Webpack 从入门到精通

(创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,请留下您的足迹) 目录 一、Webpack 简介 二、Webpack 的核心概念 三、Webpack 的安装与配置 安装 Node.js 安装 Webpack 初始…

【Linux C | 网络编程】进程池退出的实现详解(五)

上一篇中讲解了在进程池文件传输的过程如何实现零拷贝,具体的方法包括使用mmap,sendfile,splice等等。 【Linux C | 网络编程】进程池零拷贝传输的实现详解(四) 这篇内容主要讲解进程池如何退出。 1.进程池的简单退…

超越基础功能:项目进度管理工具深度评测

国内外主流的10款项目进度管理网站对比:PingCode、Worktile、滴答清单(TickTick)、Todoist、NarTick、Teambition、Monday.com、Asana、ClickUp、Trello。 在选择合适的项目进度管理工具时,许多项目经理面临着如何找到既能满足团队…

二十二、作业

目录 1.求代码结果 2.求代码结果 3.使用指针打印数组内容 4.字符串逆序 5.计算求和 6.打印水仙花数 7.打印菱形 8.喝汽水问题 1.求代码结果 输出为00345 2.求代码结果 任何一个变量/表达式,都有2个属性,值属性和类型属性 int a 3;…

Python及Jupyter-Notebook安装

来源: “码农不会写诗”公众号 链接:Python及Jupyter-Notebook安装 文章目录 01 Python安装1.1 下载安装包1.2 双击安装包,开始安装1.3 选择安装配置1.4 选择需要安装的Optional Feature,点击Next1.5 选择需要安装的Advanced Feat…

matplotlib的科研绘图辅助

matplotlib的科研绘图辅助 趁着暑假,与和鲸科技合作了一个python绘图的教程,作为暑期夏令营的一小部分,主要内容是介绍如何使用matplotlib、pandas、seaborn和plotnine进行医学科研绘图,感兴趣的可以通过如下地址进行访问&#x…

Unity XR Interaction Toolkit设置或监听手柄按键事件(三)

提示:文章有错误的地方,还望诸位大神不吝指教! 文章目录 前言一、XRI Default Input Actions1.导入官方案例2.设置控制器绑定,如手柄、主/辅助按钮、操纵杆等1.要设置控制器绑定,如左右手 手柄、主/辅助按钮、操纵杆等…

添加sidecar容器并输出日志

添加一个sidecar容器(使用busybox 镜像)到已有的pod 11-factor-app中,确保sidecar容器能够输出/var/log/11-factor-app.log的信息,使用volume挂载/var/log目录,确保sidecar能访问11-factor-app.log 文件 # 准备工作 创建一个 pod 11-factor-appapiVersion: v1 kind: Pod metada…

【研路导航】保研英语面试高分攻略,助你一路过关斩将

面试攻略之 千锤百炼英语口语 写在前面 在保研面试中,英语口语往往是让许多同学感到头疼的一部分。如何在面试中展现出自信和流利的英语表达能力,是我们今天要探讨的主题。以下是一些有效的英语口语练习方法和常见题型解析,帮助你在保研面试…

GUI - Tkinter - MVC

【python】 property属性详解_python property-CSDN博客Tkinter MVC (pythontutorial.net)GUI架构演进之MVC(一) - frydsh - 博客园 (cnblogs.com)MVC 模式 | 菜鸟教程 (runoob.com)MVC 架构详解 (freecodecamp.org)Python之MVC - chenbiao - SegmentFau…

灵活数据流处理:NeuronEX 支持 JavaScript 自定义函数

随着数据要素逐渐成为帮助工业企业提升智能化水平的重要助力,如何灵活采集和处理工业数据,并满足用户定制化的数据需求,成为企业数字化建设的焦点之一。 NeuronEX 是一款专为工业场景设计的边缘网关软件,具备工业设备数据采集、工…

@JSONField(format = “yyyyMMddHH“)的作用和使用

JySellerItqrdDataDO对象中的字段为: private Date crdat; 2.数据库中的相应字段为: crdat datetime DEFAULT NULL COMMENT 创建时间,2. 打印出的结果为: “crdat”:“2024072718” 年月日时分秒 3. 可以调整format的格式 4. 这样就把Date类…

信息搜集——小米

小米 主域名:www.miui.com 备案网站:27个 备案APP:21个 备案小程序:13个 备案公众号:23个 备案微博:43个 IP 域名 端口 状态码 Ping 网址 多地ping 网站名称 网址 域名 网站备案/许可证号 公 司名…

手撕数据结构---------顺序表和链表

1.线性表 线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是⼀种在实际中⼴泛使 ⽤的数据结构,常⻅的线性表:顺序表、链表、栈、队列、字符串… 线性表在逻辑上是线性结构,也就说是连续的⼀条直…

java实战项目--拼图小游戏(附带全套源代码)

个人主页VON 所属专栏java实战项目游戏参考黑马程序员 一、效果展示 二、功能介绍 游戏中所有的图片以及代码均已打包,玩家直接安装游戏即可,不用idea也可以畅玩。 游戏功能比较单一,只有简单的拼图功能。 a:展示原图重新游戏&a…

初涉JVM

JVM 字节码、类的生命周期、内存区域、垃圾回收 JVM主要功能: 解释运行(翻译字节码)内存管理(GC)即使编译(Just - In - Time, JIT) 将短时间内常使用到的字节码翻译成机器码存储在内…

whaler_通过镜像导出dockerfile

1、Whaler简介 Whaler:从镜像导出Dockerfile,whaler英文释义捕鲸船。 2、下载安装 # wget -cO /usr/local/bin/whaler https://github.com/P3GLEG/Whaler/releases/download/1.0/Whaler_linux_amd64 3、赋予可执行权限 [rootlocalhost ~]# chmod x /usr/local/…

Android OTA刷机包制作学习笔记

前言 OTA是一个再常见不过的需求,Android提供了recovery用于完成相关操作。 常规OTA包制作有两种: 有项目的完整AOSP源码,可以在成构建产物zip包后利用官方脚本制作。具体参阅:Office OTA假设你没有1的条件那么可以利用官方非A/…

exo-tinggrad 架构解析

目录 exo-tinggrad 架构解析 8B 模型配置 70B 模型配置 exo-tinggrad 架构解析 这个项目目录包含了一系列与Python相关的文件和文件夹,它们共同构成了一个可能的项目或库。这些文件和文件夹按照特定的命名和组织方式被放置在了一起,以便于管理、开发和维护。 tinygrad: 这…

24.7.28(tarjan 割点,割边,多重背包单调队列优化)

星期一: cf round 960 div2 B 简单构造 cf传送门 题意有点绕 思路:开始容易想到 y前和 x后全-1,y到x填1的构造,但对于 5 2 1,1 1 -1 -1 -1有问题,1和5的后缀值都为 -1…