В моем приложении есть 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));
}
}
}
UPDATE: Установки шаблонного изображения перед вызовом фоновой задачи делает это намного лучше.
Я попробую 1-й метод и вернусь. Не могу попробовать второй, когда я нацеливаю API 15. – h4ck3d
Я не могу понять, где добавить тег, должен ли я создать объект ImageView в 'bindView()' и перед вызовом 'MyImageLoader' установить там свой тег и передать его как аргумент конструктору или выполнить метод? – h4ck3d
@Droider: «Я должен создать объект ImageView в bindView()» - у вас уже есть «ImageView». Вызовите 'findViewById()' для его получения. – CommonsWare