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