Проблемы, когда я использую convertView, проблемы, когда я не - PullRequest
1 голос
/ 18 ноября 2011

У меня есть ListView, который содержит ImageView и TextView. Я делю ArrayAdapter на подклассы, чтобы я мог загрузить изображение из Интернета с помощью подкласса AsyncTask. Пока все хорошо.

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

Однако, если я не использую convertView, изображение теряется при прокрутке пользователя. Поэтому, если они прокручивают вниз и назад, изображение перезагружается из Интернета (что явно плохо для использования данных, времени работы от батареи и т. Д.)

Есть ли простой способ исправить это, чтобы он не загружался из Интернета каждый раз или перемещать изображения?

Вот что я сейчас использую:

public class SupplierAdapter extends ArrayAdapter<Supplier>{
    int resource;
    String response;
    Context context;

    public SupplierAdapter(Context context, int resource, List<Supplier> suppliers) {
        super(context, resource, suppliers);
        this.resource = resource;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent){
    LinearLayout view;
        Supplier s = getItem(position);

        if(convertView == null){
            view = new LinearLayout(getContext());
            String inflater = Context.LAYOUT_INFLATER_SERVICE;
            LayoutInflater vi;
            vi = (LayoutInflater) getContext().getSystemService(inflater);
            vi.inflate(resource, view, true);
        } else {
            view = (LinearLayout) convertView;
        }

        ImageView iv = (ImageView) view.findViewById(R.id.thumbnail);
        // s.getThumbnail returns a URL
        new DownloadImageTask(iv).execute(s.getThumbnail()); 

        TextView titleText =(TextView) view.findViewById(R.id.titleText);
        titleText.setText(s.getTitle());
        titleText.setTag(s.getId());

        return view;
    }
}

Вся помощь очень ценится:)

Ответы [ 4 ]

2 голосов
/ 18 ноября 2011

Джон, попробуйте использовать raptureinvenice.com WebImageView . Недавно я провел рефакторинг своего кода, чтобы использовать эту простую и легкую библиотеку, и пока все хорошо. Он легко обеспечивает двухуровневый кеш, обновляет несколько целей одновременно, и его было невероятно легко настроить. Похоже, что он отбрасывает около 1/20 запросов на отображение изображения. Кроме этой скрытой ошибки, которая могла быть ошибкой библиотеки, это превосходно.

1 голос
/ 18 ноября 2011

Для кэширования изображений в оперативной памяти вы можете использовать SoftReference.Таким образом, код будет выглядеть примерно так:

ImageView iv = (ImageView) view.findViewById(R.id.thumbnail);
// s.getDrawable returns a SoftReference to Drawable
SoftReference<Drawable> thumbRef = s.getDrawable();
Drawable thumb = thumbRef.get();
if (thumb == null) {
    new DownloadImageTask(s).execute(); 
} else {
    iv.setDrawable(thumb);
}

DownloadImageTask получит изображение, обернется в SoftReference, установит ссылку на коллекцию и сообщит адаптеру, что нижележащие данные изменились.Конечно, дизайн мог бы быть более эффективным, однако это всего лишь приблизительный план.

1 голос
/ 18 ноября 2011

Если вам нужно загрузить всего несколько изображений и если вам не нужно отображать большое изображение, вы можете использовать следующий код. Он хранит растровые изображения в памяти. Хорошо работает, если изображения не слишком большие.

Я изменил свой код в вашей ситуации:

import android.graphics.Bitmap;

Поставщик публичного класса {

// Data
private String  mText;
private Bitmap  mImage;
private String  mImageUrl;

// Flags
private boolean mIsLoading;

public Supplier() {
    mText       = "test";
    mImage      = null;
    mImageUrl   = "image_url";
    mIsLoading  = false;
}

public Supplier setLoadingStatus(boolean pIsLoading){
    mIsLoading = pIsLoading;
    return this;
}

public boolean isLoading(){
    return mIsLoading;
}

public Supplier setImageUrl(String pImageUrl){
    mImageUrl = pImageUrl;
    return this;
}

public String getImageUrl(){
    return mImageUrl;
}

public Supplier setText(String pText){
    mText = pText;
    return this;
}

public String getText(){
    return mText;
}

public Supplier setImageBitmap(Bitmap bmp){
    mImage = bmp;
    return this;
}

public Bitmap getImageBitmap(){
    return mImage;
}       

}

import java.io.IOException; import java.io.InputStream; импорт java.net.HttpURLConnection; import java.net.MalformedURLException; импорт java.net.URL; import java.util.ArrayList;

импорт android.R; импорт android.content.Context; импорт android.graphics.Bitmap; импорт android.graphics.BitmapFactory; импорт android.os.Handler; импорт android.os.Message; import android.view.LayoutInflater; импорт android.view.View; импорт android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.TextView;

открытый класс TestAdapter расширяет BaseAdapter {

protected static final int MSG_IMAGE_DOWNLOADED = 0;

// Constants
private final String TAG = "TestAdapter";

private ArrayList<Supplier> mItems;
private Context mContext;
private LayoutInflater mLf;
private Handler mHandler;


public TestAdapter(Context pContex) {
    mContext    = pContex;
    mLf         = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    mItems      = new ArrayList<Supplier>();
    mHandler    = new Handler(){
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case MSG_IMAGE_DOWNLOADED:
                if(null != msg.obj){
                    mItems.get(msg.arg1).setImageBitmap((Bitmap)msg.obj)
                                        .setLoadingStatus(false);
                    notifyDataSetChanged();
                }
                break;

            default:
                break;
            }
        };
    };
}

public TestAdapter addItem(Supplier pItem){
    mItems.add(pItem);
    return this;
}

@Override
public int getCount() {
    return mItems.size();
}

@Override
public Supplier getItem(int position) {
    return mItems.get(position);
}

@Override
public long getItemId(int position) {
    return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder vh;

    if(null == convertView){
        convertView     = mLf.inflate(R.layout.your_resource, parent, false);
        vh              = new ViewHolder();
        vh.mTextView    = (TextView)convertView.findViewById(R.id.your_textview_from_resource);
        vh.mImage       = (ImageView)convertView.findViewById(R.id.yout_imageview_from_resource);
        convertView.setTag(vh);
    }else{
        vh = (ViewHolder)convertView.getTag();
    }       

    vh.mTextView.setText(mItems.get(position).getText());
    if(mItems.get(position).getImageBitmap() == null && !mItems.get(position).isLoading()){
        // download image
        downloadImage(mItems.get(position).getImageUrl(), position);
        // set a flag to know that the image is downloading and it is not need to 
        // start another download if the getView method is called again.
        mItems.get(position).setLoadingStatus(true);
    }else{
        vh.mImage.setImageBitmap(mItems.get(position).getImageBitmap());
    }
    return null;
}

private void downloadImage(String pImageUrl, int pItemPosition){
    final int cItemPosition = pItemPosition;
    final String cImageUrl  = pImageUrl; 

    Thread tGetImage = new Thread(new Runnable() {          
        @Override
        public void run() {             
            Message msg = new Message();
            msg.what = MSG_IMAGE_DOWNLOADED;

            BitmapFactory.Options options = new BitmapFactory.Options();                                                                                            
            Bitmap  bmImg;      
            URL     myFileUrl = null; 

            try {
                myFileUrl= new URL(cImageUrl);
            } catch (MalformedURLException e) {
                e.printStackTrace();                        
            }                       
            try {
                HttpURLConnection conn= (HttpURLConnection)myFileUrl.openConnection();
                conn.setDoInput(true);
                conn.connect();
                InputStream is  = conn.getInputStream();
                bmImg           = BitmapFactory.decodeStream(is, null, options);

                is.close();
                conn.disconnect();          
                msg.obj     = bmImg;                    
            } catch (IOException e) {
                e.printStackTrace();                        
            }                       
            msg.arg1 = cItemPosition;
            mHandler.sendMessage(msg);              
        }
    });
    tGetImage.start();
}

private class ViewHolder{
    public TextView     mTextView;
    public ImageView    mImage;
}

}

Код не проверен, но должен работать.

1 голос
/ 18 ноября 2011

Это очень сложная проблема. Я дошел до того, что имел два слоя кеша (память и дисковый кеш), чтобы сгладить производительность поверх более интеллектуального обновления во втором потоке (AsyncTask в вашем случае). Есть много мелких деталей, например, попытка не загружать одно и то же изображение дважды (это проблема, если у вас есть один и тот же логотип компании для нескольких элементов списка). Однако основная проблема, связанная с отображением неправильного изображения, может быть устранена путем простого отслеживания текущего URL-адреса, связанного с ImageView, и обеспечения того, что он совпадает с URL-адресом, переданным в AsyncTask, до установки окончательного изображения. Вы можете хранить эту информацию в HashMap, возможно На самом деле я просто абстрагировал все эти вещи в класс WebImageView, который расширяет ImageView, чтобы сделать все это повторно используемым.

...