android中线程加载的Web图像
我在ListActivity中有一个扩展BaseAdapter:android中线程加载的Web图像,android,image,list,multithreading,adapter,Android,Image,List,Multithreading,Adapter,我在ListActivity中有一个扩展BaseAdapter: private static class RequestAdapter extends BaseAdapter { 其中定义了一些处理程序和可运行程序 // Need handler for callbacks to the UI thread final Handler mHandler = new Handler(); // Create runnable for posting final Run
private static class RequestAdapter extends BaseAdapter {
其中定义了一些处理程序和可运行程序
// Need handler for callbacks to the UI thread
final Handler mHandler = new Handler();
// Create runnable for posting
final Runnable mUpdateResults = new Runnable() {
public void run() {
loadAvatar();
}
};
protected static void loadAvatar() {
// TODO Auto-generated method stub
//ava.setImageBitmap(getImageBitmap("URL"+pic));
buddyIcon.setImageBitmap(avatar);
}
在适配器的getView函数中,我得到如下视图:
if (convertView == null) {
convertView = mInflater.inflate(R.layout.messageitem, null);
// Creates a ViewHolder and store references to the two children views
// we want to bind data to.
holder = new ViewHolder();
holder.username = (TextView) convertView.findViewById(R.id.username);
holder.date = (TextView) convertView.findViewById(R.id.dateValue);
holder.time = (TextView) convertView.findViewById(R.id.timeValue);
holder.notType = (TextView) convertView.findViewById(R.id.notType);
holder.newMsg = (ImageView) convertView.findViewById(R.id.newMsg);
holder.realUsername = (TextView) convertView.findViewById(R.id.realUsername);
holder.replied = (ImageView) convertView.findViewById(R.id.replied);
holder.msgID = (TextView) convertView.findViewById(R.id.msgID_fr);
holder.avatar = (ImageView) convertView.findViewById(R.id.buddyIcon);
holder.msgPreview = (TextView) convertView.findViewById(R.id.msgPreview);
convertView.setTag(holder);
} else {
// Get the ViewHolder back to get fast access to the TextView
// and the ImageView.
holder = (ViewHolder) convertView.getTag();
}
class GetImageTask extends AsyncTask<String, int[], Bitmap> {
@Override
protected Bitmap doInBackground(String... params) {
Bitmap bitmap = null;
// Get your image bitmap here
return bitmap;
}
@Override
protected void onPostExecute(Bitmap bitmapResult) {
super.onPostExecute(bitmapResult);
// Add your image to your view
holder.avatar.setImageBitmap(bitmapResult);
}
}
图像以这种方式加载:
Thread sepThread = new Thread() {
public void run() {
String ava;
ava = request[8].replace(".", "_micro.");
Log.e("ava thread",ava+", username: "+request[0]);
avatar = getImageBitmap(URL+ava);
buddyIcon = holder.avatar;
mHandler.post(mUpdateResults);
//holder.avatar.setImageBitmap(getImageBitmap(URL+ava));
}
};
sepThread.start();
现在,我遇到的问题是,如果有更多的项目需要显示同一张图片,并不是所有的图片都能显示出来。当你上下滚动列表时,你可能会把它们都填满
当我尝试注释掉的行(holder.avatar.setImageBitmap…)时,应用程序有时会强制关闭“只有创建视图的线程才能请求…”。但只是有时候
你知道我该怎么解决这个问题吗?任一选项。因此,您不应该尝试在其他线程中将图像添加到视图中。我的建议是使用类似以下内容的异步任务:
if (convertView == null) {
convertView = mInflater.inflate(R.layout.messageitem, null);
// Creates a ViewHolder and store references to the two children views
// we want to bind data to.
holder = new ViewHolder();
holder.username = (TextView) convertView.findViewById(R.id.username);
holder.date = (TextView) convertView.findViewById(R.id.dateValue);
holder.time = (TextView) convertView.findViewById(R.id.timeValue);
holder.notType = (TextView) convertView.findViewById(R.id.notType);
holder.newMsg = (ImageView) convertView.findViewById(R.id.newMsg);
holder.realUsername = (TextView) convertView.findViewById(R.id.realUsername);
holder.replied = (ImageView) convertView.findViewById(R.id.replied);
holder.msgID = (TextView) convertView.findViewById(R.id.msgID_fr);
holder.avatar = (ImageView) convertView.findViewById(R.id.buddyIcon);
holder.msgPreview = (TextView) convertView.findViewById(R.id.msgPreview);
convertView.setTag(holder);
} else {
// Get the ViewHolder back to get fast access to the TextView
// and the ImageView.
holder = (ViewHolder) convertView.getTag();
}
class GetImageTask extends AsyncTask<String, int[], Bitmap> {
@Override
protected Bitmap doInBackground(String... params) {
Bitmap bitmap = null;
// Get your image bitmap here
return bitmap;
}
@Override
protected void onPostExecute(Bitmap bitmapResult) {
super.onPostExecute(bitmapResult);
// Add your image to your view
holder.avatar.setImageBitmap(bitmapResult);
}
}
有关异步任务的更多信息,请查看:
当调用getView时,您将获得一个化身ImageView。您应该将此实例传递给sepThread,sepThread应该将此实例传递给mUpdateResults。通过这种方式,位图将精确显示为其下载目的的ImageView。否则,位图将显示给不正确的BuddyIcon实例。您的线程下载图像已经有一段时间了,当它准备好时,BuddyIcon引用了另一个ImageView,因为已经调用了另一个getView 应该是这样的:
public View getView(...){
//skip
(new SepThread(holder.avatar)).start();
}
public class SepThread extends Thread() {
ImageView imageView;
public SepThread(ImageVIew iv){
imageView=iv;
}
public void run() {
//skip
Bitmap avatar = getImageBitmap(URL+ava);
mHandler.post(new UpdateResults(imageView, avatar));
}
};
class UpdateResults extends Runnable() {
ImageView imageView;
Bitmap bitmap;
public UpdateResults(ImageView iv, Bitmap b){
imageView=iv;
bitmap=b;
}
public void run() {
loadAvatar(imageView, bitmap);
}
};
protected static void loadAvatar(ImageView iv, Bitmap b) {
iv.setImageBitmap(b);
}
当然,正如disretrospect上面所说的,您应该了解这些视图
我制作了一个完整的LazyList示例,并发布了源代码,可能也会有所帮助。有一个很棒的库友,可以从web下载/缓存图像
只需输入imageview和url,您就完成了=)几周前我遇到了同样的问题,我认为这是由于从web加载的速度,因为当我改变加载方式时,每一张图片都正确显示。现在,我正在下载应用程序开头的图片(仅在请求时),并将其放入数据库,然后将其从数据库获取到listview。在应用程序打开时缓存图片也是值得的。私有静态HashMap-sImageCache;将它们存储在hashmap中,并使用url作为标识符。如果在位图加载完成之前回收与位图相关的视图,在快速滚动期间会发生什么?我不知道这个类,比使用
Thread
s和Handler
sYeh要干净得多,在列表视图中缓慢加载图像时,这可能很棘手。最好是传入一个对象,该对象包含imageView本身和要加载的图像的url。将这些存储在列表中。然后,当您尝试加载新图像时,请检查此列表中是否存在该视图的任何早期实例,并将其删除。此外,如果你正在做一个快速滚动,我会禁用图像加载,直到滚动速度减慢。让我看看我是否理解这个ok。我制作了一个包含imageview和url的列表。那么,当一个图片加载的时候,我会在列表中签入吗?你的意思是检查相同的URL吗?为什么要删除它们呢?所以每次加载图像时,都要将url和imageview包装在一个对象中,并将其放入列表中。然后检查列表中较早的条目,查看您的新对象.imageView.equals(列表中的旧imageView)是否相等。如果您获得了一个匹配项,那么您可以从列表中删除旧条目,因为它现在的视图已被回收。一旦加载了一个图像,请确保也将其从列表中删除。如何将实例传递给线程?然后回到runnable?我同意这是最好的办法。