Android ListView,GridView,RecyclerView图片加载错位闪动问题解决办法

本文探讨了Android应用中ListView, GridView和RecyclerView在进行异步图片加载时出现的错位闪动问题。问题根源在于控件复用和异步加载。解决方案包括使用缓存、设置默认图片以及为ImageView设置TAG。作者提供了一个简单的图片加载封装类,有助于减少图片加载时的闪动现象。" 107618408,9929107,约瑟夫环问题解析与解决方案,"['算法', '数学', '编程问题', '数据结构']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近看了一下RecyclerView这个控件,的确非常好用,但是也并没有摆脱这种问题,recyclerview内部好像自带有控件的复用。
问题的根源还是控件的复用以及异步加载所引起的问题
解决思路:
1.使用缓存,从缓存中加载的速度大大少于从网络加载
2.设置默认图片,当一个item设置个图片然后被复用,而当前显示的图片还没有数据,正在从网络获取,这个时候此item就会显示复用前显示的图片,而当前应该显示的图片从网络中获取到之后就会重新加载上去就出现的图片闪动的情况
3.给ImageView设置TAG

我封装了一个类来进行网络获取加载图片,代码比较简单,用起来也非常方便,诸位可以根据自己的需求进行修改
话不多说上代码:

package My.Utils;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.util.Log;
import android.util.LruCache;
import android.widget.ImageView;

import com.wkk.myutils.R;

import java.io.IOException;

/**
 * Created by Think on 2016/4/11.
 */
public class ImageLoader {

    private static My.Utils.ImageLoader ImageLoader;
    private LruCache<String, Bitmap> lruCache;
    public static final int ID = -100;
    private boolean Savedlocal = false;//此属性控制是否需要缓存到本地
    private Context context;

  @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
    private ImageLoader(Context context) {
        this.context = context;
        // 版本低于12 数量 大于等于12 容量
        if (Build.VERSION.SDK_INT < 12) {
            lruCache = new LruCache<String, Bitmap>(100);
        } else {
            lruCache = new LruCache<String, Bitmap>(5 * 1024 * 1024) {
                @Override
                protected int sizeOf(String key, Bitmap value) {
                    return value.getByteCount();
                }
            };
        }
    }

    public static My.Utils.ImageLoader getInstance(Context context) {
        if (ImageLoader == null) {
            ImageLoader = new ImageLoader(context);
        }
        return ImageLoader;
    }

    /**
     * 对外开放方法
     * 1.需要设置的Imageview
     * 2.图片的URl
     * 3.默认图片
     */
    public void setimage(ImageView image, String url, int resid) {
        image.setTag(url);
        Bitmap bitmap = lruCache.get(url);
        if (bitmap != null) {
            image.setImageBitmap(bitmap);
            return;
        } else if (Savedlocal) {
            bitmap = Utils.getSavePhone(url);//setSaveToPhone
            if (bitmap != null) {
                image.setImageBitmap(bitmap);
                return;
            }
        }


        if (resid != ID) {
            image.setImageResource(resid);
        } else {
            image.setImageResource(R.mipmap.ic_launcher);
        }
        new AsyncImageDown().execute(new Image(url, image, null));
    }

    public void setimage(ImageView image, String url, Bitmap bitmap1) {
        image.setTag(url);
        Bitmap bitmap = lruCache.get(url);
        if (bitmap != null) {
            image.setImageBitmap(bitmap);
            return;
        } else if (Savedlocal) {
            bitmap = Utils.getSavePhone(url);//setSaveToPhone
            if (bitmap != null) {
                image.setImageBitmap(bitmap);
                return;
            }
        }
        if (bitmap1 != null) {
            image.setImageBitmap(bitmap1);
        } else {
            image.setImageResource(R.mipmap.ic_launcher);
        }
        new AsyncImageDown().execute(new Image(url, image, null));
    }

    public void setimage(ImageView image, String url, Drawable drawable) {
        image.setTag(url);
        Bitmap bitmap = lruCache.get(url);
        if (bitmap != null) {
            image.setImageBitmap(bitmap);
            return;
        } else if (Savedlocal) {
            bitmap = Utils.getSavePhone(url);//setSaveToPhone
            if (bitmap != null) {
                image.setImageBitmap(bitmap);
                return;
            }
        }
        if (drawable != null) {
            image.setImageDrawable(drawable);
        } else {
            image.setImageResource(R.mipmap.ic_launcher);
        }
        new AsyncImageDown().execute(new Image(url, image, null));
    }


    /**
     * 清空数据缓存
     */
    public void evictAll() {
        lruCache.evictAll();
    }

    private class AsyncImageDown extends AsyncTask<Image, Void, Image> {

        @Override
        protected Image doInBackground(Image... images) {
            //url imaeg
            Image image = images[0];
            try {
                Bitmap bitmap = HttpUtils.getImageFromNet(image.getUrl());
                if (bitmap != null && image.getUrl() != null) {
                    lruCache.put(image.getUrl(), bitmap);
                    if (Savedlocal) {
                        Utils.setSaveToPhone(image.getUrl(), bitmap);
                    }
                    image.setBitmap(bitmap);
                    return image;
                }
            } catch (IOException e) {
                e.printStackTrace();
                Log.d("测试", "ImageLoader+AsyncImageDown+doInBackground+图片请求出错" + e.toString());
            }
            return null;
        }

        @Override
        protected void onPostExecute(Image image) {
            if (image != null && image.getBitmap() != null && image.getUrl().equalsIgnoreCase((String) image.getImageView().getTag())) {
                image.getImageView().setImageBitmap(image.getBitmap());
            }
        }
    }


    public void setSavedlocal(boolean savedlocal) {
        Savedlocal = savedlocal;
    }

    private class Image {
        private String url;
        private ImageView imageView;
        private Bitmap bitmap;

        public Image(String url, ImageView imageView, Bitmap bitmap) {
            this.url = url;
            this.imageView = imageView;
            this.bitmap = bitmap;
        }

        public Bitmap getBitmap() {
            return bitmap;
        }

        public void setBitmap(Bitmap bitmap) {
            this.bitmap = bitmap;
        }

        public String getUrl() {
            return url;
        }

        public void setUrl(String url) {
            this.url = url;
        }

        public ImageView getImageView() {
            return imageView;
        }

        public void setImageView(ImageView imageView) {
            this.imageView = imageView;
        }
    }

}

另外还有一些上文中用到的方法

 /**
     * 保存图片到手机内存
     *
     * @param filename
     * @param bitmap
     * @return
     */
    public static void setSaveToPhone(String filename,
                                      Bitmap bitmap) {
        filename = filename.replace("/", "");

        String path = getPath() + "/" + filename;
        File file = new File(path);

        if (!file.exists()) {
            try {
                file.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        try {

            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
            byte[] bytes = baos.toByteArray();

            FileOutputStream out = new FileOutputStream(path);
            out.write(bytes);

            out.flush();
            out.close();
            baos.close();
        } catch (Exception e) {
            i(e.toString() + "utils-保存图片到手机内存-保存出错");
        }
    }

 /**
     * 从本地读取图片
     */
    public static Bitmap getSavePhone(String filename) {
        filename = filename.replace("/", "");

        String path = getPath() + "/" + filename;
        try {
            FileInputStream in = new FileInputStream(path);
            Bitmap bitmap = BitmapFactory.decodeStream(in);
            in.close();
            return bitmap;
        } catch (Exception e) {
        }
        return null;
    }
   public static String getPath() {
        File file = new File(Environment.getExternalStorageDirectory().getPath() + "/wkk");
        if (!file.exists() || !file.isDirectory()) {
            file.mkdirs();
        }
        return file.getPath();
    }

  /**
     * 根据url连接网络 获取图片
     *
     * @param url
     * @return
     * @throws IOException
     */
    public static Bitmap getImageFromNet(String url) throws IOException {
        HttpURLConnection conn = null;
        URL mURL = new URL(url);// 创建一个ur对象
        // 得到http的链接对象
        conn = (HttpURLConnection) mURL.openConnection();
        conn.setRequestMethod("GET");// 设置请求的方法为Get
        conn.setConnectTimeout(10000);// 设置链接服务器的超时时间 如果超过10秒钟没有链接 抛异常
        conn.setReadTimeout(10000);// 设置读取数据超时时间
        conn.connect();// 开始链接
        int responseCode = conn.getResponseCode();// 得到服务器相应码
        if (responseCode == 200) {
            // 访问成功
            InputStream is = conn.getInputStream();// 获得服务器返回的流
            Bitmap bitmap = BitmapFactory.decodeStream(is);// 根据流创建一个Bitmap位图对象
            is.close();
            return bitmap;
        } else {
            Utils.d("测试", "访问失败:responseCode=" + responseCode);
        }
        return null;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值