我的Android设备上运行了以下代码。它运行良好,并显示我的列表项奇妙。它也很聪明,它只在ArrayAdapter需要时才下载数据。但是,当缩略图的下载正在进行时,整个列表会停止,并且在完成下载之前无法滚动。有什么方法可以解决这个问题,所以它仍然会愉快地滚动,也许会显示下载图像的占位符,完成下载,然后显示?
我想我只需要将我的downloadImage类放入它自己的线程中,以便它与UI分开执行。但是如何将它添加到我的代码中是个谜!
对此的任何帮助都将非常感激。
private class CatalogAdapter extends ArrayAdapter<SingleQueueResult> {
private ArrayList<SingleQueueResult> items;
//Must research what this actually does!
public CatalogAdapter(Context context, int textViewResourceId, ArrayList<SingleQueueResult> items) {
super(context, textViewResourceId, items);
this.items = items;
}
/** This overrides the getview of the ArrayAdapter. It should send back our new custom rows for the list */
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.mylists_rows, null);
}
final SingleQueueResult result = items.get(position);
// Sets the text inside the rows as they are scrolled by!
if (result != null) {
TextView title = (TextView)v.findViewById(R.id.mylist_title);
TextView format = (TextView)v.findViewById(R.id.mylist_format);
title.setText(result.getTitle());
format.setText(result.getThumbnail());
// Download Images
ImageView myImageView = (ImageView)v.findViewById(R.id.mylist_thumbnail);
downloadImage(result.getThumbnail(), myImageView);
}
return v;
}
}
// This should run in a seperate thread
public void downloadImage(String imageUrl, ImageView myImageView) {
try {
url = new URL(imageUrl);
URLConnection conn = url.openConnection();
conn.connect();
InputStream is = conn.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
Bitmap bm = BitmapFactory.decodeStream(bis);
bis.close();
is.close();
myImageView.setImageBitmap(bm);
} catch (IOException e) {
/* Reset to Default image on any error. */
//this.myImageView.setImageDrawable(getResources().getDrawable(R.drawable.default));
}
}
答案 0 :(得分:4)
以下是我在我的应用中使用的简化版本:
// this lives in Application subclass and is reused
public static final ExecutorService EXECUTOR = Executors.newSingleThreadExecutor();
// the method itself
public void attachImage(final String fileUrl, final ImageView view) {
EXECUTOR.execute(new Runnable() {
@Override
public void run() {
final Drawable image = methodThatGetsTheImage(fileUrl);
if (image != null) {
view.post(new Runnable() {
@Override
public void run() {
view.setImageDrawable(drawable);
}
});
}
}
});
}
答案 1 :(得分:1)
您还可以查看cwac-thumbnail以获取插入式解决方案(尽管它比上面的简单解决方案有更多的开销)。我几乎在任何可以下载网页图片的地方使用它都非常成功;你基本上为你的应用程序设置了一些全局缓存选项,然后将ListAdapter包装在ThumbnailAdapter中,列表中列出了image:ids的image:ids,并在适配器的getView方法中的imageviews上调用setTag(imageUrl),它处理剩下的事情。
答案 2 :(得分:0)
是。您应该尽可能避免在UI线程上运行。当你在getView()中时,你在UI线程上。要突破这样做:
new Thread(new Runnable(){
public void run() {
// your code here
}}).start();
然后,当您需要以某种方式修改视图时,请返回到这样的UI线程:
runOnUiThread(new Runnable(){
public void run() {
// your view-modifying code here
}});
..或使用View.post()机制。
在您的示例中,将会发生的事情是,在图像可供显示之前,该项目将显示在屏幕上。我建议使用'loading'微调器或其他占位符来向用户指示发生了什么。
您可以在实践中多次这样嵌套,尽管您将达到简化设计的顺序。匿名类可能在内存方面效率低下,并且在没有取消机制的情况下触发大量线程可能有其自身的缺点。
在getView()退出后修改视图的副作用可能会遇到一些困难。某些视图可能需要使用invalidate()来使其更改生效。还要注意,如果要在getView()中回收视图,则应确保在执行视图更改代码时视图仍在用于您正在应用的内容。 setTag()/ getTag()在此处用于存储您稍后可以检查的一些数据ID,以确保您的View未被回收。