[英]How do I move my image downloader into a seperate thread on Android?
我的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));
}
}
这是我在应用程序中使用的内容的简化版本:
// 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);
}
});
}
}
});
}
您也可以签出cwac-thumbnail以获得嵌入式解决方案(尽管它比上面的简单解决方案有更多的开销)。 我几乎可以在任何可以下载Web图像的地方使用它,并且都取得了巨大的成功。 您基本上为应用程序设置了一些全局缓存选项,然后将ListAdapter包裹在ThumbnailAdapter中,并在列表中包含android:imageviews的ID列表,然后在适配器的getView方法中对imageviews调用setTag(imageUrl),然后它处理其余的。
是。 您应该尽可能避免在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()机制。
在您的示例中,将发生的情况是该项目将在图像可供显示之前显示在屏幕上。 我建议使用“加载”微调器或其他占位符向用户指示发生了什么。
实际上,您可以多次这样嵌套,尽管您将达到简化设计的目的。 匿名类在内存方面可能是低效的,并且在没有取消机制的情况下触发许多线程可能有其自身的缺点。
由于getView()退出后修改视图的副作用,您可能会遇到一些困难。 某些视图可能需要调用invalidate()才能使更改生效。 还要注意,如果要在getView()中回收视图,则应确保在执行更改视图的代码时,该视图仍用于所应用的内容。 setTag()/ getTag()在这里有用,用于存储数据的某些ID,您以后可以检查以确保View未被回收。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.