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
相關文章
相關標籤/搜索