1

在我的应用程序中,有一个ListView使用自定义CursorAdapter将数据加载到其中的应用程序,它基本上是一个ImageView和一个TextView。我正在加载图像AsyncTask,现在的问题是,最初所有图像都分配给正确的文本,但是当我快速上下滚动时,它会为每个文本绑定随机图像。由于我使用的是 CursorAdapter ,所以我不能ViewHolder在这里使用,那么我该怎么做才能消除这个问题呢?

这是我的示例代码:

public class MyAdapter extends CursorAdapter {

    private LayoutInflater mLayoutInflater;
    @SuppressWarnings("unused")
    private Context mContext;

    public MyAdapter(Context context, Cursor c, int flags) {
        super(context, c, flags);
        mContext = context;
        mLayoutInflater = LayoutInflater.from(context);
    }
    public void bindView(View view, Context context, Cursor cursor) {
        String title = cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns.TITLE));
        String album_id = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID));
        TextView text = (TextView)view.findViewById(R.id.txtTitle);
        text.setText(title);
        Uri sArtworkUri = Uri.parse("content://media/external/audio/albumart");
        Uri uri = ContentUris.withAppendedId(sArtworkUri, Integer.valueOf(album_id));
        new MyImageLoader(context,view).execute(uri);

    }
    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) {
        return mLayoutInflater.inflate(R.layout.row, parent, false);
    }
    private class MyImageLoader extends AsyncTask<Uri, Void, Bitmap>{
        Context context;
        View view;


        MyImageLoader(Context context,View view){
            this.context = context;
            this.view = view;
        }
        @Override
        protected Bitmap doInBackground(Uri... uri) {
            ContentResolver res = context.getContentResolver();
            InputStream in = null;
            try {
                in = res.openInputStream(uri[0]);
            } 
            catch (FileNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            Bitmap artwork = BitmapFactory.decodeStream(in);
            return artwork;
        }
        protected void onPostExecute(Bitmap bmp){
            ImageView iv = (ImageView)view.findViewById(R.id.imgIcon);
            if(bmp!=null)
                //iv.setImageBitmap(bmp);
                iv.setImageBitmap(Bitmap.createScaledBitmap(bmp, 100, 100, false));
        }
    }
}

更新: 我应用了 setTag 方法,现在洗牌变少了,但是当我快速滚动时,旧图像会持续一秒钟,直到加载正确的图像。这是新代码:

public void bindView(View view, Context context, Cursor cursor) {
        String title = cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns.TITLE));
        String album_id = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID));
        ImageView iv = (ImageView)view.findViewById(R.id.imgIcon);
        TextView text = (TextView)view.findViewById(R.id.txtTitle);
        text.setText(title);
        Uri sArtworkUri = Uri.parse("content://media/external/audio/albumart");
        Uri uri = ContentUris.withAppendedId(sArtworkUri, Integer.valueOf(album_id));
// *****TAG SET*****
        iv.setTag(uri);
//***PASSING BOTH URI AND IMAGEVIEW TO CONSTRUCTOR***
        new MyImageLoader(context,view,iv,uri).execute(uri);

    }
    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) {
        View v = mLayoutInflater.inflate(R.layout.row, parent, false);
        //v.setTag(R.id.imgIcon, v.findViewById(R.id.imgIcon));
        return v;
    }
    private class MyImageLoader extends AsyncTask<Object, Void, Bitmap>{
        Context context;
        View v;
        ImageView iv;
        Uri u;

        MyImageLoader(Context context,View v,ImageView iv,Uri u){
            this.context = context;
            this.v = v;
            this.iv = iv;   
            this.u = u;
        }
        @Override

        protected synchronized Bitmap doInBackground(Object... param) {
            ContentResolver res = context.getContentResolver();
            InputStream in = null;
            try {
                Uri uri= (Uri)param[0];
                in = res.openInputStream(uri);
            } 
            catch (FileNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            Bitmap artwork = BitmapFactory.decodeStream(in);

            return artwork;
        }
        protected void onPostExecute(Bitmap bmp){

            if(bmp!=null)
            {   ImageView iv = (ImageView)v.findViewById(R.id.imgIcon);
                if(iv.getTag().toString().equals(u.toString()))
                    iv.setImageBitmap(Bitmap.createScaledBitmap(bmp, 100, 100, false));
            }
        }
    }

更新:在调用后台任务之前设置占位符图像会更好。

4

1 回答 1

2

我使用的一种解决方案是将 附加UriImageViewvia setTag()。然后,当您去更新 时ImageView,检查Uri您要应用的图像的 是否与 中的值匹配getTag()。如果是这样,请继续更新ImageView. 如果没有,ImageView则被回收,您可以跳过更新。

另一种方法是setHasTransientState(true)您确定ImageView缓存未命中并需要启动AsyncTask. 这将导致AdapterView避免回收该行,直到进行了匹配的setHasTransientState(false)调用。Chet Haase 有一个关于此的 DevBytes 视频,在将动画应用于ListView一行并试图避免回收问题的背景下。但是,setHasTransientState()它是 API 级别 16 的新功能,因此如果您尝试支持 Android 4.0 或更早的设备,这将不是一个可用的选项。

于 2013-02-24T14:08:52.380 回答