当我使用convertView时出现问题,当我没有问题时

问题描述:

我有一个ListView,它包含一个ImageView和一个TextView。我是继承ArrayAdapter,以便我可以通过一个子类AsyncTask从互联网加载图像。迄今为止都很好。当我使用convertView时出现问题,当我没有问题时

的问题是,如果我尝试使用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; 
    } 
} 

所有帮助非常感谢:)

+0

你有没有考虑过使用SimpleAdapter和缓存? –

+0

@丹,我没有。如何缓存?保存到SD卡?我不确定那将如何工作。 –

+0

如果您要处理的不是字符串数组,而是SimpleAdapter更好。对于缓存,您可以将其保存到SD中,并有一些标准来检查更新。 –

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

+0

不错,这与我所拥有的非常相似,但我无法分享我的代码,因为我为我的雇主写了代码。有趣的是,我认为我在我的实现中似乎也有类似的错误。我相信这与内存使用有关。我唯一的问题是,它使用SoftReferences,它在Android上有些破碎。我使用LruCache,我宁愿反正给我一个一致的最大缓存大小。 – kabuko

+0

谢谢,这很理想! –

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

对于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,设置基准以收集并通知适配器垫层数据已经改变。设计可以更高效,但这只是一个粗略的计划。

+0

这看起来相当有希望 - 我会给它一个镜头,让你知道我如何继续。谢谢:) –

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

我改变了我的代码,您的情况:

进口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; 
}  

}

进口产生java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList;

import 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; 
} 

}

的代码没有进行测试,但应该工作。