《Android源码设计模式与实战》稳健性开闭原则学习笔记二

 意思就是软件中的对象类函数,应该对外扩展就跟我们java中的接口一样,我只要增加一个功能在接口中写一个方法然后在另外一个类实现这个接口就ok!

灵活性很强,以为软件生命周期中因为种种原因对原来的代码进行重构,破坏原有的代码系统,但是我们在实际开发中可以用继承的方式来实现代码 修改源代码扩展是同时存在的回到上一次小伟的代码相信大家在面试中 也会被提问到,虽然通过内存加载解决网络图片load问题,但是大家都知道内存是有限的,我们AndroidBitmap 超过8MB直接oom,而且这样用户体验也不好,当用户再次打开应用时原来的图片丢失,又要重新去下载图片,这样特别耗费流量,同时加载也会变慢,而且容易丢失,直接挂掉了,因此有没有更好的缓存机制呢?
随着主管的提醒,小伟又陷入沉思中,终于皇天不负有心人,哈哈,小伟又对代码进行了优化,同时自信心有比之前提升了,很棒哈哈!

package zm.jc.com.bmobsys.disk;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

/**
  图片缓存到sd卡
 * Created by John on 2017/1/17.
 */

public class DiskCache {
    public static String cacheDir="sdcard/cache/";
    //从缓存中获取图片
    public Bitmap get(String url){
        return BitmapFactory.decodeFile(cacheDir+url);
    }
    /**
     * 将图片缓存到内存中
     */
    public void put(String url,Bitmap bitmap){
        FileOutputStream fos=null;
        try {
            fos=new FileOutputStream(cacheDir+url);
            bitmap.compress(Bitmap.CompressFormat.PNG,100,fos);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }finally {
            if(fos!=null){
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}
public class ImageLoader {
    //图片
   ImageCache imageCache=new ImageCache();

    //sd卡缓存
    DiskCache diskCache=new DiskCache();

    //是否使用sd缓存
    boolean isUseDiskCache=false;

    ExecutorService mExecutorService= Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
    public void displayImageView(final String url, ImageView imageView){

        //判断使用哪种缓存
        Bitmap bitmap=isUseDiskCache?diskCache.get(url):imageCache.get(url);
        if(bitmap!=null){
            imageView.setImageBitmap(bitmap);
            return;

        }
 //没有缓存就交给线程池进行下载
    }
    public void useDiskCache(boolean useDiskCache){
        isUseDiskCache=useDiskCache;
    }

用户使用直接这样

       ImageLoader imageLoader=new ImageLoader();
       //使用sd卡缓存
       imageLoader.useDiskCache(true);
       //使用内存缓存
       imageLoader.useDiskCache(false);

经过这次之后主管说,小伟您的思路是正确的,但是有缺陷,如果我想综合二种可以吗?没有缓存时去使用SD卡缓存,sd卡没有再去网络下载这才是最好的策略,这样的主管哪里找吗,工作中如果能遇到这样的一位好的领导你说你怎么能不进步呢?

下面实行双缓存机制

package zm.jc.com.bmobsys.imgcache;

import android.graphics.Bitmap;

import zm.jc.com.bmobsys.disk.DiskCache;

/**
 * Android双缓存机制
 * Created by John on 2017/1/17.
 */

public class DoubleCache {
    ImageCache imageCache=new ImageCache();
    DiskCache diskCache=new DiskCache();
    //先从内存中获取图片,如果没有再从手机SD卡中读取
    public Bitmap get(String url){
        Bitmap bitmap=imageCache.get(url);
        if(bitmap==null){
            bitmap=diskCache.get(url);
        }
        return bitmap;
    }
   //将图片缓存到内存或者sd卡
    public void put(String url,Bitmap bitmap){
        imageCache.put(url,bitmap);
        diskCache.put(url,bitmap);
    }
}

再看看ImageLoader类修改

package zm.jc.com.bmobsys.imgcache;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.widget.ImageView;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import zm.jc.com.bmobsys.disk.DiskCache;

/**
 * Created by John on 2017/1/17.
 */

public class ImageLoader {
    //图片
   ImageCache imageCache=new ImageCache();
    //sd卡缓存
    DiskCache diskCache=new DiskCache();
    //双缓存机制
    DoubleCache doubleCache=new DoubleCache();
    //是否使用sd缓存
    boolean isUseDiskCache=false;
    //是否使用双缓存机制
    boolean isUseDoubleCache=false;

    ExecutorService mExecutorService= Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
    public void displayImageView(final String url, ImageView imageView){
        Bitmap bitmap=null;
        if(isUseDoubleCache)
        {
            bitmap=doubleCache.get(url);
        }else if(isUseDiskCache){
            bitmap=diskCache.get(url);
        }else{
            bitmap=imageCache.get(url);
        }
        if(bitmap!=null){
            imageView.setImageBitmap(bitmap);
        }
//        没有缓存就交给线程池进行下载
    }

    public void useDiskCache(boolean useDiskCache){
        isUseDiskCache=useDiskCache;
    }
    public void useDoubleCache(boolean useDoubleCache){
        isUseDoubleCache=useDoubleCache;
    }

}

最后主管这次还是算比较满意,但是同时问题又来了?因为每个里面很多if else如果一不小心写错了调试的时候可能花很多的时间,那么这样ImageLoader也变的越来越臃肿,扩展性比较差,当软件需求变化时我们尽可能去实现扩展性而不是修改代码,毕竟小伟也尽力了,主管看小伟一脸懵逼的样子准备自己做个榜样,授人鱼,不如授人渔,这里盗个图,如果侵权立马删除哈

《Android源码设计模式与实战》稳健性开闭原则学习笔记二_第1张图片

相信大家看了上面应该也知道put根get方法都是在不断的服用,那么相信大家也非常清除,想这样公共使用的方法我们直接抽取成一个接口是不是更加灵活呢?
好,相信大家思路来了,那么开始撸码继续

下面看下接口的声明

public interface ImageCache {
    public void put(String url, Bitmap bitmap);
    public Bitmap get(String url);
}

然后看MemoryCache类

package zm.jc.com.bmobsys.imgcache;

import android.graphics.Bitmap;
import android.util.LruCache;

/**
 * Created by John on 2017/1/17.
 */

public class MemoryCache implements ImageCache {
    private LruCache mMemoryCache;
    public MemoryCache(){
        //初始化LRU缓存

    }
    @Override
    public void put(String url, Bitmap bitmap) {
        mMemoryCache.put(url,bitmap);

    }

    @Override
    public Bitmap get(String url) {
        return mMemoryCache.get(url);

    }
    //从SD卡缓存DiskCache类
    public class DiskCache implements ImageCache{
        @Override
        public Bitmap get(String url) {
            //本地文件获取图片
            return null;
        }

        @Override
        public void put(String url, Bitmap bitmap) {
            //将bitmap写入文件

        }
    }
    //双缓存机制类
    public class DoubleCache implements ImageCache{
        ImageCache imageCache=new MemoryCache();
        ImageCache diskCache=new DiskCache();
        //先从缓存中获取图片,没有再去sd卡获取
        @Override
        public Bitmap get(String url) {
            Bitmap bitmap=imageCache.get(url);
            if(bitmap==null){
                bitmap=diskCache.get(url);
            }
            return bitmap;
        }

        /**
         * 将图片缓存到内存或者sd卡
         * @param url
         * @param bitmap
         */
        @Override
        public void put(String url, Bitmap bitmap) {
           imageCache.put(url,bitmap);
            diskCache.put(url,bitmap);
        }
    }
}

最后看实现内存缓存 SD卡缓存 双缓存机制代码如下

 ImageLoader imageLoader=new ImageLoader();
        //使用缓存内存
        imageLoader.setImageCache(new MemoryCache());
        //使用SD卡缓存
        imageLoader.setImageCache( new DiskCache());
        //使用双缓存机制
        imageLoader.setImageCache(new DoubleCache());
        imageLoader.setImageCache(new ImageCache() {
            @Override
            public void put(String url, Bitmap bitmap) {
                //缓存图片
            }

            @Override
            public Bitmap get(String url) {
                //从缓存中获取图片资源
                return null;
            }
        });

是不是简化了很多呢?

你可能感兴趣的:(《Android源码设计模式与实战》稳健性开闭原则学习笔记二)