我正在尝试创建一个自定义listview adaptar,它可以异步更新每个视图中的imageView,这样它就不会变慢。
到目前为止,我正在使用一个存储imageview位图的向量,在适配器构造函数中我正在调用获取所有位图的线程。 在getView()方法中,我检查vector [position]是否为null,以实际更改imageView位图。
这是代码:
public class SongAdapter extends ArrayAdapter<Song> {
private int resource;
private LayoutInflater inflater;
private ArrayList<Song> items;
private Context cntx;
private final Utilities util = new Utilities(); //una per tutte le canzoni
private Bitmap[] covers; //la utilizzo per fare un cashing delle cover
public SongAdapter(Context cntx, int resId, ArrayList<Song> objects)
{
super(cntx, resId, objects);
this.cntx = cntx;
items = objects;
resource = resId;
inflater = LayoutInflater.from(cntx);
covers = new Bitmap[objects.size()];
asyncLoadImagesCover(); //lacio un thread per caricare le immagini
}
//carico le immagini nella listview in background
public void asyncLoadImagesCover()
{
new Thread(new Runnable() {
@Override
public void run() {
for(int i = 0; i < items.size(); i++)
covers[i] = util.getAlbumArtFromSong(items.get(i).getPath(), cntx);
//notifyDataSetChanged();
}
}).start();
}
//cerco di mantenere in memoria l'oggetto in modo da evitare il ricaricamento
private static class ViewHolder
{
TextView titolo;
TextView artista;
ImageView cover;
}
//////////////////////////////////////////////////////////////////////////////////////
//Funzione che riscrive gli elementi della listview
@Override
public View getView(int position, View v, ViewGroup parent)
{
//recupero l'oggetto canzone
Song song = getItem(position);
ViewHolder holder;
if(v == null)
{
//creo la view partendo dal layout
v = inflater.inflate(resource, parent, false);
holder = new ViewHolder();
holder.titolo = (TextView)v.findViewById(R.id.songTitle);
holder.artista = (TextView)v.findViewById(R.id.artistText);
holder.cover = (ImageView)v.findViewById(R.id.albumImage);
v.setTag(holder);
}
else
holder = (ViewHolder) v.getTag();
//setto i valori a partire dall'holder, in questo modo non devo fare findviewbyid ogni volta
holder.titolo.setText(song.getTitle());
holder.artista.setText(song.getArtist());
if(covers[position] != null)
holder.cover.setImageBitmap(covers[position]);
return v;
}
}
无论如何这不能很好地工作,50%的时间活动崩溃,我想这是因为新线程。 我在网上搜索并找到了不同的解决方案,但我想先了解为什么我的代码会破碎。另外,如何创建一个更新我的listview gui的线程,在getView中传递v和位置?
////////////////////////////////////////////// 编辑:
对于任何有兴趣的人,这就是我所做的: 我创建了一个带有两个独立对象的类,它使用一个处理程序来更新UI,一个ExecutorService用于堆叠通过我的函数获取图像的线程:
public class CoverLoader {
Utilities util = new Utilities();
Context cntx;
ExecutorService executorService;
Handler handler = new Handler(); //si occupa di aggiornare la UI
public CoverLoader(Context cntx)
{
this.cntx = cntx;
executorService = Executors.newFixedThreadPool(5);
}
public void DisplayImage(ImageView iv, String path)
{
executorService.submit(new ImageLoader(iv,path));
}
//Separo la parte del caricamento dalla parte di aggiornamento della gui
//questa classe si occupa solo di recuperare la bmp
public class ImageLoader implements Runnable
{
ImageView iv;
String path;
public ImageLoader(ImageView iv, String path)
{
this.iv = iv;
this.path = path;
}
@Override
public void run()
{
Bitmap bmp = util.getAlbumArtFromSong(path, iv.getContext());
handler.post(new BitmapDisplayer(iv,bmp));
}
}
//Si occupa di aggiornare la UI, richiamata dall'handler a termine del processo di caricamento
class BitmapDisplayer implements Runnable
{
Bitmap bitmap;
ImageView iv;
public BitmapDisplayer(ImageView iv, Bitmap bitmap)
{
this.iv = iv;
this.bitmap = bitmap;
}
@Override
public void run()
{
iv.setImageBitmap(bitmap);
}
}
}
现在在getView()上:
@Override
public View getView(int position, View v, ViewGroup parent)
{
Song song = getItem(position);
ViewHolder holder;
if(v == null)
{
//creo la view partendo dal layout
v = inflater.inflate(resource, parent, false);
holder = new ViewHolder();
holder.titolo = (TextView)v.findViewById(R.id.songTitle);
holder.artista = (TextView)v.findViewById(R.id.artistText);
holder.cover = (ImageView)v.findViewById(R.id.albumImage);
v.setTag(holder);
}
else
holder = (ViewHolder) v.getTag();
//setto i valori a partire dall'holder, in questo modo non devo fare findviewbyid ogni volta
holder.titolo.setText(song.getTitle());
holder.artista.setText(song.getArtist());
coverLoader.DisplayImage(holder.cover, song.getPath()); //Richiamo uno stack di thread
//if(covers[position] != null)
//holder.cover.setImageBitmap(covers[position]);
return v;
}
到目前为止一切顺利,现在我只想找到一种方法(数组可能?)来保存我已经拥有的图像
答案 0 :(得分:0)
你不应该在绑定到Activity上下文的对象中执行Threads,因为它是一个简短的生物(内存泄漏)。
您也不应该下载所有图像以及getView代码(性能)中请求的图像。
您还应该尝试避免多个线程访问的变量(同步)。