KJFrameForAndroid框架学习----高效设置网络图片

KJFrameForAndroid框架项目地址:https://github.com/kymjs/KJFrameForAndroid

或备用地址http://git.oschina.net/kymjs/KJFrameForAndroid

KJFrameForAndroid开发群:257053751

我们都知道,计算机读取数据时:内存的读取速度是最快的,然后是文件的读取速度,最后是网络资源的读取。

假设每次载入同一张图片都要从网络获取,那代价实在太大了。所以同一张图片仅仅要从网络获取一次就够了,然后在本地缓存起来,之后载入同一张图片时就 从缓存中载入就能够了。从内存缓存读取图片是最快的,可是由于Android对每一个应用所能使用的内存容量都有限制,所以最好再加上文件缓存。文件缓存空间也不是无限大的,容量越大读取效率越低,这个非常好理解,从沙漠中找出丢失的一根针和从盘子中找到一根针,哪个easy一想即知。因此我们常设置一个限定大小比方10M。

所以,载入图片的流程应该是:

1、先从内存缓存中获取,取到则返回,取不到则进行下一步;

2、从文件缓存中获取,取到则返回并更新到内存缓存,取不到则进行下一步;

3、从网络下载图片,并更新到内存缓存和文件缓存。

假设您仅仅想了解文件缓存与内存缓存公用,请查看下一篇博文。



在过去,我们常常会使用一种很流行的内存缓存技术的实现,即软引用或弱引用 (SoftReference or WeakReference)。可是依据Google的描写叙述:如今已经不再推荐使用这样的方式了,由于从 Android 2.3 (API Level 9)開始,垃圾回收器会更倾向于回收持有软引用或弱引用的对象,这让软引用和弱引用变得不再可靠。另外,Android 3.0 (API Level 11)中,图片的数据会存储在本地的内存其中,因而无法用一种可预见的方式将其释放,这就有潜在的风险造成应用程序的内存溢出并崩溃。

因此,我们很多其它的是去使用lru算法(Least Recently Used 最近最少使用算法)最初这样的算法是用在操作系统调度上的。他的原理是通过个线性表存储数据,并记录数据每次调用次数,越经常使用到的排名就越靠前,越少用到的排名就越靠后,假设是一个新增加的数据,就会把它放在第一位,然后移除掉排名最后一位的数据。这里是KJFrameForAndroid框架中关于内存lru算法的实现方式LruMemoryCache

既然是载入网络图片,那么当然须要载入的控件和网络图片地址作为參数,示比例如以下所看到的

private void loadImage(ImageView imageView, String imageUrl) {
    // 首先訪问内存缓存,推断图片是否已经存在
    Bitmap bitmap = mMemoryCache.get(StringUtils.md5(imageUrl));
    if (bitmap != null) {
            imageView.setImageBitmap(bitmap);
        }else{
        //否则就去网络下载
        BitmapWorkerTask task = new BitmapWorkerTask(imageView);
            task.execute(imageUrl);
    }
}

至于实际下载的方法,我就不具体解说了,相信大家都能想到,就是一个网络请求,然后下载图片,再转成bitmap,最后设置为控件图片。然而这里有一个须要注意的重要地方,就是当我们把图片下载成功后要记得在mMemoryCache中缓存起来。

这里是KJFraemForAndroid应用开发框架中的一段网络图片载入的代码:

  /********************* 异步获取Bitmap并设置image的任务类 *********************/
    private class BitmapWorkerTask extends AsyncTask<String, Void, Bitmap> {
        private View imageView;

        public BitmapWorkerTask(View imageview) {
            this.imageView = imageview;
        }

        @Override
        protected Bitmap doInBackground(String... params) {
            Bitmap bitmap = null;
            //有关这种方法,以下的文章将会解说
            byte[] res = downloader.loadImage(params[0]);
            if (res != null) {
                bitmap = BitmapCreate.bitmapFromByteArray(res, 0, res.length,
                        config.width, config.height);
            }
            if (bitmap != null && config.openMemoryCache) {
                // 图片加载完毕后缓存到LrcCache中
                putBitmapToMemory(params[0], bitmap);
                if (config.isDEBUG)
                    KJLoger.debugLog(getClass().getName(),
                            "put to memory cache\n" + params[0]);
            }
            return bitmap;
        }

        @Override
        protected void onPostExecute(Bitmap bitmap) {
            super.onPostExecute(bitmap);
            if (imageView instanceof ImageView) {
                if (bitmap != null) {
                    ((ImageView) imageView).setImageBitmap(bitmap);
                }
            } else {
                imageView.setBackgroundDrawable(new BitmapDrawable(bitmap));
            }
            if (config.callBack != null)
                config.callBack.imgLoadSuccess(imageView);
            taskCollection.remove(this);
        }
    }

深入理解图片载入在实际项目中的应用

以上仅仅是网络图片载入并缓存的基本操作,那么我们假设在实际项目中使用必须考虑到代码的完备性与可扩展性。

①比方我们想指定图片的大小,尽管我们能够通过设置view的固定宽高来强制图片的显示大小,但假设是一张几兆的图片,而我们仅仅须要15*15分辨率大小的显示区域,这显然是浪费的;

②又比方,我们希望控件在网络正在下载图片时先显示一个默认的图片(比方一个灰色的头像)又或者是图片下载的时候显示一个环形的进度条,那么上面的代码是没有办法的;

③再比方,我们希望图片的下载方式有多种,对于不同站点来源有不同的下载方式。。。。

这些种种特殊的需求告诉我们,上面的代码全然没有办法做到。那么为了控件的完备性与可扩展性,我们就须要一个配置器、一个显示器、一个下载器。。等等依据特殊须要而加入的插件式开发。

因此,我们能够看到在KJFrameForAndroid框架的org.kymjs.aframe.bitmap包下有着KJBitmapConfig、I_ImageLoder、I_Display等等用final修饰的类或者协议接口。

比方KJBitmapConfig类,是一个用final修饰的配置器类,通过这个配置器,我们就能够动态的对每一张下载的图片设置宽高、以及内存大小等。而I_ImageLoder、I_Display则是两个协议接口,分别定义了下载器和显示器的方法,这里实际上是GoF设计模式中工厂方法模式的应用,仅仅是这里的工厂实际上并非用来创建对象,而是用来定义显示方法或下载方法的,不论是哪个实现了I_ImageLoder抽象工厂的实际工厂,都必须有一个载入图片的方法。那么在项目的实际应用中,就能够无论这个下载器的实际工厂是什么,仅仅须要调用工厂的载入图片的方法即可了。

/**
 * 图片加载接口协议,可自己定义实现此协议的下载器
 *
 * @explain 採用工厂方法模式设计的下载器,本类也是一个抽象工厂类,用于生产byte[]产品
 * @author kymjs([email protected])
 * @version 1.0
 * @created 2014-7-11
 */
public interface I_ImageLoder {
    public byte[] loadImage(String imageUrl);

}

这里我们应该就能够知道上面的代码段中有这么一段代码原因了

byte[] res = downloader.loadImage(params[0]);

downloader实际上就是下载器的抽象工厂。

至于显示器的逻辑和下载器是一样的,这里我就不具体介绍了,大家能够自己查看KJFrameForAndroid的源码或演示样例项目。

这里是I_ImageLoader下载器协议的一个实现类 Downloader.java,大家当然也能够依据自己的须要去实现自己的下载器,这全然没有不论什么作为扩展试开发,这对于图片设置代码本身没有不论什么影响。

时间: 2024-10-07 02:43:39

KJFrameForAndroid框架学习----高效设置网络图片的相关文章

KJFrameForAndroid框架学习----高效加载Bitmap

KJFrameForAndroid框架项目地址:https://github.com/kymjs/KJFrameForAndroid 或备用地址http://git.oschina.net/kymjs/KJFrameForAndroid KJFrameForAndroid开发群:257053751 我们在写Android程序的时候,肯定会用到很多图片.那么对于图片的压缩处理自然是必不可少.为什么要压缩?我想这个问题不必在强调了,每个人在最初学习Android的时候肯定都会知道这么一个原因:我们编

KJFrameForAndroid框架学习----深入理解注解原理

Android开发中,有一个让人又爱又恨的方法叫findViewById(int);我想如果你是一民Android开发者,必然知道这个方法,让我们来看一下KJFrameForAndroid框架是如何解决这个问题的. KJFrameForAndroid框架项目地址:https://github.com/kymjs/KJFrameForAndroid. 为什么说findViewById(int);让人又爱又恨呢?想必大家也是很有感触. 写一个布局,用Java代码写和用xml文件写,完成速度完全是无法

KJFrameForAndroid框架学习——多线程管理

在Android开发中,由于不能再UI线程中做耗时操作,常常需要开启线程来做一些操作.但是这样一来就产生了一个问题,就是大量的线程并发执行,造成了线程维护的开销进而使得代码质量下降手机发烫又耗电.让我们来看一下KJFrameForAndroid框架是如何解决这个问题的. KJFrameForAndroid框架项目地址:https://github.com/kymjs/KJFrameForAndroid. 其实Android提供了一套专门用于异步处理的类,就是我们熟悉又模式的AsynTask类.

Hadoop学习笔记—18.Sqoop框架学习

一.Sqoop基础:连接关系型数据库与Hadoop的桥梁 1.1 Sqoop的基本概念 Hadoop正成为企业用于大数据分析的最热门选择,但想将你的数据移植过去并不容易.Apache Sqoop正在加紧帮助客户将重要数据从数据库移到Hadoop.随着Hadoop和关系型数据库之间的数据移动渐渐变成一个标准的流程,云管理员们能够利用Sqoop的并行批量数据加载能力来简化这一流程,降低编写自定义数据加载脚本的需求. Apache Sqoop(SQL-to-Hadoop) 项目旨在协助 RDBMS 与

windows下scrapy框架学习笔记—&#39;scrapy&#39; 不是内部或外部命令

最近几天在深入的学习scrapy框架,但是装完各种需要的基础包之后却发现scrapy命令在别的路径下都用不了,我一开始是把python安装在F:\Python路径下的,安装了scrapy后它默认都会安装在这个路径下,scrapy在路径F:\Python\Scripts路径下,我的scrapy命令只能在此路径下用,因此创建什么工程也都只能在此文件下. 想了一下它的工作原理:它在F:\Python\Scripts路径下,就会在Scripts文件下存在一个scrapy批处理文件,那么在DOS下想要命令

spring框架学习(六)AOP

spring框架学习(六)AOP AOP(Aspect-OrientedProgramming)面向方面编程,与OOP完全不同,使用AOP编程系统被分为方面或关注点,而不是OOP中的对象. AOP的引入 在OOP面向对象的使用中,无可避免的会出现代码重复,而且使用面向对象的编程方式,这种重复无法避免,比如用户权限判断中,根据相应的权限执行相应的方法:在servlet中设置编码格式时,同样相同的代码出现很多次,而且还根业务无关,很容易忘记写,结果运行的时候就出现乱码拉.这种重复代码不仅使编码麻烦,

Struts2框架学习(三) 数据处理

Struts2框架学习(三) 数据处理 Struts2框架框架使用OGNL语言和值栈技术实现数据的流转处理. 值栈就相当于一个容器,用来存放数据,而OGNL是一种快速查询数据的语言. 值栈:ValueStack一种数据结构,操作数据的方式为:先进后出 OGNL : Object-GraphNavigation Language(对象图形导航语言)将多个对象的关系使用一种树形的结构展现出来,更像一个图形,那么如果需要对树形结构的节点数据进行操作,那么可以使用 对象.属性 的方式进行操作,OGNL技

spring框架学习(五)注解

spring框架学习(五)注解 注解Annotation,是一种类似注释的机制,在代码中添加注解可以在之后某时间使用这些信息.跟注释不同的是,注释是给我们看的,java虚拟机不会编译,注解也是不编译的,但是我们可以通过反射机制去读取注解中的信息.注解使用关键字@interface,继承java.lang.annotition.Annotition spring框架为我们提供了注解功能. 使用注解编程,主要是为了替代xml文件,使开发更加快速.但是,xml文件的使用就是解决修改程序修改源代码,现在

Android Afinal框架学习(二) FinalActivity 一个IOC框架

框架地址:https://github.com/yangfuhai/afinal 对应的源码: net.tsz.afinal.annotation.view.* FinalActivity FinalActivity是一个基础类,结合注解实现了,依赖注入(view的资源id,常用的监听器), 利用set方式注入 完全注解方式就可以进行UI绑定和事件绑定,无需findViewById和set event Listener 这个过程:initInjectedView>findViewById.set