【发布时间】:2014-07-24 07:27:36
【问题描述】:
我正在开发一个 Andorid 应用程序,该应用程序将通过 ListView 列出很多书籍,实际上我已经使用 ListView 有一段时间了,我知道它的基本用法。
我还阅读了这篇论文:http://lucasr.org/2012/04/05/performance-tips-for-androids-listview/
但是我发现即使我按照文章中提到的技巧,例如使用“视图回收”和“异步加载”,滚动 ListView 看起来也不流畅。
这是适配器:
class BookAdapter extends ArrayAdapter<Book> {
private List<Book> data;
public BookAdapter(Context context, int resource, List<Book> data) {
super(context, resource, data);
this.data = data;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = new DynamicBookView(getContext());
}
Book bk = getItem(position);
DynamicBookView bookView = ((DynamicBookView) convertView); //so said view recycling
bookView.setBook(bk);
return convertView;
}
@Override
public int getCount() {
return data.size();
}
@Override
public Book getItem(int position) {
return data.get(position);
}
public void swap(List<Book> books) {
data.clear();
data.addAll(books);
notifyDataSetChanged();
}
}
还有观点:
public class DynamicBookView extends RelativeLayout {
private ImageView bImage;
private TextView bName;
private TextView bAuthor;
private TextView bDesc;
AsyncHttpClient asyncHttpClient = new AsyncHttpClient();
RequestHandle lastRequset;
public DynamicBookView(Context context) {
this(context, null);
}
public DynamicBookView(Context context, AttributeSet attrs) {
super(context, attrs);
View v = LayoutInflater.from(context).inflate(R.layout.common_dynamic_book, null);
addView(v, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
bImage = (ImageView) v.findViewById(R.id.book_image);
bName = (TextView) v.findViewById(R.id.book_name);
bAuthor = (TextView) v.findViewById(R.id.book_author);
bDesc = (TextView) v.findViewById(R.id.book_description);
}
public void setBook(final Book book) {
DynamicBookView.this.reset();
bName.setText(book.name);
bAuthor.setText(book.author);
bDesc.setText(book.description);
if (book.icon != null)
fetchImageForBook(book);
if (!book.loaded) {
// loadBook is an async operation which use `AsyncHttpClient` too
BookServer.getInstance().loadBook(book, new BookServer.BookServerLoadListener() {
@Override
protected void onComplete() {
setBook(book);
}
});
}
}
private void fetchImageForBook(Book book) {
//get from local:
if (lastRequset != null) {
lastRequset.cancel(true);
}
lastRequset = asyncHttpClient.get(book.icon, new AsyncHttpResponseHandler() {
@Override
public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
bImage.setImageBitmap(BitmapFactory.decodeByteArray(responseBody, 0, responseBody.length));
}
@Override
public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
}
});
}
public void reset() {
if (lastRequset != null) {
lastRequset.cancel(true);
}
bName.setText("");
bAuthor.setText("");
bDesc.setText("");
bImage.setImageBitmap(null);
}
}
所以我想知道是否有什么我可以做的让滚动更流畅?
更新:1
一旦我删除加载代码:
public void setBook(final Book book) {
DynamicBookView.this.reset();
bName.setText(book.name);
bAuthor.setText(book.author);
bDesc.setText(book.description);
}
那么性能可以接受。
顺便说一句,请求需要 2-3 秒才能得到响应。
更新:2
我不确定你是否注意到,列表项的每个视图都会触发两个异步任务:
public void setBook(final Book book) {
bName.setText(book.name);
bAuthor.setText(book.author);
bDesc.setText(book.description);
if (book.icon != null)
fetchImageForBook(book);
if (!book.loaded) {
// loadBook is an async operation which use `AsyncHttpClient` too
BookServer.getInstance().loadBook(book, new BookServer.BookServerLoadListener() {
@Override
protected void onComplete() {
setBook(book);
}
});
}
}
通常,Book 只包含name 和id,然后我必须像author description 和image 字段那样检索书的详细信息。然后我将触发另一个任务来获取图像。现在我评论了fetchImageForBook(book);这行,也就是说我只是显示书籍而不加载图像,但滚动仍然不流畅。(我一次无法获取信息,因为我们不提供服务)
【问题讨论】:
-
如果把http操作换成本地的,性能会不会提升?
-
我还没有添加本地支持,因为数据会经常变化,所以需要在线。
-
好的,如果删除 http 元素会提高性能吗?您的结构是根据视图的请求从网络获取元素,所以我会认为这是造成性能问题的原因?
-
是的,一旦我删除了异步加载任务(评论
loadBook方法),那么性能是可以接受的。 -
@hguser 我不知道为什么你必须创建一个RelativeLayout的子类并自己添加视图,为什么不将common_dynamic_book.xml作为你的适配器的项目视图,你可以使用ViewHolder图案。查看本教程:jmsliu.com/1431/…