我正在尝试制作专辑ListView。在那里我使用AsyncTask将album_art图像加载到列表缩略图。一切都很好,但问题是那些图像没有附加正确的行。如果我滚动列表视图,相册图像会随机变化。有时同一图像显示在多行中,有时根本没有图像。我不知道为什么会这样。它看起来像一种线程问题。我该如何解决?
这是我的代码:
public class PropertyOfAlbum extends BaseAdapter {
public static ViewHolder holder;
private Context mContext;
Cursor cursor;
private FakeImageLoader mFakeImageLoader;
private LayoutInflater layoutInflater;
Typeface tf, tf2, tf3;
Bitmap coverBitmap;
//private FakeImageLoader mFakeImageLoader;
public PropertyOfAlbum(Context context, Cursor cur) {
super();
mContext = context;
cursor = cur;
tf = Typeface.createFromAsset(context.getAssets(),
"fonts/gang_wolfik_blade.ttf");
tf2 = Typeface.createFromAsset(context.getAssets(),
"fonts/gang_wolfik_blade.ttf");
tf3 = Typeface.createFromAsset(context.getAssets(),
"fonts/gang_wolfik_blade.ttf");
layoutInflater = LayoutInflater.from(context);
}
@TargetApi(Build.VERSION_CODES.GINGERBREAD)
@SuppressLint("NewApi")
public View getView(final int position, View view, ViewGroup parent) {
cursor.moveToPosition(position);
// Using an AsyncTask to load the slow images in a background thread
if (view == null) {
view = layoutInflater.inflate(R.layout.album_row, null);
holder = new ViewHolder();
holder.title = (TextView) view.findViewById(R.id.title);
holder.duration = (TextView) view.findViewById(R.id.duration);
holder.artist = (TextView) view.findViewById(R.id.artist);
holder.iv = (ImageView) view.findViewById(R.id.list_image);
holder.col = cursor.getColumnIndexOrThrow(MediaStore.Audio.Albums.ALBUM_ART);
view.setTag(holder);
}else{
holder = (ViewHolder) view.getTag();
}
//mFakeImageLoader = new FakeImageLoader(cursor,holder.col);
holder.title.setTypeface(tf);
holder.artist.setTypeface(tf2);
holder.duration.setTypeface(tf3);
holder.title.setTextSize(18);
Log.d(null, "col " + holder.col);
holder.title.setText(cursor.getString(1));
holder.artist.setText(cursor.getString(2));
holder.duration.setText(cursor.getString(4));
//coverBitmap = BitmapFactory.decodeFile(cursor.getString(holder.col));
if(coverBitmap == null){
holder.iv.setImageDrawable(mContext.getResources().getDrawable(R.drawable.album));
}else{
holder.iv.setImageBitmap(coverBitmap);
}
holder.position = position;
new AsyncTask<ViewHolder, Void, Bitmap>() {
private ViewHolder v;
@Override
protected Bitmap doInBackground(ViewHolder... params) {
v = params[0];
coverBitmap = BitmapFactory.decodeFile(cursor.getString(holder.col));
return coverBitmap;
}
@Override
protected void onPostExecute(Bitmap result) {
super.onPostExecute(result);
if(v.position == position){
if (coverBitmap==null) {
holder.iv.setImageDrawable(mContext.getResources().getDrawable(R.drawable.album));
}else{
holder.iv.setImageBitmap(coverBitmap);
}
}
}
}.execute(holder);
return view;
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return cursor.getCount();
}
@Override
public Object getItem(int arg0) {
// TODO Auto-generated method stub
return arg0;
}
@Override
public long getItemId(int arg0) {
// TODO Auto-generated method stub
return arg0;
}
public static class ViewHolder {
TextView title;
TextView duration;
TextView artist;
ImageView iv;
int col,position;
}
}
答案 0 :(得分:1)
将AsyncTask实例与适配器上的View行链接起来并不是一个好习惯,通常,在必要时将它放在另一个流中的getView()之外,因为getView上的视图( )在AsyncTask加载完成时,您将无法控制该视图上显示的内容。
我能给你的最好建议是忘记这种方法并将毕加索应用于你的项目。 Picasso是Android上最简单但功能最强大的图片加载库,我保证你不会后悔:http://square.github.io/picasso/
答案 1 :(得分:0)
您只有1个对coverBitmap的引用。每次调用getView()时(例如每次滚动),它都会重用一些视图(即convertView!= null),你将新的背景设置为当前的任何coverBitmap,并且然后启动一个新的AsyncTask,然后再次替换coverBitmap。因此,循环继续,您遇到了问题。
现在,一个解决方案是让某种对象将位图映射到您引用的特定相册。
EG。
private Map<String, Bitmap> albumImages = new HashMap<String, Bitmap>();
既然你有东西可以存放你的东西,你可以删除你的&#34; coverBitmap&#34;并将您的位图添加到AsyncTask中的albumImages:
@Override
protected Bitmap doInBackground(ViewHolder... params) {
v = params[0];
return BitmapFactory.decodeFile(cursor.getString(holder.col));
}
@Override
protected void onPostExecute(Bitmap result) {
super.onPostExecute(result);
// Add the returned Bitmap to our Map if it's not null
if(result != null) alumbImages.put(cursor.getString(holder.col), result);
if(v.position == position){
if (result == null) {
holder.iv.setImageDrawable(mContext.getResources().getDrawable(R.drawable.album));
}else{
holder.iv.setImageBitmap(result);
}
}
}
现在让我们回到你的getView()方法并替换你获取和设置图像的方式,并确保每次调用该方法时都不会触发AsyncTask:
Bitmap albumImage = albumImages.get(cursor.getString(holder.col));
if(albumImage == null){
holder.iv.setImageDrawable(mContext.getResources().getDrawable(R.drawable.album));
// Now is where you can call the AsyncTask, so that it's only called if we don't already have the image:
new AsyncTask<ViewHolder, Void, Bitmap>() { ... }
}
else holder.iv.setImageBitmap(albumImage);
holder.position = position;
然而,这仍然远非最佳,我建议使用延迟加载库,以便更好地处理保留大量图像所需的所有资源。这个用户非常友好:https://github.com/nostra13/Android-Universal-Image-Loader