Android 如何为以后的ListView显示安排繁重的工作?

Android 如何为以后的ListView显示安排繁重的工作?,android,listview,multithreading,cursor,Android,Listview,Multithreading,Cursor,我有一个包含200个项目的列表视图。我为每一行使用自定义视图。有一段代码需要花费一些时间来计算,因此列表在滚动时会挂起,并以慢速(2-3秒)加载 我使用Filterable和SectionIndexer对SimpleCursorAdapter进行了子类化 我想首先显示记录的名称,然后将计算放在一个线程中,然后在完成后显示 如何将一些工作推后,然后更新listview以包含计算数据?这应该在没有用户交互的情况下动态显示。嗯,有趣的问题。以下是一些快速的想法: 1) 将可直接检索的值,即您输入的记录

我有一个包含200个项目的列表视图。我为每一行使用自定义视图。有一段代码需要花费一些时间来计算,因此列表在滚动时会挂起,并以慢速(2-3秒)加载

我使用Filterable和SectionIndexer对SimpleCursorAdapter进行了子类化

我想首先显示记录的名称,然后将计算放在一个线程中,然后在完成后显示


如何将一些工作推后,然后更新listview以包含计算数据?这应该在没有用户交互的情况下动态显示。

嗯,有趣的问题。以下是一些快速的想法:

1) 将可直接检索的值,即您输入的记录名称,直接放入列表中。为可能需要一段时间才能计算的所有内容保留默认值,例如“加载…”

2) 创建第二个线程来执行计算,但要确保它不会计算所有内容,请使用ListView的onScrollStateChanged侦听器。这只允许您在列表空闲或通过触摸滚动缓慢滚动时进行后台工作。换句话说,当它处于“fling”模式时,不必费心,因为在计算完成之前,这些行早已过去了

3) 我不完全确定如何将加载阶段排队到线程中。您只希望有一个加载线程-为每一行打开一个新线程将相当混乱,而且毫无意义,因为手机不是多核的-但这意味着线程必须有一个排队系统。我的意思是线程必须知道哪些行正在等待计算,但我还没有想到你会怎么做。但是,这还必须与哪些行可见相关联。线程计算列表中很久以前的行的信息没有意义

4) 每当加载线程完成某一行时,就可以在列表适配器上调用notifyDatasetChanged()。如果ListView尝试刷新每一行的数据,而不仅仅是那些可见的数据,这可能会有点沉重,但您必须进行实验才能看到

我希望这些想法能有所帮助


作为对注释的回应:假设您询问行何时可见,可以通过实现ListView.OnScrollListener来实现。我的灵感来自ApiDemos列表13,但以下是相关的代码:

public class YourClass extends ListActivity implements ListView.OnScrollListener {
    public void onCreate(Bundle sIS){
        (...)
        // Note, you may have to write your own list adapter, extending BaseAdapter
        // See List13 in Api Demos for an example if you're not sure how to do that
        setListAdapter(yourImageAdapter); 
        getListView().setOnScrollListener(this);
    }

    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
            int totalItemCount) {
        Log.d(LOG_TAG, "onScroll, firstVisibleItem = " + firstVisibleItem +
                ", visibleItemCount = " + visibleItemCount
                + ", totalItemCount = " + totalItemCount);
    }

    public void onScrollStateChanged(AbsListView view, int scrollState) {
        Log.d(LOG_TAG, "onScrollStateChanged called, scrollState = " + scrollState);
        switch (scrollState) {
        case OnScrollListener.SCROLL_STATE_IDLE:
            int first = view.getFirstVisiblePosition();
            int count = view.getChildCount();

            Log.d(LOG_TAG, "first = " + first + ", count = " + count);

            break;
        case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
            //Scrolling with the finger touching the screen
            break;

        case OnScrollListener.SCROLL_STATE_FLING:
            // User 'threw' the list up or down and it's scrolling rapidly
            break;
        }
    }
}
这将告诉您关于列表的所有信息:是否滚动、哪些内容可见等等。如果您在加载线程中使用这些信息仅对可见行执行后台工作,这将有助于减少不必要的开销

关于BaseAdapter的另一点:我没有尝试过使用任何其他形式的列表适配器,所以可能它们都是一样的,但是BaseAdapter有一个非常有用的地方,那就是它允许您单独处理每行的“膨胀”。每次列表即将显示新行时,都会调用
getView
。如果信息尚未计算,您可以将自定义代码放入其中,以执行诸如“加载…”之类的操作,如果信息已计算,则可以实际显示它


顺便问一下,在这个列表中,你到底在计算什么,花费了这么长的时间?

由于android用户界面是单线程的,所以每当你执行长操作时,它都会被阻止

您可以执行常规java线程,并在主UI类中有一个Handler(),您可以将信息反馈到该类中。但是

最简单的方法是创建一个AsyncTask()。它们是java线程,略有变化。他们可以在主计算之前/之后执行UI操作。例如:

 private class AndroidThread extends AsyncTask {
      protected Object doInBackground(Object... params) {
           return result;
      }

      protected void onPostExecute(Object result) {
           // do things here with the result of the doInBackground function
           // Like: "UiElement"."performTask(result)"
      }
 }

有关AsyncTask的更多信息

如何检测行的绘制时间?我有一个联系人列表,我计算联系人即将到来的生日及其年龄(显示年龄,如7个月内21岁)