【问题标题】:Problems when I use convertView, problems when I don't使用 convertView 时出现问题,不使用时出现问题
【发布时间】:2011-11-18 07:11:41
【问题描述】:

我有一个 ListView,其中包含一个 ImageView 和一个 TextView。我正在对 ArrayAdapter 进行子类化,以便我可以通过子类化的 AsyncTask 从 Internet 加载图像。到目前为止一切顺利。

问题是,如果我尝试使用 convertView,我会遇到图像被短暂回收到错误行的问题。 (这是一家公司的标志,所以这……不好。)

但是,如果我不使用 convertView,图像会在用户滚动时丢失。因此,如果他们向下滚动并向后滚动,图像会从互联网重新加载(这显然不利于数据使用、电池寿命等)

是否有一种简单的方法可以解决此问题,使其不会每次都从 Internet 加载或移动图像?

这是我目前使用的:

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

非常感谢所有帮助:)

【问题讨论】:

  • 你考虑过使用 SimpleAdapter 和缓存吗?
  • @Dan,我没有。究竟如何缓存?保存到 SD 卡?我不确定这会如何工作。
  • SimpleAdapter 如果您要做的不仅仅是处理字符串数组,那么它会更好。对于缓存,您可以将其保存到 SD 中,并设置一些检查更新的标准。

标签: android listview networking convertview


【解决方案1】:

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

【讨论】:

  • 很好,这与我所拥有的非常相似,但我无法分享我为雇主编写的代码。有趣的是,我认为我的实现中似乎也有类似的错误。我相信这与内存使用有关。我唯一的疑虑是它使用了在 Android 上有些损坏的 SoftReferences。我使用 LruCache 代替,无论如何我更喜欢给我一个一致的最大缓存大小。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

    对于 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,设置对集合的引用并通知适配器底层数据已更改。当然,设计可能会更有效率,但这只是一个粗略的计划。

    【讨论】:

    • 这看起来很有希望 - 我会试一试,让你知道我的进展如何。谢谢你:)
    【解决方案4】:

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

    我根据您的情况更改了代码:

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

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

    }

    代码未经测试,但应该可以工作。

    【讨论】:

      猜你喜欢
      • 2011-06-14
      • 2019-08-11
      • 2021-10-30
      • 1970-01-01
      • 1970-01-01
      • 2015-11-13
      • 2019-03-30
      • 2013-04-14
      • 2012-07-31
      相关资源
      最近更新 更多