我使用convertView时的问题,当我不使用时出现问题

时间:2011-11-17 22:22:41

标签: android listview networking convertview

我有一个包含ImageView和TextView的ListView。我正在继承ArrayAdapter,以便我可以通过子类AsyncTask从Internet加载图像。到目前为止一切都很好。

问题是,如果我尝试使用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 个答案:

答案 0 :(得分:2)

John,尝试使用raptureinvenice.comWebImageView。我最近重构了我的代码,使用这个简单轻量级的库,到目前为止,非常好。它可以轻松提供两级缓存,同时更新多个目标,并且设置非常简单。看起来似乎放弃了大约1/20的显示图像的请求。除了可能是图书馆错误的这个潜伏的错误,它是非常好的。

答案 1 :(得分:1)

这是一个令人烦恼的复杂问题。我有两层缓存(内存和磁盘缓存),以便在第二个线程(在您的情况下为AsyncTask)中更智能的更新之上平滑性能。有很多小细节,比如尝试不下载两次相同的图像(如果你有多个列表项的相同公司徽标,这是一个问题)。显示错误图像的主要问题可以通过跟踪与ImageView关联的当前URL来确定,并确保与设置最终图像之前传入AsyncTask的URL相同。您可以将该信息存储在HashMap中。我实际上只是将所有这些内容抽象到一个WebImageView类中,该类扩展了ImageView以使其全部可重用。

答案 2 :(得分:1)

对于RAM图像缓存,您可以使用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,设置对集合的引用并通知适配器底层数据已更改。对于cource来说,设计可能更有效,但这只是一个粗略的计划。

答案 3 :(得分:1)

如果您只需下载一些图像,并且不需要显示大图像,则可以使用以下代码。它将位图存储在内存中。效果很好的是图像不是太大。

我将代码更改为您的情况:

导入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; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList;

导入android.R; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Handler; import android.os.Message; import android.view.LayoutInflater; import android.view.View; import 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;
}

}

代码未经过测试但应该有效。