使用 ExpandableListView/SimpleCursorTreeAdapter 在 UI 线程上运行 SQLite 查询

2024-01-08

我正在开发一个用于显示大量 RSS 源的 Android 应用程序(是的,我知道已经有很多这样的应用程序)。要显示的数据由内容提供商支持,我希望向后兼容 API 级别 4。

我正在使用一个ExpandableListView显示三个不同 RSS 提要的内容。这ExpandableListView的适配器是作为子类实现的SimpleCursorTreeAdapter:

private class RssFeedLatestListAdapter extends SimpleCursorTreeAdapter {

    public static final String FEED_NAME_COLUMN = "feedName";

    public RssFeedLatestListAdapter(Context ctx, Cursor groupCursor, int groupLayout,
            String[] groupFrom, int[] groupTo, int childLayout, String[] childFrom,
            int[] childTo) {
        super(ctx, groupCursor, groupLayout, groupLayout, groupFrom, groupTo, childLayout, childFrom, childTo);
    }

    @Override
    protected Cursor getChildrenCursor(final Cursor groupCursor) {
        final String feedName = groupCursor.getString(groupCursor.getColumnIndex(FEED_NAME_COLUMN));
        return managedQuery(LATEST_URI, null,
                FeedItemColumns.CATEGORY + " = ? AND " + FeedItemColumns.FEED + " = ?",
                new String[] { mCategory.getId(), feedName }, null);
    }

    @Override
    protected void bindGroupView(View view, Context context, Cursor cursor, boolean isExpanded) {
        super.bindGroupView(view, context, cursor, isExpanded);

        // Bind group view (impl details not important) ...
    }

    @Override
    protected void bindChildView(View view, Context context, Cursor cursor, boolean isLastChild) {
        super.bindChildView(view, context, cursor, isLastChild);

        // Bind child view (impl details not important) ...
    }
}

通过此设置,所有内容都会按预期加载。然而,UI 挂起/卡顿在加载列表内容期间随机。通常不足以获得 ANR,但仍然很明显且非常烦人!

为了调试这个问题,我启用了 android.os.StrictMode (顺便说一句,很棒的新功能/工具!),并启动了模拟器(在 Android 2.3 上)。加载列表内容后,我得到以下 StrictMode 输出:



D/StrictMode(  395): StrictMode policy violation; ~duration=1522 ms: android.os.StrictMode$StrictModeDiskReadViolation: policy=23 violation=2
D/StrictMode(  395):  at android.os.StrictMode$AndroidBlockGuardPolicy.onReadFromDisk(StrictMode.java:745)
D/StrictMode(  395):  at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1345)
D/StrictMode(  395):  at android.database.sqlite.SQLiteQueryBuilder.query(SQLiteQueryBuilder.java:330)
D/StrictMode(  395):  at com.mycompany.myapp.provider.RSSFeedProvider.query(RSSFeedProvider.java:128)
D/StrictMode(  395):  at android.content.ContentProvider$Transport.query(ContentProvider.java:187)
D/StrictMode(  395):  at android.content.ContentResolver.query(ContentResolver.java:262)
D/StrictMode(  395):  at android.app.Activity.managedQuery(Activity.java:1550)
D/StrictMode(  395):  at com.mycompany.myapp.activity.MultipleFeedsActivity$RssFeedLatestListAdapter.getChildrenCursor(MultipleFeedsActivity.java:388)
D/StrictMode(  395):  at android.widget.CursorTreeAdapter.getChildrenCursorHelper(CursorTreeAdapter.java:106)
D/StrictMode(  395):  at android.widget.CursorTreeAdapter.getChildrenCount(CursorTreeAdapter.java:178)
D/StrictMode(  395):  at android.widget.ExpandableListConnector.refreshExpGroupMetadataList(ExpandableListConnector.java:561)
D/StrictMode(  395):  at android.widget.ExpandableListConnector.expandGroup(ExpandableListConnector.java:682)
D/StrictMode(  395):  at android.widget.ExpandableListConnector.expandGroup(ExpandableListConnector.java:636)
D/StrictMode(  395):  at android.widget.ExpandableListView.expandGroup(ExpandableListView.java:608)
D/StrictMode(  395):  at com.mycompany.myapp.activity.MultipleFeedsActivity.onReceiveResult(MultipleFeedsActivity.java:335)
D/StrictMode(  395):  at com.mycompany.myapp.service.FeedResultReceiver.onReceiveResult(FeedResultReceiver.java:40)
D/StrictMode(  395):  at android.os.ResultReceiver$MyRunnable.run(ResultReceiver.java:43)
D/StrictMode(  395):  at android.os.Handler.handleCallback(Handler.java:587)
D/StrictMode(  395):  at android.os.Handler.dispatchMessage(Handler.java:92)
D/StrictMode(  395):  at android.os.Looper.loop(Looper.java:123)
D/StrictMode(  395):  at android.app.ActivityThread.main(ActivityThread.java:3647)
D/StrictMode(  395):  at java.lang.reflect.Method.invokeNative(Native Method)
D/StrictMode(  395):  at java.lang.reflect.Method.invoke(Method.java:507)
D/StrictMode(  395):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
D/StrictMode(  395):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
D/StrictMode(  395):  at dalvik.system.NativeStart.main(Native Method)
  

这似乎很有道理!在SimpleCursorTreeAdapter.getChildrenCursor(),在 UI 线程上查询内容提供者,这当然是一个坏主意,肯定会挂起 UI!

我看了一下JavaDoc http://developer.android.com/reference/android/widget/CursorTreeAdapter.html#getChildrenCursor%28android.database.Cursor%29(API 级别 4)CursorTreeAdapter(超类SimpleCursorTreeAdapter)和对于getChildrenCursor()它说:

“如果您想异步查询提供程序以防止阻塞 UI,可以返回 null 并稍后调用 setChildrenCursor(int, Cursor)。”.

伟大的!让我们这样做吧!我改变了我的实施getChildrenCursor()启动一个新任务,负责执行查询并在适配器上设置子游标。开始任务后,我只是返回 nullgetChildrenCursor():

@Override
protected Cursor getChildrenCursor(final Cursor groupCursor) {
    final String feedName = groupCursor.getString(groupCursor.getColumnIndex(FEED_NAME_COLUMN));
    new RefreshChildrenCursorTask(groupCursor.getPosition()).execute(feedName);
    return null;
}

,其中RefreshChildrenCursorTask实现为:

private class RefreshChildrenCursorTask extends AsyncTask<String, Void, Cursor> {

    private int mGroupPosition;

    public RefreshChildrenCursorTask(int groupPosition) {
        this.mGroupPosition = groupPosition;
    }

    @Override
    protected Cursor doInBackground(String... params) {
        String feedName = params[0];
        return managedQuery(LATEST_URI, null,
                FeedItemColumns.CATEGORY + " = ? AND " + FeedItemColumns.FEED + " = ?",
                new String[] { mCategory.getId(), feedName }, null);
        }

        @Override
        protected void onPostExecute(Cursor childrenCursor) {
            mLatestListAdapter.setChildrenCursor(mGroupPosition, childrenCursor);
        }
    }
}

我在 2.3 模拟器上重新安装了该应用程序并启动了它。它的工作方式就像一个魅力,再见无响应的用户界面!但喜悦并没有持续多久……接下来要做的就是在目标设备上运行相同的代码(在本例中是运行 Android 2.2 的三星 Galaxy S)。然后我得到以下内容Exception在加载列表提要内容期间:



E/AndroidRuntime(23191): FATAL EXCEPTION: main
E/AndroidRuntime(23191): java.lang.NullPointerException
E/AndroidRuntime(23191):  at android.widget.SimpleCursorTreeAdapter.initFromColumns(SimpleCursorTreeAdapter.java:194)
E/AndroidRuntime(23191):  at android.widget.SimpleCursorTreeAdapter.initChildrenFromColumns(SimpleCursorTreeAdapter.java:205)
E/AndroidRuntime(23191):  at android.widget.SimpleCursorTreeAdapter.init(SimpleCursorTreeAdapter.java:186)
E/AndroidRuntime(23191):  at android.widget.SimpleCursorTreeAdapter.(SimpleCursorTreeAdapter.java:136)
E/AndroidRuntime(23191):  at com.mycompany.myapp.activity.MultipleFeedsActivity$RssFeedLatestListAdapter.(MultipleFeedsActivity.java:378)
E/AndroidRuntime(23191):  at com.mycompany.myapp.activity.MultipleFeedsActivity$2.run(MultipleFeedsActivity.java:150)
E/AndroidRuntime(23191):  at android.os.Handler.handleCallback(Handler.java:587)
E/AndroidRuntime(23191):  at android.os.Handler.dispatchMessage(Handler.java:92)
E/AndroidRuntime(23191):  at android.os.Looper.loop(Looper.java:123)
E/AndroidRuntime(23191):  at android.app.ActivityThread.main(ActivityThread.java:4627)
E/AndroidRuntime(23191):  at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime(23191):  at java.lang.reflect.Method.invoke(Method.java:521)
E/AndroidRuntime(23191):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:871)
E/AndroidRuntime(23191):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:629)
E/AndroidRuntime(23191):  at dalvik.system.NativeStart.main(Native Method)
  

快速浏览一下源代码SimpleCursorTreeAdapter告诉我它无法处理从异步返回 nullgetChildrenCursor()。他们似乎在 Android 2.3 中解决了这个问题,但是在早期版本的 Android 中你应该如何解决这个问题呢?我真的必须编写自己的实现吗CursorTreeAdapter能够异步刷新子光标?

有没有人遇到过同样的问题,甚至找到了(可行的)解决方法?如果没有,有人能给我提示如何继续吗?我真的很感激任何帮助我可以得到!

提前致谢!

问候, 雅各布


如果他们在 2.3 SimpleCursorTreeAdapter 中修复了它,为什么不直接下载 java 文件并将其包含在您的项目中并使用该版本而不是手机上的版本呢?

我没有看过代码,但只要他们没有进行任何新的 2.3 API 调用,它就应该可以工作。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 ExpandableListView/SimpleCursorTreeAdapter 在 UI 线程上运行 SQLite 查询 的相关文章

  • 如何从 SDK 实现每个会话的 Google Places 自动完成功能?

    是否可以从 Android 和 iOS 应用程序的 place sdk 实现基于会话的自动完成 根据 6 月 11 日生效的新 Google 地图框架定价 对自动完成的请求可以分为基于击键 会话的请求 我找不到描述实施步骤的文档 除了这个参
  • android edittext中的字符映射

    我想让我的编辑文本就像我写字符 g 时一样 它是相关的映射自定义字符应该写成印地语中的 我认为应该有字符映射 但没有知识任何人都可以帮助我 怎么做 其他应用程序https play google com store apps details
  • 我在布局上看不到任何 FirebaseRecyclerAdapter 项目

    我试图将数据从 Firebase 数据库检索到我的布局 但我看不到任何项目FirebaseRecyclerAdapter在布局中 请帮忙 我按照一个教程展示了如何做到这一点 当我运行应用程序时 我没有看到任何项目 但我可以滚动 public
  • Android短音的正确播放方法?

    我正在创建一个应用程序 屏幕上将有多个图像 这些图像将是按钮 点击时会播放短促的声音 我对此进行了研究 只能找到我当前用来播放声音的方法 这似乎根本没有响应 我希望声音能够快速播放并且能够响应多次快速点击 我不确定这在 Android 中是
  • 从响应中获取标头(Retrofit / OkHttp 客户端)

    我正在使用 Retrofit 与 OkHttp 客户端和 Jackson 进行 Json 序列化 并希望获取响应的标头 我知道我可以扩展 OkClient 并拦截它 但这发生在反序列化过程开始之前 我基本上需要的是获取标头以及反序列化的 J
  • Android Q:file.mkdirs() 返回 false

    我们有一个应用程序 使用外部存储来存储一些临时文件 图像 二进制数据 该代码已经运行了几年 直到最近才发生重大变化 在 Android Q 上它不起作用 File f new File Environment getExternalStor
  • Gradle 构建错误:无法从 https://repo1.maven.org/maven2/io/fabric/tools/gradle/maven-metadata.xml 加载 Maven 元数据

    我在 Android studio 中遇到 gradle 构建错误 如下所示 Error A problem occurred configuring project MyApp Could not resolve all dependen
  • 自定义首选项中的android首选项水平分隔线?

    我创建了自己的自定义首选项对象来扩展首选项 我创建它们只是因为这些自定义数据类型没有首选项 一切正常 但我的自定义首选项没有相同的外观 因为它们缺少系统首选项对象具有的水平分隔线 我已经查找了创建水平分隔线的代码 但我找不到它是在哪里完成的
  • Bitmap.getPixels() 中的 IllegalArgumentException

    我想将数据从位图复制到int using getPixels 这是我当前的代码 int pixels new int myBitmap getHeight myBitmap getWidth myBitmap getPixels pixel
  • 如何更改终端的默认目录?

    我想更改 Android Studio v2 2 2 终端的默认目录 当我打开终端时 它基于项目的目录 C 项目路径 我经常需要使用adb shell 所以我必须导航到 SDK 路径 平台工具 才能使用 adb 命令 是否可以更改终端的默认
  • Android:后台Activity可以执行代码吗?

    后台的活动是否被视为 正在运行 并且可以执行代码 还是处于挂起状态 他们暂停了 活动生命周期 http developer android com reference android app Activity html ActivityLi
  • Android 手机作为 GSM 调制解调器在 PC 上发送/接收短信?

    是否可以将 Android 移动设备用作 PC 上的 GSM 调制解调器 我正在 net下开发应用程序来发送 接收短信等 现在我想通过 USB 将我的 Android 设备连接到我的 PC 并将其用作 GSM 调制解调器来与其通信 这里是参
  • 当 OnFocusChangeListener 应用于包装的 EditText 时,TextInputLayout 没有动画

    不能比标题说得更清楚了 我有一个由文本输入布局包裹的 EditText 我试图在 EditText 失去焦点时触发一个事件 但是 一旦应用了事件侦听器 TextInputLayout 就不再对文本进行动画处理 它只是位于 editText
  • 如何在谷歌地图android上显示多个标记

    我想在谷歌地图android上显示带有多个标记的位置 问题是当我运行我的应用程序时 它只显示一个位置 标记 这是我的代码 public class koordinatTask extends AsyncTask
  • Mipmap 与可绘制文件夹[重复]

    这个问题在这里已经有答案了 我正在使用 Android Studio 1 1 Preview 1 我注意到 当我创建一个新项目时 我得到以下层次结构 不同 DPI 的 Mipmap 文件夹 不再有不同 DPI 的可绘制文件夹 我应该将所有资
  • Android 2.3 模拟器在更新位置时崩溃

    我正在使用 Eclipse 编写和调试 Android 应用程序 我需要做的事情之一是更新设备的位置 因此我尝试使用模拟器控制窗口中的位置控制面板 在 手动 选项卡上 我选择 十进制 输入有效的纬度和经度 然后单击 发送 不幸的是 接下来发
  • Android 中的处理程序与异步调用

    目前我正在使用处理程序来调用 Web 服务方法以使其在后台运行 问题是它需要更多的时间来给出响应 在性能方面似乎更昂贵 现在我计划使用异步调用 哪一个是最好的 Android 中的处理程序和异步调用有什么区别 请帮我想出一个最好的解决方案
  • CamcorderProfile.videoCodec 返回错误值

    根据docs https developer android com reference android media CamcorderProfile html 您可以使用CamcorderProfile获取设备默认视频编解码格式 然后将其
  • Android 后台倒计时器

    我有一个 Android 应用程序 它管理一个倒计时器 类 CountDownTimer 它显示在应用程序屏幕中 以显示到达 00 00 还剩多少时间 我现在的问题是 当我按主页按钮或启动另一个应用程序时 应用程序 计时器不会在后台运行 所
  • 有没有任何代码可以在android中设置壁纸而无需裁剪和缩放?

    我正在创建一个画廊应用程序 我的第一个应用程序 这是我的代码 Bitmap bmd BitmapFactory decodeStream is try getApplicationContext setWallpaper bmd catch

随机推荐

  • JMX 和 RMI 的区别

    JMX 的目的是什么以及它的用途是什么 我一直在浏览 JMX 上的一些教程 它们所做的就是注册一些 Mbean 并从 jconsole 调用这些 Mbean 如果这就是它的目的 那么 JMX 和 RMI 远程过程调用 之间有什么区别 提前致
  • 如何使用 VBA 将样式应用于 Word 中的多个选择?

    我创建了一个宏 它将特定的样式应用于文档中选择的任何内容 但是 在草稿视图中 当用户在样式区域窗格中单击以选择一个段落 然后按住 Ctrl 键并单击其他段落时 运行此宏时不会应用此附加选择 Sub BodyTextApply Selecti
  • 在单元测试中伪造我的数据库层的方法是什么?

    我有一个关于单元测试的问题 假设我有一个带有一个创建方法的控制器 该方法将新客户放入数据库中 code a bit shortened public actionresult Create Formcollection formcollec
  • 如何使用 javascript 将 json 数据写入 google 工作表

    我正在尝试使用 javascript 将 json 数据渲染到 google 工作表 我尝试搜索大量文档 并且已经尝试了几个小时 我确实在工作表中输入了一行数据 但我需要在正确的行和列中渲染整个 json 数据集 function rend
  • 如何在Spring字符串到数组或列表转换中转义“,”(逗号)

    我们有一个 Spring 绑定 它将字符串转换为Lists 使用 Spring 提供的默认转换器 例如 如果我们有a b c从表单推送然后控制器得到一个List与元素 a b c 我们不需要在代码中做任何特殊的事情 我在处理数据中的逗号时遇
  • 自动点击弹出按钮

    我有以下按钮突然出现在窗口上 span class a b c Accept Waiting Chat span 是否可以拦截它并自动点击它 我正在考虑 JS 或 Greymonkey 扩展中的一些东西 Ideas None
  • 阻止直接访问文件,但允许通过 jquerys 加载函数访问

    我在用着jQuery通过它向用户显示某个页面 load 功能 我这样做是为了允许用户自定义网站 让他们能够满足自己的需求 目前 我正在尝试显示该文件feed php容器内部main php 我遇到一个问题 我想阻止直接访问文件 即 直接进入
  • 使用 MSBuild 4.0 记录构建消息

    我在代码中使用 MsBuild 4 0 如下所示 var globalProperties new Dictionary
  • 使用 Python BeautifulSoup 库解析 Span HTML 标签中的信息

    我正在编写一个 Python 网络抓取工具 用于获取特定股票的价格 在我的程序末尾 有一些打印语句可以正确解析 html 数据 以便我可以在某个 HTML span 标记内获取股票的价格信息 我的问题是 我该怎么做 我已经获得了正确的 HT
  • 无法强制 clang CompilerInstance 对象将标头解析为 C++ 文件

    我有一个名为的 C 标头class h我想解析 class MyClass public Class Class bool isTrue const bool isFalse const private bool m attrib bool
  • WebStorm IDE 的高效使用

    我最近爱上了 WebStorm 作为 JavaScript 开发的 IDE 问题是 我来自 vim 和轻量级编辑器的世界 所以我可能无法完全理解 IDE 带来的所有功能 是的 我已经看过演示文稿并阅读了文档 但是有很多功能 我不确定其中哪些
  • 在 ggplot 中制作多个几何图形动画

    我正在尝试制作一个动画情节 展示 NBA 球队的三分出手率和助攻率如何随时间变化 虽然图中的点正确过渡 但我尝试添加垂直和水平平均线 但是总体平均值保持不变 而不是逐年变化 p lt ggplot dataBREFPerPossTeams
  • EF 4.3 迁移 - 如何生成降级脚本?

    我有一个问题 在网络上找不到答案 我正在使用带有 SQL 的 Code First EF 4 3 1 迁移 我添加了几个迁移 现在我想生成一个用于在两个迁移之间升级 降级的脚本 对于升级 我运行以下命令 成功重现升级脚本 PM gt Upd
  • 我什么时候在哪里以及如何更改对象的 __class__ 属性?

    我希望能够做到 gt gt gt class a str pass gt gt gt b a gt gt gt b class str Traceback most recent call last File
  • 单击时添加 div,然后在每次单击时切换它

    我尝试点击添加 添加的内容将第一次出现 添加后 我想单击 添加 它只会切换 已添加 而不是每次单击时添加 已添加 Jquery function var NewContent div class added Added div add cl
  • 在 Velocity 模板中调用宏函数

    我试图弄清楚如何从速度宏调用返回一个值并将其分配给一个变量 我的宏函数看起来像这样 它曾经是常见的共享宏文件 macro getBookListLink readingTrackerResult readingTrackerResult g
  • Spring Boot + Batch:注入/自动装配的 bean 在 ItemReader 中为 null

    当我尝试自动装配 ItemReader 中的任何 bean 时 我收到 NPE 有人可以帮我解决我哪里出错了吗 谢谢 要求是我想在 ItemReader 中注入 DAO 以从多个源获取数据并创建单个对象 这是我的配置类 Configurat
  • PHP 保护目录不被直接 URL 访问

    我有一个管理员脚本 admin index php 所有的活动都是通过这个完成的index php file 用户在获得程序功能的访问权限之前先登录 SESSION user authenticated 创建并设置为true admin t
  • 扩展 Magic Mouse 的功能:我需要 kext 吗?

    我最近购买了一个妙控鼠标 它非常棒并且充满潜力 不幸的是 它受到软件支持的严重阻碍 我想解决这个问题 我做了很多研究 这些是迄今为止我对事件链的发现 Magic Mouse 向系统发送完整的多点触控事件 多点触控事件在 Multitouch
  • 使用 ExpandableListView/SimpleCursorTreeAdapter 在 UI 线程上运行 SQLite 查询

    我正在开发一个用于显示大量 RSS 源的 Android 应用程序 是的 我知道已经有很多这样的应用程序 要显示的数据由内容提供商支持 我希望向后兼容 API 级别 4 我正在使用一个ExpandableListView显示三个不同 RSS