- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在开发一个用于显示大量 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(很棒的新功能/工具 btw!),并启动了模拟器(在 Android 2.3 上)。加载列表内容后,我得到以下 StrictMode 输出:
D/StrictMode( 395): StrictMode policy violation; ~duration=1522 ms: android.os.StrictMode$StrictModeDiskReadViolation: policy=23 violation=2D/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)
This seems reasonable! In SimpleCursorTreeAdapter.getChildrenCursor()
, the content provider is queried on the UI thread, which of course is a bad idea that will most definitely hang the UI!
I had a look at the JavaDoc (API level 4) of CursorTreeAdapter
(a super-class of SimpleCursorTreeAdapter
) and for getChildrenCursor()
it says:
"If you want to asynchronously query a provider to prevent blocking the UI, it is possible to return null and at a later time call setChildrenCursor(int, Cursor).".
Great! Let's do that! I change my implementation of getChildrenCursor()
to start a new task responsible for performing the query and setting the children cursor on the adapter. After having started the task, I just return null in getChildrenCursor()
:
@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: mainE/AndroidRuntime(23191): java.lang.NullPointerExceptionE/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
的源代码告诉我,它无法处理从 getChildrenCursor()
异步返回的 null。他们似乎已经在 Android 2.3 中解决了这个问题,但是你应该如何在早期版本的 Android 中绕过它呢?我真的必须编写自己的 CursorTreeAdapter
实现才能异步刷新子游标吗?
有没有人遇到过同样的问题,甚至可能找到了(可行的)解决方法?如果没有,任何人都可以提示我如何进行!? 如果能得到任何帮助,我将不胜感激!
提前致谢!
问候,雅各布
最佳答案
如果他们在 2.3 SimpleCursorTreeAdapter 中修复了它,您为什么不直接下载 java 文件并将其包含在您的项目中并使用该版本而不是手机上的版本?
我没有看过代码,但只要他们没有进行任何新的 2.3 API 调用,它就应该可以工作。
关于android - 使用 ExpandableListView/SimpleCursorTreeAdapter 在 UI 线程上运行 SQLite 查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4672180/
我一直在研究以下 android 应用示例。 http://developer.android.com/resources/samples/ApiDemos/src/com/example/andro
下面是我的 Activity 代码以及一个内部类,它是简单游标树适配器的子类。问题是当我点击 There is an error 的子元素时 protected void onStart() {
我正在为 Android 编写一个简单的应用程序。 我有 2 个表 - 一个名为“grous”,另一个名为“group_items”。 我想使用可扩展列表来显示两个表中的数据。 最好的方法是什么?是否
光标需要如何格式化才能使类别及其子项正确显示。适配器将如何区分什么是类别和什么是子项? 最佳答案 初始 Cursor 只需要父项。在这里,我通常使用 Cursor 来提供不同的值。 您需要扩展 Sim
我正在使用 SimpleCursorTreeAdapter 创建 ExpandableListView。我面临很多问题。 谁能告诉我我该怎么做? 最佳答案 我在 SimpleCursorTreeAda
如何根据光标特定值自定义行布局?我猜我需要自定义bindChildView - 但如何呢? :) 主要功能: public void fillQuestions(int id) { C
我有一个包含三列的 sqlite 数据库:id、日期和字符串。对于一个日期,可以有多个与之关联的字符串,因此我有多个具有相同日期的行,只是字符串不同。 我想使用 ExpandableListView
我正在将 SimpleCursorTreeAdapter 用于 ExpandableListview。我从 android 示例中得到了示例效果很好。 我的两个光标投影是这样的 private sta
我通过扩展 SimpleCursorTreeAdapter 创建了一个 ExpandableListAdapter。游标由加载程序管理。当列表显示给用户时,我启动后台服务以从服务器获取最新数据。如果服
我有一个关于我在我的项目中子类化的 SimpleCursorTreeAdapter 的问题。它目前通过 ContentProvider 与 SQLite-DB 通信。现在,我遇到了一个问题,我想插入后
在花了几天时间研究这个问题之后,我终于放弃并发布了这个问题。这里(部分)回答了类似的问题并提出了解决方案,但没有一个最终帮助了我。与讨论的主题和我的问题的区别似乎是:其他人似乎都没有使用 Simple
我正在尝试通过使用 CursorLoader 和 SimpleCursorTreeAdapter 来异步查询提供程序 这是我的 Fragment 类,它实现了 CursorLoader public
这是我正在使用的:我有一个 ExpandableListView,它使用 SimpleCursorTreeAdapter 来填充来自 SQLite 数据库的 View 。我正在使用自定义组 View
我正在开发一个用于显示大量 RSS 提要的 Android 应用程序(是的,我知道已经有很多这样的应用程序了)。要显示的数据由内容提供者提供支持,我希望向后兼容 API 级别 4。 我正在使用 Exp
我想从 SQLite 数据库获取数据并通过 SimpleCursorTreeAdapter 填充我的 ExpandableListView,但它在某些地方失败了。我真的找不到问题所在,甚至不知道异常发
我是一名优秀的程序员,十分优秀!