RxJava2自定义图片缓存框架(Concise Vsesion)

使用RxJava2制做简易版图片缓存框架

#####借此也了解RxJava2的对应操做符的使用。git

图片库缓存思绪流程图

Picture library flow chart.png

项目Git地址 github.com/GenialSir/I…github

  • 1,完成后图片库调用方式:数据库

    RxImageLoader.with(this).load("Link").into(ImageView);
    复制代码
  • 2,首先建立RxImageLoader,采用单例模式,代码以下:缓存

    /**
     * @author genialsir@163.com (GenialSir) on 2019/5/10
     */
    public class RxImageLoader {
    
    static RxImageLoader singleton;
    
    private String mUrl;
    private final RequestCreator requestCreator;
    
    private RxImageLoader(Builder builder) {
       requestCreator = new RequestCreator(builder.mContext);
    }
    
    public static RxImageLoader with(Context context) {
        if (singleton == null) {
          synchronized (RxImageLoader.class) {
                if (singleton == null) {
                    singleton = new Builder(context).build();
                }
            }
        }
        return singleton;
    }
    
    
    public RxImageLoader load(String url) {
        mUrl = url;
        return singleton;
    }
    
    
    public void into(final ImageView imgView) {
    
      //Concat等待订阅你传递给它的每一个其余Observable,直到上一个Observable完成。
      Observable.concat(requestCreator.getMemoryCacheObservable(mUrl),
                 requestCreator.getDiskCacheObservable(mUrl),
                 requestCreator.getNetworkCacheObservable(mUrl))
                // rx1写法 若Image为null,则依次执行disk、Network。
       //.first(new Func1<Image, Boolean>() {
      //  
      // @Override
      // public Boolean call(Image image) {
      // //若数据为null,则往下执行。
      //   return image != null;
      //                            }
      //                        })
              //rx2写法,用于校验数据处理条件。
              .filter(new Predicate<Image>() {
                  @Override
                  public boolean test(Image image) throws Exception {
                      //若无效连接或者无效bitmap则跳过不执行onNext。
                      return !(TextUtils.isEmpty(image.getUrl()) && image.getBitmap() == null);
                  }
              })
              //指定concat执行完第一个知足条件的则不往下执行。
              .firstElement()
              .toObservable()
              .subscribe(new Observer<Image>() {
                  @Override
                  public void onSubscribe(Disposable d) {
    
                  }
    
                  @Override
                  public void onNext(Image image) {
                      imgView.setImageBitmap(image.getBitmap());
                  }
    
                  @Override
                  public void onError(Throwable e) {
    
                  }
    
                  @Override
                  public void onComplete() {
    
                  }
              });
    
      //Consumer有返回Observable对象。
      //                        .subscribe(new Consumer<Image>() {
      //                            @Override
      //public void accept(Image image) throws              Exception {
      //                                imgView.setImageBitmap(image.getBitmap());
      //                            }
      //                        });
      }
    
      private static class Builder {
      private Context mContext;
    
      private Builder(Context context) {
          mContext = context;
      }
    
      private RxImageLoader build() {
          return new RxImageLoader(this);
      }
      }
    }
    复制代码
  • 3,管理Image属性的Model:网络

    public class Image {
    
      public Image(String url, Bitmap bitmap) {
          this.url = url;
          this.bitmap = bitmap;
      }
    
      private String url;
    
      private Bitmap bitmap;
    
      public String getUrl() {
          return url;
      }
    
      public void setUrl(String url) {
          this.url = url;
      }
    
      public Bitmap getBitmap() {
          return bitmap;
      }
    
      public void setBitmap(Bitmap bitmap) {
          this.bitmap = bitmap;
      }
    }
    复制代码
  • 4,咱们图片框架展现顺序基于Memory,Disk,Network,先生成共有的抽象类:框架

    public abstract class CacheObservable {
    
      public Observable<Image> getImage(final String url) {
      return Observable.create(new ObservableOnSubscribe<Image>() {
          @Override
          public void subscribe(ObservableEmitter<Image> emitter) throws Exception {
              //订阅没有解除
              if (!emitter.isDisposed()) {
                  Image image = getDataFromCache(url);
                  if (image == null) {
                      //为RXJava2 OnNext不容许为Null值,传入则不往下执行,so 建立Image空值对象。
                      //参考ObservableCreate函数中OnNext。
                      emitter.onNext(new Image("", null));
                  } else {
                      emitter.onNext(image);
                  }
                  emitter.onComplete();
              }
          }
      })
        //I/O操做(读写文件、读写数据库、网络信息交互等)所使用的Scheduler。
        .subscribeOn(Schedulers.io())
        //它指定的操做将在Android主线程运行。
        .observeOn(AndroidSchedulers.mainThread());
      }
    
      public abstract Image getDataFromCache(String url);
    
      public abstract void putDataToCache(Image image);
      }
    复制代码
  • 5,Network缓存管理类:ide

    public class NetworkCacheObservable extends CacheObservable {
    
     @Override
     public Image getDataFromCache(String url) {
         Bitmap bitmap = downloadImage(url);
         if(bitmap != null){
         return new Image(url, bitmap);
         }
         return null;
     }
    
     @Override
     public void putDataToCache(Image image) {
    
     }
    
     private Bitmap downloadImage(String url){
         Bitmap bitmap = null;
         InputStream inputStream = null;
         try {
             URLConnection con = new URL(url).openConnection();
             inputStream = con.getInputStream();
             bitmap = BitmapFactory.decodeStream(inputStream);
         }catch (IOException e){
             e.printStackTrace();
         }finally {
             if(inputStream != null){
                 try {
                     inputStream.close();
                 }catch (IOException e){
                     e.printStackTrace();
                 }
             }
         }
         return bitmap;
       }
     }
    复制代码
  • 6,Disk缓存管理类:函数

    public class DiskCacheObservable extends CacheObservable {
    
       //DiskLruCache中对于图片的最大缓存值.
      private static final int maxSize = 30 * 1024 * 1024;
      private Context mContext;
      private DiskLruCache mDiskLruCache;
    
      public DiskCacheObservable(Context context) {
      mContext = context;
      initDiskLruCache();
      }
    
       private void initDiskLruCache() {
      try {
          File cacheDir = DiskCacheUtil.getDiskCacheDir(mContext, "image_cache");
          if (!cacheDir.exists()) {
              cacheDir.mkdirs();
          }
          int versionCode = DiskCacheUtil.getAppVersionCode(mContext);
          mDiskLruCache = DiskLruCache.open(cacheDir, versionCode, 1, maxSize);
      } catch (Exception e) {
          e.printStackTrace();
      }
      }
    
      @Override
       public Image getDataFromCache(String url) {
       Bitmap bitmap = getDataFromDiskLruCache(url);
          if (bitmap != null) {
          return new Image(url, bitmap);
      }
      return null;
      }
    
      private Bitmap getDataFromDiskLruCache(String url) {
      FileDescriptor fileDescriptor = null;
      FileInputStream fileInputStream = null;
      DiskLruCache.Snapshot snapshot = null;
      try {
          //生成图片URL对应的key
          String key = DiskCacheUtil.getMd5String(url);
          //查找key对应的缓存
          snapshot = mDiskLruCache.get(key);
          if (snapshot != null) {
              fileInputStream = (FileInputStream) snapshot.getInputStream(0);
              fileDescriptor = fileInputStream.getFD();
          }
          //将缓存数据解析成Bitmap对象
          Bitmap bitmap = null;
          if (fileDescriptor != null) {
              bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor);
          }
          return bitmap;
      } catch (IOException e) {
          e.printStackTrace();
      } finally {
          if (fileDescriptor == null && fileInputStream != null) {
              try {
                  fileInputStream.close();
              } catch (IOException e) {
    
              }
          }
      }
      return null;
      }
    
      @Override
      public void putDataToCache(Image image) {
      try {
          //第一步:获取将要缓存的图片的对应惟一key值
          String key = DiskCacheUtil.getMd5String(image.getUrl());
          //第二步:获取DiskLruCache的Editor
          DiskLruCache.Editor editor = mDiskLruCache.edit(key);
          if (editor != null) {
              //第三步:从Editor中获取OutputStream
              OutputStream outputStream = editor.newOutputStream(0);
              //第四步:下载网络图片且保存至DiskLruCache图片缓存中
              boolean isSuccessful = download(image.getUrl(), outputStream);
              if (isSuccessful) {
                  editor.commit();
              } else {
                  editor.abort();
              }
              mDiskLruCache.flush();
          }
      } catch (Exception e) {
          e.printStackTrace();
      }
      }
    
      private boolean download(String downloadUrl, OutputStream outputStream) {
      HttpURLConnection urlConnection = null;
      BufferedOutputStream out = null;
      BufferedInputStream in = null;
      try {
          final URL url = new URL(downloadUrl);
          urlConnection = (HttpURLConnection) url.openConnection();
          in = new BufferedInputStream(urlConnection.getInputStream(), 8 * 1024);
          out = new BufferedOutputStream(outputStream, 8 * 1024);
          int buffer;
          while ((buffer = in.read()) != -1) {
              out.write(buffer);
          }
          //download successfully.
          return true;
      } catch (IOException e) {
          e.printStackTrace();
      } finally {
          if (urlConnection != null) {
              urlConnection.disconnect();
          }
          try {
              if (out != null) {
                  out.close();
              }
              if (in != null) {
                  in.close();
              }
          } catch (IOException e) {
              e.printStackTrace();
          }
      }
      return false;
      }
    }
    复制代码
  • 7 Memory缓存管理类:ui

    public class MemoryCacheObservable extends CacheObservable {
    
      //KB
      private int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
      private int cacheSize = maxMemory / 8;
    
      private LruCache<String, Bitmap> mLruCache = new LruCache<String, Bitmap>(cacheSize) {
          @Override
          protected int sizeOf(String key, Bitmap value) {
          return value.getRowBytes() * value.getHeight() / 1024;
          }
      };
    
      @Override
      public Image getDataFromCache(String url) {
          Bitmap bitmap = mLruCache.get(url);
          if (bitmap != null) {
              return new Image(url, bitmap);
          }
          return null;
      }
    
      @Override
      public void putDataToCache(Image image) {
          if (image != null) {
              mLruCache.put(image.getUrl(), image.getBitmap());
          }
      }
    }
    复制代码
  • 8 生成统一管理缓存类:this

    public class RequestCreator {
    
     private static final String TAG = "RequestCreator";
    
     private MemoryCacheObservable memoryCacheObservable;
     private DiskCacheObservable diskCacheObservable;
     private NetworkCacheObservable networkCacheObservable;
    
      public RequestCreator(Context context){
     memoryCacheObservable = new MemoryCacheObservable();
     diskCacheObservable = new DiskCacheObservable(context);
     networkCacheObservable = new NetworkCacheObservable();
    复制代码

    }

    public Observable<Image> getMemoryCacheObservable(String url) {
     Log.d(TAG, "getMemoryCacheObservable url is " + url);
     return memoryCacheObservable.getImage(url)
             .filter(new Predicate<Image>() {
                 @Override
                 public boolean test(Image image) throws Exception {
                     return !(TextUtils.isEmpty(image.getUrl()) && image.getBitmap() == null);
                 }
             })
             .doOnNext(new Consumer<Image>() {
                 @Override
                 public void accept(Image image) throws Exception {
                     Log.d(TAG,"getMemoryCacheObservable get data from memory" + image);
                 }
             });
     }
    
      public Observable<Image> getDiskCacheObservable(String url) {
     Log.d(TAG, "getDiskCacheObservable url is " + url);
     return diskCacheObservable.getImage(url)
             .filter(new Predicate<Image>() {
                 @Override
                 public boolean test(Image image) throws Exception {
                     return !(TextUtils.isEmpty(image.getUrl()) && image.getBitmap() == null);
                 }
             })
             .doOnNext(new Consumer<Image>() {
                 @Override
                 public void accept(Image image) throws Exception {
                     Log.d(TAG,"getDiskCacheObservable accept");
                     memoryCacheObservable.putDataToCache(image);
                 }
             });
     }
    
      public Observable<Image> getNetworkCacheObservable(String url) {
     Log.d(TAG, "getNetworkCacheObservable url is " + url);
     return networkCacheObservable.getImage(url)
             .filter(new Predicate<Image>() {
                 @Override
                 public boolean test(Image image) throws Exception {
                     return image != null;
                 }
             })
             .doOnNext(new Consumer<Image>() {
                 @Override
                 public void accept(Image image) throws Exception {
                     Log.d(TAG,"getNetworkCacheObservable accept.");
                     diskCacheObservable.putDataToCache(image);
                     memoryCacheObservable.putDataToCache(image);
                 }
             });
     }
     }
    复制代码

至此,基于RxJava2简易版的图片缓存框架完成,如有问题请评论留言。如果感受对你有些帮助的话点个喜欢,多多益善,哈哈。

lqd, I am not your brother.jpg
相关文章
相关标签/搜索