运行UI线程SQLite的查询与ExpandableListView / SimpleCursorTreeAdapter [英] SQLite query run on UI thread with ExpandableListView/SimpleCursorTreeAdapter

查看:427
本文介绍了运行UI线程SQLite的查询与ExpandableListView / SimpleCursorTreeAdapter的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在开发用于显示一些RSS提要的Andr​​oid应用程序的进展情况(是的,我知道有许多应用程序是这样的话)。要显示的数据是由内容提供商的支持,我想向下兼容的API级别4

I'm in the progress of developing an Android app for displaying a number of RSS feeds (yes, I know there are many apps like this already). The data to be displayed is backed by a content provider, and I want to be backward compatible with API level 4.

我使用的是 ExpandableListView 来显示三种不同的RSS feed的内容。该 ExpandableListView 的适配器是作为一个子类的 SimpleCursorTreeAdapter

I'm using an ExpandableListView to display the content of three different RSS feeds. The ExpandableListView's adapter is implemented as a sub-class of 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) ...
    }
}

通过这种设置,所有的内容都加载预期。然而,用户界面挂起/口吃随机在列表内容的加载。通常不足以让一个ANR,但仍然明显,很烦人!

With this setup, all content is loaded as expected. However, the UI hangs/stutters randomly during the loading of the list content. Usually not enough to get an ANR, but still noticeable and very annoying!

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

In order to debug this issue, I enabled android.os.StrictMode (great new feature/tool btw!), and started up the emulator (on Android 2.3). When the list content is loaded, I get the following StrictMode output:


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一个坏主意了!

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!

我一看<一href="http://developer.android.com/reference/android/widget/CursorTreeAdapter.html#getChildrenCursor%28android.database.Cursor%29"相对=nofollow> JavaDoc的 CursorTreeAdapter (超一流的 SimpleCursorTreeAdapter )和 getChildrenCursor()这样说的:

I had a look at the JavaDoc (API level 4) of CursorTreeAdapter (a super-class of SimpleCursorTreeAdapter) and for getChildrenCursor() it says:

如果你想异步查询提供商prevent阻塞UI,可以返回null,在稍后的时间呼叫setChildrenCursor(INT,光标)。的。

太棒了!让我们做到这一点!我改变我的执行 getChildrenCursor的()开始负责执行的查询和设置光标孩子适配器上一个新的任务。在已经开始的工作,我只是返回null在 getChildrenCursor()

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模拟器的应用程序,并启动它。它的工作就像一个魅力,再见无响应的用户界面!但喜悦并没有持续多久......接下来要做的事情就是运行在目标设备上相同的code(在这种情况下,三星Galaxy S运行Android 2.2)。然后我得到了以下异常名单提要内容的加载过程中:

I reinstalled the app on the 2.3 emulator and started it up. It worked like a charm, bye bye non-responsive UI! But the joy didn't last long ... The next thing to do was to run the same code on the target device (in this case a Samsung Galaxy S running Android 2.2). I then got the following Exception during the loading of the list feed content:


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 来源$ C ​​$ C告诉我,有没有办法,它可以应付空异步从 getChildrenCursor()。他们似乎已经解决了Android 2.3的这个问题,但怎么是你应该得到它周围在早期版本的Andr​​oid?难道我真的有写我自己的实施 CursorTreeAdapter ,以便能够刷新孩子光标异步?

A quick look at the source code of SimpleCursorTreeAdapter tells me that there is no way that it can cope with null being returned asynchronously from getChildrenCursor(). They seem to have solved this problem in Android 2.3, but how are you supposed to get around it in earlier versions of Android? Do I really have to write my own implementation of CursorTreeAdapter to be able to refresh the children cursor asynchronously?

有没有人有同样的问题,甚至发现了一个(可行)解决方法吗?如果不是,可能有人给我如何进行的提示!? 我真的AP preciate任何帮助我可以得到!

Has anybody had the same problem and perhaps even found a (feasible) workaround? If not, could anybody give me a hint on how to proceed!? I would really appreciate any help I can get!

在此先感谢!

问候, 雅各布

推荐答案

如果他们固定在2.3 SimpleCursorTreeAdapter,你为什么不只是下载的java文件,并将其包含在您的项目,并使用该版本,而不是一在手机上?

If they fixed it in the 2.3 SimpleCursorTreeAdapter, why don't you just download the java file and include it in your project and use that version rather than the one on the phone?

我还没有看在code,但只要他们没有做出任何新的2.3 API调用,它应该工作。

I haven't looked at the code, but as long as they didn't make any new 2.3 API calls, it should work.

这篇关于运行UI线程SQLite的查询与ExpandableListView / SimpleCursorTreeAdapter的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆