1

我有一个返回数千行的 SQLite 查询,我想使用ListView.

为了保持我的 UI 线程响应,我ListAdapter在后台线程上创建。

然而,花费最多时间(并且可能导致 ANR)的语句是ListActivity.setListAdapter我必须在 UI 线程上执行的......有什么建议吗?

公共类 CursorTestActivity 扩展 ListActivity {

    私有静态最终字符串 LOGTAG = "DBTEST";

    私有数据库管理器 mDbManager;
    私人光标 mCursor;
    私有处理线程 mIOWorkerThread;
    私有处理程序 mIOHandler;
    私有处理程序 mUIHandler;

    @覆盖
    公共无效 onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mDbManager = new DatabaseManager(this);

        mUIHandler = 新的处理程序();
        createIOWorkerThread();

        log("创建光标");
        mCursor = mDbManager.getCursor(); // 执行 db.query(...)
        开始管理光标(mCursor);

        mIOHandler.post(new Runnable() {
            @覆盖
            公共无效运行(){
                setMyListAdapter();
            }
        });
        log("onCreate 完成");
    }

    私人无效 setMyListAdapter() {
        log("构造适配器");
        // CustomCursorAdapter 实现 bindView 和 newView
        final CustomCursorAdapter listAdapter = new CustomCursorAdapter(this,
                mCursor,假);
        log("完成构建适配器");
        mUIHandler.post(new Runnable() {
            @覆盖
            公共无效运行(){
                log("设置列表适配器");
                设置列表适配器(列表适配器);// 返回的行越多越慢
                log("设置内容视图");
                设置内容视图(R.layout.main);
                log("完成设置内容视图");
            }
        });
    }

    私人无效createIOWorkerThread(){
        mIOWorkerThread = new HandlerThread("io_thread");
        mIOWorkerThread.start();
        Looper looper = mIOWorkerThread.getLooper();
        mIOHandler = new Handler(looper);
    }

    私人无效destroyIOWorkerThread(){
        如果(mIOWorkerThread == null)
            返回;
        Looper looper = mIOWorkerThread.getLooper();
        if (looper != null) {
            looper.quit();
        }
    }

    @覆盖
    公共无效 onDestroy() {
        super.onDestroy();
        如果(mDbManager != null)
            mDbManager.close();
        destroyIOWorkerThread();
    }

    私有静态无效日志(字符串 s){
        Log.d(LOGTAG, s);
    }

}
4

2 回答 2

0

游标是延迟加载的,因此在第一次数据访问时会加载游标 - getCount 就是这样的访问。setAdapter 方法在游标上调用 getCount - 存在性能问题。

  • 您可以在适配器中设置空光标并在加载光标期间显示空列表。然后在适配器中使用 changeCursor 方法将光标更改为新光标。
  • 您可以首先在第一个查询中获取例如 100 行,然后在后台加载更多行并将更改光标到新行。
  • 或者您可以创建自己的 Cursor 实现,该实现具有自己的 getCount 实现并根据请求获取所需的行。
于 2011-05-14T20:12:42.190 回答
0
  1. 考虑使用 PagedListAdapter。它与@pawelziemba 提出的类似,但由 Android 框架https://developer.android.com/reference/android/arch/paging/PagedListAdapter提供——如果你可以使用 Room 框架,你可以免费获得它
  2. 在 ViewHolder 中异步加载数据 - 如果 viewHolder 重新绑定,请记住取消工作,并在需要时缓存加载的数据
于 2020-05-28T07:22:12.500 回答