首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >手写图片缓存框架 ImageLoader

手写图片缓存框架 ImageLoader

作者头像
老马的编程之旅
发布于 2022-06-22 01:52:10
发布于 2022-06-22 01:52:10
93900
代码可运行
举报
文章被收录于专栏:深入理解Android深入理解Android
运行总次数:0
代码可运行

图片缓存是App开发中最常见的,本篇博文给大家带来自己手写的图片缓存框,大致的思路很简单,首先从内存中获取图片,如果内存中没有,就从手机本地进行获取,如果还没有,就从网络访问进行获取。 所以,我们在ImageLoader中只需要暴露一个方法loadImage(),外部只需要调用这个方法就可以完成图片缓存的所以逻辑

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//加载图片到对应的控件
public void loadImage(String key, ImageView view) {

    synchronized (view) {
        this.imageView = view;
        //检查缓存里是否有
        Bitmap bitmap = getFromCache(key);

        if (bitmap != null) {

            //缓存存在,直接显示
            view.setImageBitmap(bitmap);
        } else {
            //网络进行下载
                /*view.setBackgroundDrawable(drawable);*/
            view.setBackgroundDrawable(new ColorDrawable(Color.GRAY));

            ImageAsycTask task = new ImageAsycTask(view);
            task.execute(key);
        }
    }

}

这里,我将从内存中和本地获取图片的逻辑都统一放在getFromCache()方法中,这里值得一提的是,当内存中没有,本地有该图片的时候,还会将这个图片放入LinkedHashMap中,让这个图片在LinkedHashMap中处于最新的位置,不至于被回收。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private Bitmap getFromCache(String key) {
    //检查内存软引用
    synchronized (firstHashMap) {
        if (firstHashMap.get(key) != null) {
            Bitmap bitmap = firstHashMap.get(key).get();
            if (bitmap != null) {
                //更新一下,因为Lru算法会默认清除最老的选项
                firstHashMap.put(key, new SoftReference<Bitmap>(bitmap));
                return bitmap;
            }
        }
    }
    //检查磁盘
    Bitmap bitmap = getFromLocal(key);
    if (bitmap != null) {
        //更新一下,因为Lru算法会默认清除最老的选项
        firstHashMap.put(key, new SoftReference<Bitmap>(bitmap));
        return bitmap;
    }
    return null;
}

在内存中,我使用了一个LinkedHashMap

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private static LinkedHashMap<String, SoftReference<Bitmap>> firstHashMap = new LinkedHashMap<String, SoftReference<Bitmap>>(MAX_LENGTH) {
    @Override
    protected boolean removeEldestEntry(Entry<String, SoftReference<Bitmap>> eldest) {
        if (this.size() > MAX_LENGTH) {
            //返回true,表示移除最老的
            return true;
        }
            //往磁盘进行添加
            diskCache(eldest.getKey(), eldest.getValue());
            return false;
    }

};

这里内部的removeEldestEntry()方法内部如果返回true,会默认移除掉最旧的一个成员,返回false表示不移除,同时还会把图片放入到手机本地中,这个逻辑通过diskCache()方法实现的,这里图片在本地中名字使用md5加密后的名字

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//  把图片缓存到本地磁盘
private static void diskCache(String key, SoftReference<Bitmap> value) {
    //消息摘要算法
    Bitmap bitmap;
    FileOutputStream os = null;
    try {
        String fileName = MD5Utils.md5(key, "utf-8");
        String path = mContext.getCacheDir().getAbsolutePath() + File.separator + fileName;

        os = new FileOutputStream(new File(path));
        if (value.get() != null) {
            value.get().compress(Bitmap.CompressFormat.JPEG, 80, os);

        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (os != null) {
            try {
                os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


}

如果本地缓存中没有,会通过getFromLocal(key)方法,从手机本地中进行获取

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//检查sd卡里是否有
private Bitmap getFromLocal(String key) {
    InputStream is = null;
    try {
        String filname = MD5Utils.md5(key, "utf-8");
        if (filname == null) {
            return null;

        } else {
            String path = mContext.getCacheDir().getAbsolutePath() + File.separator + filname;
            is = new FileInputStream(new File(path));
            Bitmap bitmap = BitmapFactory.decodeStream(is);
            return bitmap;
        }
    } catch (Exception e) {
        e.printStackTrace();
        return null;

    } finally {
        if (is != null) {
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}

如果本地和内存都没有的话,那么就从网络进行获取,这里使用了AsyncTask

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class ImageAsycTask extends AsyncTask<String, Void, Bitmap> {
    private ImageView imagView;
    private String key;

    public ImageAsycTask(ImageView imageView) {
        this.imagView = imageView;
    }



    @Override
    protected Bitmap doInBackground(String... strings) {
        this.key = strings[0];
        Log.i(TAG,key);
        Bitmap bitmap = downLoad(key);

        return bitmap;
    }

    @Override
    protected void onPostExecute(Bitmap bitmap) {

        super.onPostExecute(bitmap);
        if (bitmap != null) {
            addCache(key, bitmap);
            /*Log.i("11",bitmap.toString());*/
            imagView.setImageBitmap(bitmap);
        }
    }
}

其中downLoad()方法就是访问网络获取图片的方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private Bitmap downLoad(String key) {
    final Bitmap[] bitmap = new Bitmap[1];
    mHttpClient = new OkHttpClient();
    Request request = new Request.Builder().url(key).build();
    mHttpClient.newCall(request).enqueue(new Callback() {



        @Override
        public void onFailure(Call call, IOException e) {
            Log.i("TAG", "网络访问失败了");

        }

        @Override
        public void onResponse(Call call, Response response) throws IOException {
            InputStream is = response.body().byteStream();
            bitmap[0] = BitmapFactory.decodeStream(is);
            Log.d("okHttp", bitmap[0].toString());
                   }
    });
    return bitmap[0];


}

图片下载完成之后,我们会将其读写到内存中,并显示在view上,这个view是通过AsyncTask的构造函数传进来的

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private void addCache(String key, Bitmap bitmap) {
    if (bitmap != null) {
        synchronized (firstHashMap) {
            firstHashMap.put(key, new SoftReference<Bitmap>(bitmap));
        }
    }
}

这样这个图片缓存框架就写好了,我们就单纯的在MainActivity中访问网络进行显示来验证我们的框架,布局太简单就不贴了

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class MainActivity extends AppCompatActivity {
    String url = "http://7mno4h.com2.z0.glb.qiniucdn.com/560bd9b6Nc4b5cbfe.jpg";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ImageView imageView  = (ImageView) findViewById(R.id.image);
        ImageLoader imageLoader = ImageLoader.getmInstance(this);
        imageLoader.loadImage(url,imageView);
    }
}

运行项目,效果如下:

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2016-07-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
高频面试点:Android性能优化之内存优化(下篇)
链接:https://juejin.im/post/5e72b2d151882549236f9cb8
陈宇明
2020/12/16
6590
我的图片四级缓存框架
开发App一定涉及到图片加载、图片处理,那就必须会用到三方的图片框架,要么选择自己封装。至于主流的三方图片框架,就不得不说老牌的ImageLoader、如今更流行的Glide、Picasso和Fresco。但三方的框架本文不会过多介绍。
蜻蜓队长
2018/08/03
8950
我的图片四级缓存框架
picasso图片缓存框架
picasso是Square公司开源的一个Android图形缓存库,地址http://square.github.io/picasso/,可以实现图片下载和缓存功能。 picasso使用简单,如下 Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);   主要有以下一些特性: 在adapter中回收和取消当前的下载; 使用最少的内存完成复杂的图形转换操作; 自动的内存和硬盘缓存; 图形转换操作,如变换
xiangzhihong
2018/01/30
1.9K0
picasso图片缓存框架
ImageLoader
这次做一个图片加载器,里面涉及到线程池,bitmap的高效加载,LruCache,DiskLruCache。接下来我先介绍这四个知识点
提莫队长
2019/02/21
4660
《Android源码设计模式》学习笔记之ImageLoader
需求:设计一个图片加载工具类。 要求:职责单一、可扩展性强、实现三级缓存,遵循开闭原则。
程序员飞飞
2020/02/27
6460
android之listview缓存图片(缓存优化)
网上关于这个方面的文章也不少,基本的思路是线程+缓存来解决。下面提出一些优化: 1、采用线程池 2、内存缓存+文件缓存 3、内存缓存中网上很多是采用SoftReference来防止堆溢出,这儿严格限制只能使用最大JVM内存的1/4 4、对下载的图片进行按比例缩放,以减少内存的消耗 具体的代码里面说明。先放上内存缓存类的代码MemoryCache.java: public class MemoryCache {   private static final String TAG = "MemoryC
xiangzhihong
2018/01/29
1.9K0
Android瀑布流照片墙实现,体验不规则排列的美感
本文讲解了如何利用Android原生开发实现照片墙功能,包括布局、照片显示、图片缓存、滑动优化等方面的具体实现。同时介绍了如何实现查看原图和多点触控缩放的功能。
用户1158055
2018/01/05
3.1K0
Android瀑布流照片墙实现,体验不规则排列的美感
Android-Universal-Image-Loader图片异步加载并缓存
 这个图片异步加载并缓存的类已经被很多开发者所使用,是最常用的几个开源库之一,主流的应用,随便反编译几个火的项目,都可以见到它的身影。        可是有的人并不知道如何去使用这库如何进行配置,网上查到的信息对于刚接触的人来说可能太少了,下面我就把我使用过程中所知道的写了下来,希望可以帮助自己和别人更深入了解这个库的使用和配置。         GITHUB上的下载路径为:https://github.com/nostra13/Android-Universal-Image-Loader ,下载最新的库
xiangzhihong
2018/01/29
1.3K0
Android-Universal-Image-Loader图片异步加载并缓存
android使用LruCache对listview加载图片时候优化处理
注意:LruCache是有版本限制的,低版本的sdk需要在libs文件夹添加相应的support-4v文件。 本文改造的大部分是参考http://www.iteye.com/topic/1118828,感谢。 不废话直接上工程代码,内有关键注释,项目就不上传了,自己对照着上面网址改呗。 首先是Application文件,负责创建图片存储文件夹: public class MyApp extends Application{ @Override public void onCrea
xiangzhihong
2018/01/29
8630
[android] 练习使用ListView(三)
解决OOM和图片乱序问题 package com.android.test; import java.io.InputStream; import java.net.HttpURLConnectio
唯一Chat
2019/09/10
3730
[android] 练习使用ListView(三)
13.缓存、三级缓存、内存溢出、AsyncTask
SharePreference工具类 /** * SharePreference封装 * */ public class PrefUtils { public static final String PREF_NAME = "config"; public static boolean getBoolean(Context ctx, String key, boolean defaultValue) { SharedPreferences sp = ctx.getSharedPre
六月的雨
2018/05/14
1.2K0
使用LRU算法缓存图片,android 3.0
在您的UI中显示单个图片是非常简单的,如果您需要一次显示很多图片就有点复杂了。在很多情况下 (例如使用 ListView, GridView 或者 ViewPager控件), 显示在屏幕上的图片以及即将显示在屏幕上的图片数量是非常大的(例如在图库中浏览大量图片)。 在这些控件中,当一个子控件不显示的时候,系统会重用该控件来循环显示 以便减少对内存的消耗。同时垃圾回收机制还会 释放那些已经载入内存中的Bitmap资源(假设您没有强引用这些Bitmap)。一般来说这样都是不错的,但是在用户来回滑动屏幕
xiangzhihong
2018/01/30
1.1K0
大量图片优化
最近在练习中用GridView加入相册中图片发现加入大量的相片之后,GirdView会变得很卡,想到或许可以用异步加载的方式来解决,但是能力有限,想得到却无法实现。在读了一些大牛的博客和代码之后,终于实现了。 1  在异步加载之前的代码的和普通加载代码一样,只需要在GirdView的Adapter的public View getView(int position, View convertView, ViewGroupparent)方法使用异步加载的方式返回ImageView。 2  如果能把加载过的
xiangzhihong
2018/01/30
9660
Android-Universal-Image-Loader源码分析
ImageLoader 是 android 使用中出现比较早(PS:即的刚接触安卓项目的时候就用的是这个图片加载图,算算已经快5年了),使用最多的一个开源图片加载库了。随着glide , fresco 和 picasso等图片加载的库出现,ImageLoader使用变得越来越少。最近在看其他图片加载库的源码,顺便补补之前错过的一些事情。
静默加载
2020/05/29
1.8K0
Android Universal Image Loader
最近在阅读Coding的安卓客户端源码,因为该源码的图片加载库使用的是universal-image-loader,我以前也使用过,但是没总结过,所以这次好好研究并总结下它的使用方法。其实,这些类库使用起来不会很难,但是很多时候如果之前没有仔细阅读这些类库的相关文档,开发过程中由于时间紧迫常常会因为快速实现功能而没有采用官方推荐的最佳实践,这样对于应用来说其实是不好的。
宅男潇涧
2018/08/01
6450
Android Universal Image Loader
Android开发笔记(七十七)图片缓存算法
由于手机流量有限,又要加快app的运行效率,因此好的app都有做图片缓存。图片缓存说起来简单,做起来就用到很多知识点,可算是集Android技术之大全了。只要理解图片缓存的算法,并加以实践把它做好,我觉得差不多可以懂半个Android的开发。
aqi00
2019/01/18
1.2K0
【Android应用开发】 Universal Image Loader ( 使用简介 | 示例代码解析 )
转载请注明出处 : http://blog.csdn.net/shulianghan/article/details/50824912
韩曙亮
2023/03/27
1.2K0
【Android应用开发】 Universal Image Loader ( 使用简介 | 示例代码解析 )
Android车轮之图片加载框架Android-Universal-Image-Loader
前言:从学习Android已经有十周时间了,之前都在学习PHP脚本语言,曾经还用纯php写了一个小型论坛,虽然不难,即使你用的东西自己同样封装了,但是最终总是感觉不太舒服,后来就用了国内的ThinkPHP框架作为框架学习,然而就慢慢体验到了使用框架的好处,比如优化的程序较好,更容易学习到框架里面不错的知识模块...... 其实Android也是一样的,倘若你开发一个项目的话,一切都从零开始,嘿嘿,那你就可悲╮(╯▽╰)╭,对于开源的东西,学会选择轮子以及会用轮子对于开发项目是非常重要的,接下来介绍的轮子就
AlicFeng
2018/06/08
6720
相关推荐
高频面试点:Android性能优化之内存优化(下篇)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档