我有一个包含 200 个项目的列表视图。我为每一行使用自定义视图。有一段代码需要一些时间来计算,因此列表在滚动时挂起并且加载速度很慢(2-3 秒)。
我对 SimpleCursorAdapter 进行了子类化,并使用了 Filterable 和 SectionIndexer。
我想首先显示记录的名称,然后将计算放入一个线程中,然后在完成后显示。
如何推迟一些工作,然后更新列表视图以包含计算数据?这应该在没有用户交互的情况下即时显示。
我有一个包含 200 个项目的列表视图。我为每一行使用自定义视图。有一段代码需要一些时间来计算,因此列表在滚动时挂起并且加载速度很慢(2-3 秒)。
我对 SimpleCursorAdapter 进行了子类化,并使用了 Filterable 和 SectionIndexer。
我想首先显示记录的名称,然后将计算放入一个线程中,然后在完成后显示。
如何推迟一些工作,然后更新列表视图以包含计算数据?这应该在没有用户交互的情况下即时显示。
由于 android Android UI 是单线程的,每当您执行长时间操作时,它都会被阻止。
您可以执行常规 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 的更多信息,请参阅此
嗯,有趣的问题。以下是一些快速的想法:
1)将可以直接检索的值,即您输入的记录名称直接放入列表中。为可能需要一段时间计算的所有内容保留默认值,例如“正在加载...”。
2) 创建第二个线程来进行计算,但要确保它不会计算所有内容,请使用 ListView 的 onScrollStateChanged 侦听器。这使您仅在列表空闲或通过触摸滚动缓慢滚动时才执行后台工作。换句话说,当它处于“fling”模式时不要打扰,因为在计算完成之前这些行早就过去了。
3)我不完全确定如何将加载阶段排入线程中。您只想拥有一个加载线程——为每一行打开一个新线程会相当混乱,而且由于手机不是多核的,也毫无意义——但这意味着线程必须有一个排队系统。我的意思是线程必须知道哪些行正在等待计算,但我还没有想到你会怎么做。但是,这也必须与哪些行可见。线程计算列表中很久以前的行的信息没有意义。
4) 每当加载线程完成特定行时,您可以在列表适配器上调用 notifyDatasetChanged()。如果 ListView 尝试刷新每一行的数据而不仅仅是那些可见的数据,这可能会变得有点繁重,但您必须尝试才能看到。
我希望这些想法能有所帮助!
作为对评论的回应:假设您询问一行何时可见,您可以通过实现 ListView.OnScrollListener 来做到这一点。我从 ApiDemos List13 中获得灵感,但以下是相关的代码:
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
都会调用。如果尚未计算信息,您可以将自定义代码放入其中以执行诸如放置“正在加载...”之类的操作,或者如果已计算,则实际显示它。
顺便说一句,你在这个需要这么长时间的列表中实际计算的是什么?