【问题标题】:Android custom adapter list view images showing randomly while scrollAndroid自定义适配器列表视图图像在滚动时随机显示
【发布时间】:2014-01-11 17:22:38
【问题描述】:

嗨,我是 android 的菜鸟,我正在尝试使用自定义适配器将一些数据加载到 ListView。我正在使用以下代码加载数据。第一次,它运行良好。但是,当我尝试加载更多时,数据加载和图像在滚动时随机显示。在该列表中显示一些随机图像后,最终显示正确的图像。它也在下一个滚动中重复

这是我的getView 代码

 @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View v = convertView;
        final ViewHolder holder;
        if (v == null) {
            LayoutInflater vi =
                (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            v = vi.inflate(R.layout.review_list_m, null);
            v.setMinimumHeight(height);
            holder = new ViewHolder();
            holder.item1 = (TextView) v.findViewById(R.id.name);
            holder.image = (ImageView) v.findViewById(R.id.posterView);
            v.setTag(holder);
        }
        else
            holder=(ViewHolder)v.getTag();

        int colorPos = position % colors.length;
        v.setBackgroundColor(Color.parseColor(colors[colorPos]));


        final Custom custom = entries.get(position);
        if (custom != null) {
            holder.image.setBackgroundColor(Color.parseColor(colors[colorPos]));
            holder.image.setLayoutParams(new LinearLayout.LayoutParams(height-10,width-10));
            String imgUrl=custom.getImage();

            AsyncHttpClient client = new AsyncHttpClient();
              String[] allowedContentTypes = new String[] { "image/png", "image/jpeg" };
              client.get(imgUrl, new BinaryHttpResponseHandler(allowedContentTypes) {
                  @Override
                  public void onSuccess(byte[] fileData) {
                      // Do something with the file
                      ByteArrayInputStream inputStream = new ByteArrayInputStream(fileData);
                      Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
                      holder.image.setImageBitmap(bitmap);
                  }
              });

              holder.item1.setHeight(height/3);
            Log.v("PATH",custom.getcustomBig());
            holder.item1.setText(custom.getcustomBig());

        }
        return v;
    }

有什么想法吗?请帮忙

更新

   @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View v = convertView;
        final ViewHolder holder;
        if (v == null) {
            LayoutInflater vi =
                (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            v = vi.inflate(R.layout.review_list_m, null);
            v.setMinimumHeight(height);
            holder = new ViewHolder();
            holder.item1 = (TextView) v.findViewById(R.id.name);
            holder.image = (ImageView) v.findViewById(R.id.posterView);
            v.setTag(holder);
        }
        else
            holder=(ViewHolder)v.getTag();

        int colorPos = position % colors.length;
        v.setBackgroundColor(Color.parseColor(colors[colorPos]));


        final Custom custom = entries.get(position);
        if (custom != null) {
            holder.image.setBackgroundColor(Color.parseColor(colors[colorPos]));
            holder.image.setLayoutParams(new LinearLayout.LayoutParams(height-10,width-10));
            final String imgUrl=custom.getImage();
            holder.image.setTag(imgUrl);


            holder.image.setImageBitmap(null);
            Bitmap cachedBitmap = cache.get(imgUrl);
            if( cachedBitmap == null) {

                Log.v("HERE","DOWNLOADING");
                AsyncHttpClient client = new AsyncHttpClient();
              String[] allowedContentTypes = new String[] { "image/png", "image/jpeg" };
              client.get(imgUrl, new BinaryHttpResponseHandler(allowedContentTypes) {
                  @Override
                  public void onSuccess(byte[] fileData) {
                      // Do something with the file
                      ByteArrayInputStream inputStream = new ByteArrayInputStream(fileData);
                      Bitmap bitmap = BitmapFactory.decodeStream(inputStream);

                       holder.image.setImageBitmap(bitmap);
                                      }
              });
            }
            else 
            {
                holder.image.setImageBitmap(cachedBitmap);
            }

              holder.item1.setHeight(height/3);
            //Log.v("PATH",custom.getcustomBig());
            holder.item1.setText(custom.getcustomBig());

        }

【问题讨论】:

  • 你的问题在于这一行:if (custom != null) 看到这个链接了解列表视图回收stackoverflow.com/questions/11945563/…
  • 为解决问题删除这两行 final Custom custom = entries.get(position);如果(自定义!= null)

标签: android android-listview android-asynctask custom-adapter


【解决方案1】:

如果 v != null,您可能应该将 null 位图设置为 holder.image。否则,Android 可以显示来自其他单元格的位图,直到通过异步 http 请求下载新图像。

示例代码(用于重新下载图像的问题),它不是睾丸,但应该让您知道它的外观:

HashMap<String, Bitmap> cache = new HashMap<String, Bitmap>();

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

    //....

    final Custom custom = entries.get(position);
    if (custom != null) {
        holder.image.setBackgroundColor(Color.parseColor(colors[colorPos]));
        holder.image.setLayoutParams(new LinearLayout.LayoutParams(height-10,width-10));
        String imgUrl=custom.getImage();

        Bitmap cachedBitmap = cache.get(imgUrl);

        if( cachedBitmap == null) {
            AsyncHttpClient client = new AsyncHttpClient();
            String[] allowedContentTypes = new String[] { "image/png", "image/jpeg" };
            client.get(imgUrl, new BinaryHttpResponseHandler(allowedContentTypes) {
                @Override
                public void onSuccess(byte[] fileData) {
                    // Do something with the file
                    ByteArrayInputStream inputStream = new ByteArrayInputStream(fileData);
                    Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
                    holder.image.setImageBitmap(bitmap);
                    cache.add( imgUrl, bitmap );
                }
            });
        }
        else 
        {
            holder.image.setImageBitmap(cachedBitmap);
        }

        holder.item1.setHeight(height/3);
        Log.v("PATH",custom.getcustomBig());
        holder.item1.setText(custom.getcustomBig());
    }

【讨论】:

  • 添加此行时,holder.image.setImageBitmap(null);图像随机停止加载。但图像在滚动时再次加载。有什么想法吗?
  • 我不明白,您的意思是您暂时看不到之前下载的图像(例如,您再次滚动到第一个单元格并且此单元格中的图像暂时为空)?
  • 是的.. 显示前 3 行,当我向下滚动其余行中的图像时显示为空并在滚动后加载。当我向上滚动时,同样的事情。有什么想法吗?
  • 您可以添加 SparseArray(其中键是自定义 id,或位置和值是位图)或 HashMap(其中键是位图 url,值是位图)存储下载的位图以及何时需要使用它再次。因此,您可以检查图像是否以前下载过,是否应该使用缓存,而不是启动新的异步请求。
  • 嗨@thomasz 你能告诉我/给我一段代码吗?我是新手
【解决方案2】:

编辑答案 在设置位图之前验证您的 imageview 的标签没有更改。 你可以试试:

    /**
 * Caches an image (or a group of them) async.
 * @author 
 *
 */
public static class ImageCacher extends AsyncTask<String, String, Integer>{

    Context context;
    ImageView iv;
    Bitmap b;


    public ImageCacher(Context context, ImageView iv){
        this.context = context;
        this.iv = iv;
    }

    @Override
    protected Integer doInBackground(String... params) {

        for(final String param:params){
            //check if already CACHED
            String filename = String.format("%d", param.hashCode());
            File file = new File(context.getFilesDir(), filename);
            if(file.exists()){
                try {
                    b = BitmapFactory.decodeFile(file.getAbsolutePath());
                } catch (Exception e) {
                }
                if(b != null){
                    if(iv != null){
                        iv.post(new Runnable() {

                            public void run() {
                                String tag = (String) iv.getTag();
                                if(tag != null){
                                    if(tag.matches(param))
                                        iv.setImageBitmap(b);
                                }

                            }
                        });
                    }

                    return 0;
                }else{
                    file.delete();
                }
            }

            //download
            file = new File(context.getFilesDir(), filename);
            b = saveImageFromUrl(context, param);
            if(b != null){
                if(iv != null){
                    iv.post(new Runnable() {

                        public void run() {
                            String tag = (String) iv.getTag();
                            if(tag != null){
                                if(tag.matches(param))
                                    iv.setImageBitmap(b);
                            }

                        }
                    });
                }
            }
        }

        return 0;
    }

}

/**
 * Gets an image given its url
 * @param param
 */
public static Bitmap saveImageFromUrl(Context context, String fullUrl) {
    Bitmap b = null;

    try {
        URL url = new URL(fullUrl);
        URLConnection conn = url.openConnection();
        conn.setDoInput(true);
        conn.connect();
        //save bitmap to file
        InputStream is = conn.getInputStream();
        String filename = String.format("%d", fullUrl.hashCode());
        File file = new File(context.getFilesDir(), filename);
        if(file.exists()){
            //delete
            file.delete();
            file=null;
        }
        file = new File(context.getFilesDir(), filename);

        FileOutputStream out = new FileOutputStream(file);
        byte buffer[] = new byte[256];
        while(true){
            int cnt = is.read(buffer);
            if(cnt <=0){
                break;
            }
            out.write(buffer,0, cnt);
        }

        out.flush();
        out.close();
        is.close();

        b = BitmapFactory.decodeFile(file.getAbsolutePath());

    } catch (Exception e) {
        e.printStackTrace();
    }

    return b;
}

/**
 * Gets an already cached photo
 * 
 * @param context
 * @param fullUrl
 * @return
 */
public static Bitmap getCachedPhoto(Context context, String fullUrl){
    System.gc();
    String filename = String.format("%d", fullUrl.hashCode());
    File file = new File(context.getFilesDir(), filename);
    if(file.exists()){
        try {
            Bitmap b = BitmapFactory.decodeFile(file.getAbsolutePath());
            return b;
        } catch (Exception e) {
        }
    }

    return null;
}

然后,要在适配器中设置图像,您可以这样做:

//set info
    vh.iv.setTag("");
    String foto = your_url_goes_here;
    vh.iv.setImageResource(R.drawable.fotodefault_2x);
    if(!TextUtils.isEmpty(foto)){
        vh.iv.setTag(foto);
        Bitmap b = getCachedPhoto(context, foto);
        if(b != null){
            vh.iv.setImageBitmap(b);
        }else{
            new ImageCacher(context, vh.iv).execute(foto);
        }
    }

不要忘记正确封装类和方法。 希望对您有所帮助。

【讨论】:

  • 你能给我更多关于缓存算法的想法吗?
  • 检查编辑后的答案。我建议您使用我现在正在使用的代码。随意进行修改和改进。问候。
  • 在代码中我使用内部存储进行缓存。如果文件很大,您可能想使用外部存储。此外,我在设置正确的图像之前设置了一个默认的可绘制资源,所以如果需要几秒钟,用户可以看到一些东西,而不是空白或旧图像。
【解决方案3】:

我的 arrayAdapter 出现了随机图片问题。然后我使用了 Picasso,它负责在 listview 中重用 imageView:http://square.github.io/picasso/

代码示例:

    Picasso.with(mContext)
            .load(url)
            .resize(size, size)
            .centerCrop()
            .placeholder(R.drawable.image_holder)
            .into(holder.imgDefaultImage);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-08
    • 1970-01-01
    • 1970-01-01
    • 2012-05-26
    • 2014-05-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多