可能重复:Android - 如何在ListView中延迟加载图像
我正在使用自定义适配器处理listview . 我想加载图像和文本视图 . 图像是从互联网网址加载的 . 我只是想显示可见列表项的图像以供用户使用 . 我提到Shelves opensource project example from romainguy,但是要理解代码很复杂 . 对于初学者级别,我只想知道如何处理适配器和活动之间的标记 . 从commonsware example我可以在适配器上设置标签,但无法在列表视图的空闲状态下显示相应的图像 . 请帮我解决你的想法 . 示例代码更容易理解 .
谢谢 .
编辑:
ApiDemos中Efficient和Slow适配器的组合更有助于理解 .
对高效适配器示例所做的更改如下:
public class List14 extends ListActivity implements ListView.OnScrollListener {
// private TextView mStatus;
private static boolean mBusy = false;
static ViewHolder holder;
public static class EfficientAdapter extends BaseAdapter {
private LayoutInflater mInflater;
private Bitmap mIcon1;
private Bitmap mIcon2;
public EfficientAdapter(Context context) {
// Cache the LayoutInflate to avoid asking for a new one each time.
mInflater = LayoutInflater.from(context);
// Icons bound to the rows.
mIcon1 = BitmapFactory.decodeResource(context.getResources(),
R.drawable.icon48x48_1);
mIcon2 = BitmapFactory.decodeResource(context.getResources(),
R.drawable.icon48x48_2);
}
/**
* The number of items in the list is determined by the number of
* speeches in our array.
*
* @see android.widget.ListAdapter#getCount()
*/
public int getCount() {
return DATA.length;
}
/**
* Since the data comes from an array, just returning the index is
* sufficent to get at the data. If we were using a more complex data
* structure, we would return whatever object represents one row in the
* list.
*
* @see android.widget.ListAdapter#getItem(int)
*/
public Object getItem(int position) {
return position;
}
/**
* Use the array index as a unique id.
*
* @see android.widget.ListAdapter#getItemId(int)
*/
public long getItemId(int position) {
return position;
}
/**
* Make a view to hold each row.
*
* @see android.widget.ListAdapter#getView(int, android.view.View,
* android.view.ViewGroup)
*/
public View getView(int position, View convertView, ViewGroup parent) {
// A ViewHolder keeps references to children views to avoid
// unneccessary calls
// to findViewById() on each row.
// When convertView is not null, we can reuse it directly, there is
// no need
// to reinflate it. We only inflate a new View when the convertView
// supplied
// by ListView is null.
if (convertView == null) {
convertView = mInflater.inflate(R.layout.list_item_icon_text,
null);
// Creates a ViewHolder and store references to the two children
// views
// we want to bind data to.
holder = new ViewHolder();
holder.text = (TextView) convertView.findViewById(R.id.text);
holder.icon = (ImageView) convertView.findViewById(R.id.icon);
convertView.setTag(holder);
} else {
// Get the ViewHolder back to get fast access to the TextView
// and the ImageView.
holder = (ViewHolder) convertView.getTag();
}
if (!mBusy) {
holder.icon.setImageBitmap(mIcon1);
// Null tag means the view has the correct data
holder.icon.setTag(null);
} else {
holder.icon.setImageBitmap(mIcon2);
// Non-null tag means the view still needs to load it's data
holder.icon.setTag(this);
}
holder.text.setText(DATA[position]);
// Bind the data efficiently with the holder.
// holder.text.setText(DATA[position]);
return convertView;
}
static class ViewHolder {
TextView text;
ImageView icon;
}
}
private Bitmap mIcon1;
private Bitmap mIcon2;
@Override
public void onCreate(Bundle savedInstanceState) {
mIcon1 = BitmapFactory.decodeResource(this.getResources(),
R.drawable.icon48x48_1);
mIcon2 = BitmapFactory.decodeResource(this.getResources(),
R.drawable.icon48x48_2);
super.onCreate(savedInstanceState);
setListAdapter(new EfficientAdapter(this));
getListView().setOnScrollListener(this);
}
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
}
public void onScrollStateChanged(AbsListView view, int scrollState) {
switch (scrollState) {
case OnScrollListener.SCROLL_STATE_IDLE:
mBusy = false;
int first = view.getFirstVisiblePosition();
int count = view.getChildCount();
for (int i = 0; i < count; i++) {
holder.icon = (ImageView) view.getChildAt(i).findViewById(
R.id.icon);
if (holder.icon.getTag() != null) {
holder.icon.setImageBitmap(mIcon1);
holder.icon.setTag(null);
}
}
// mStatus.setText("Idle");
break;
case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
mBusy = true;
// mStatus.setText("Touch scroll");
break;
case OnScrollListener.SCROLL_STATE_FLING:
mBusy = true;
// mStatus.setText("Fling");
break;
}
}
private static final String[] DATA = { "Abbaye de Belloc",
"Abbaye du Mont des Cats", "Abertam", "Abondance", "Ackawi",
"Acorn", "Adelost", "Affidelice au Chablis", "Afuega'l Pitu"};
}
它现在工作正常 . 但是当滚动状态时它没有正确地重新加载图像 . 某些项目间隔未显示图像2 . 这是加载图像的正确顺序 . 但不是列表中的所有项目 . 固体项间隔之间发生不匹配 . 怎么纠正呢?
5 回答
Praveen -
正如您已经在此发现我的博客文章,我只是想将其推回到Stackoverflow,以便其他人可以使用它 .
以下是基本讨论:http://ballardhack.wordpress.com/2010/04/05/loading-remote-images-in-a-listview-on-android/
还有一个我后来记录的类,它使用一个线程和一个回调来加载图像:
http://ballardhack.wordpress.com/2010/04/10/loading-images-over-http-on-a-separate-thread-on-android/
Update: 为了解决您的特定异常,我认为
getChildAt
列表中返回的视图不是ImageView
- 它是用于保存图像和文本的任何布局视图 .Update to include relevant code :( Per @ george-stocker的推荐)
这是我使用的适配器:
我知道了 . 这是我想要的完美代码 . 延迟加载适用于自定义适配器只是可见列表项的图标 . 希望它对初学者有所帮助
据我了解,滚动完成后需要更新列表 . 这很简单 . 这是您的固定代码:
notifyDataSetChanged将告诉适配器重新显示所有可见项,因此它们将与image2一起显示 .
据我所见,静态
ViewHolder
没有任何帮助 . 尝试将整个onScrollStateChanged
函数放在/*
和*/
之间,删除static ViewHolder
行,并将holder = new ViewHolder();
更改为ViewHolder holder = new ViewHolder();
.啊,检查你的logcat以确保你的应用程序没有被杀死并重新启动 . 大多数手机将您的总应用程序大小限制为16mb或24mb . 很容易加载一堆图像,运行,杀死,重新启动,并让你的onPause不会在屏幕上加载大数据 . 这是穷人的收集 .