我有一个包含200个项目的列表视图。我为每一行使用自定义视图。有一段代码需要一些时间来计算,因此列表会在滚动时挂起并以慢速(2-3秒)加载。
我已经使用了SimpleCursorAdapter,并使用了Filterable和SectionIndexer。
我想最初显示记录的名称,并在计算中添加一个线程,并在完成后显示。
如何推迟一些工作,稍后更新列表视图以包含计算数据?这应该在没有用户交互的情况下即时显示。
答案 0 :(得分:2)
由于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 see this
的详细信息答案 1 :(得分:1)
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
。您可以在其中放置自定义代码,以便在尚未计算信息的情况下执行“加载...”等操作,或者实际显示该信息(如果有)。
顺便说一下,你在这个列表中实际计算了多长时间?