1

私のアプリにはListView、カスタムを使用してCursorAdapterデータをロードする があり、基本的にImageViewTextViewです。AsyncTask問題は、最初はすべての画像が正しいテキストに割り当てられていますが、すばやく上下にスクロールすると、テキストごとにランダムな画像がバインドされます。CursorAdapter を使用ViewHolderしているため、 here を使用できないため、この問題を解決するにはどうすればよいですか?

ここに私のサンプルコードがあります:

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 メソッドを適用したところ、シャッフルが少なくなりましたが、速くスクロールすると、正しい画像が読み込まれるまで古い画像が 1 秒間表示されたままになります。新しいコードは次のとおりです。

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

私が使用した 1 つの解決策は、 を via に接続するUriことImageViewですsetTag()。次に、 を更新するときに、適用しようとしているイメージの が の値と一致するImageViewかどうかを確認します。その場合は、先に進んで を更新してください。そうでない場合は、リサイクルされているので、更新をスキップできます。UrigetTag()ImageViewImageView

もう 1 つのアプローチはsetHasTransientState(true)キャImageView​​ッシュ ミスがあり、AsyncTask. これによりAdapterView、一致するsetHasTransientState(false)呼び出しが行われるまで、その行のリサイクルが回避されます。Chet Haase は、アニメーションを行に適用し、リサイクルの問題を回避しようとするコンテキストで、これに関する DevBytes ビデオを公開しています。ListViewただし、setHasTransientState()API レベル 16 では新しいため、Android 4.0 以前のデバイスをサポートしようとしている場合、これは利用可能なオプションではありません。

于 2013-02-24T14:08:52.380 に答える