gpt4 book ai didi

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

转载 作者:太空宇宙 更新时间:2023-11-03 13:37:53 24 4
gpt4 key购买 nike

我正在开发一个用于显示大量 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/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com