Intereting Posts

ANDROID: загрузка асинхронных изображений в listView

Я хотел бы отображать ListView с адаптированным адаптером (с изображением и текстом).

Изображения загружаются с удаленных серверов, поэтому я решил использовать AsyncTask.

На самом деле, изображения хорошо отображаются, но если я быстро прокручиваюсь, отображается неправильное изображение в течение 1/2 секунд (после загрузки появляется правильное изображение)

Вот код моего адаптера:

public class GiAdapter extends BaseAdapter { private Context mContext; private List<SiteStaff> mListAppInfo; private HashMap<Integer, ImageView> views; private HashMap<String,Bitmap> oldPicts = new HashMap<String,Bitmap>(); private LayoutInflater mInflater; private boolean auto; private final String BUNDLE_URL = "url"; private final String BUNDLE_BM = "bm"; private final String BUNDLE_POS = "pos"; private final String BUNDLE_ID = "id"; public GiAdapter(Context context, List<SiteStaff> list) { mContext = context; mListAppInfo = list; views = new HashMap<Integer, ImageView>(); mInflater = LayoutInflater.from(mContext); } @Override public int getCount() { return mListAppInfo.size(); } @Override public Object getItem(int position) { return mListAppInfo.get(position).getId(); } @Override public long getItemId(int position) { return mListAppInfo.get(position).getId(); } @Override public View getView(int position, View convertView, ViewGroup parent) { LinearLayout layoutItem; // reuse of convertView if (convertView == null) { layoutItem = (LinearLayout) mInflater.inflate(R.layout.auto_gi, parent, false); } else { layoutItem = (LinearLayout) convertView; } // infos for the current element SiteStaff entry = mListAppInfo.get(position); //set some text fields TextView name = (TextView) layoutItem.findViewById(R.id.name); TextView size = (TextView) layoutItem.findViewById(R.id.size); name.setText(entry.getName()); size.setText(entry.getSize()); // get the imageView for the current object ImageView v = (ImageView) layoutItem.findViewById(R.id.gi_image); // put infos in bundle and send to the LoadImage class Bundle b = new Bundle(); //url of the pict b.putString(BUNDLE_URL, entry.getUrl()); //position in the listView b.putInt(BUNDLE_POS, position); //id of the current object b.putInt(BUNDLE_ID, entry.getId()); //put info in the map in order to display in the onPostExecute views.put(position, v); // thread new LoadImage().execute(b); return layoutItem; } //asyncTackClass for loadingpictures private class LoadImage extends AsyncTask<Bundle, Void, Bundle> { @Override protected Bundle doInBackground(Bundle... b) { Bitmap bm =null; //cache: for better performance, check if url alredy exists if(oldPicts.get(b[0].getString(BUNDLE_URL))==null){ bm = Utils.getBitMapFromUrl(b[0].getString(BUNDLE_URL)); oldPicts.put(b[0].getString(BUNDLE_URL),bm); }else{ bm = oldPicts.get(b[0].getString(BUNDLE_URL)); } // get info from bundle Bundle bundle = new Bundle(); bundle.putParcelable(BUNDLE_BM, bm); bundle.putInt(BUNDLE_POS, b[0].getInt(BUNDLE_POS)); return bundle; } @Override protected void onPostExecute(Bundle result) { super.onPostExecute(result); //get picture saved in the map + set ImageView view = views.get(result.getInt(BUNDLE_POS)); Bitmap bm = (Bitmap) result.getParcelable(BUNDLE_BM); if (bm != null){ //if bitmap exists... view.setImageBitmap(bm); }else{ //if not picture, display the default ressource view.setImageResource(R.drawable.unknow); } } } } 

Спасибо !

Это случилось и со мной. Я понял, что до того, как новое изображение привязалось к представлению изображения, старый был показан некоторое время. В вашем случае происходит то, что ваша правильная информация показывает onPostExecute (), которая занимает некоторое время, и до того, как будут отображаться все данные, установленные в convertview. Есть два способа, которые вы могли бы устранить,

В вашем getView () измените блок if {} … else {} на просто

 layoutItem = (LinearLayout) mInflater.inflate(R.layout.auto_gi, parent, false); 

или

Задайте образ с каким-то образ-заполнителем в getView () до вызова onPostExecute ().

Надеюсь это поможет.

Как упоминалось в Шубхайю, вы видите неправильные изображения в своих списках ListView, потому что ваш адаптер перерабатывает представление для построения каждой строки, а ваши задачи Async поддерживают ссылки на это переработанное представление. Когда ваши задачи будут завершены, они обновят ImageView, который может фактически соответствовать некоторой другой строке.

Проблема с раздуванием нового представления при каждом вызове getView заключается в том, что при прокрутке вы получите плохую производительность для своего ListView. Вы (правильно) используете convertView для уменьшения этих накладных расходов, вам просто не хватает части правильной привязки ImageView к Async. Я нашел решение здесь: http://android-developers.blogspot.com/2010/07/multithreading-for-performance.html

Таким образом, в основном это расширение Drawable для инкапсуляции задачи и обновление только изображения, если задача правильно привязана к изображению. Раздел «Обработка параллелизма» решает ту проблему, с которой вы столкнулись. В частности, прочтите параграф прямо перед этим разделом для краткого изложения того, что вызывает вашу проблему.

Когда вы расширяете BaseAdapter и реализуете getView (int position, View convertView, родительская группа ViewGroup), convertView фактически является переработанным представлением.

Это вид, который был уничтожен (последний вид выталкивается с экрана). Что вы можете сделать, это очистить convertView, чтобы он не отображал устаревшие данные. Возможно, найти представление с изображением и сделать layoutItem.removeAll (). Надеюсь, это очистит взгляды и даст вам чистый макет для работы.