二级缓存 RXJAVA 实现。

二级缓存

网上很多人说三级缓存,其实都是二级缓存。也就是 内存缓存,文件缓存 。所谓的网络缓存 是不存在的、

下面2级缓存 用RXJAVA 实现。代码没有做优化,但是功能实现了。。。

API_server

public interface GetImage {
    @GET("{url}")
    Observable<ResponseBody> getimage(@Path("url") String url);

    String BASE_URL = "http://img2.baa.bitautotech.com/";
}

RetrofitManager:

public class RetrofitManager {
    Retrofit retrofit;

    private RetrofitManager() {
        retrofit = new Retrofit.Builder()
                .baseUrl(GetImage.BASE_URL)
                .addCallAdapterFactory(RxJava3CallAdapterFactory.create()) //添加Rxjava
                .addConverterFactory(GsonConverterFactory.create()) // <span style="font-family: Arial, Helvetica, sans-serif;">定义转化器 可以将结果返回一个json格式</span>
                .build();
    }

    public static final RetrofitManager Instance = new RetrofitManager();

    public static RetrofitManager getInstance() {
        return Instance;
    }

    public GetImage creatserver() {
        return retrofit.create(GetImage.class);
    }

}

缓存父类```CacheObservable:

public abstract class CacheObservable {

    /**
     * 获取缓存数据
     * @param url
     * @return
     */
    public Observable<ImageBean> getImage(final String url) {
        return Observable.create(new ObservableOnSubscribe<ImageBean>() {
            @Override
            public void subscribe(@NonNull ObservableEmitter<ImageBean> e) throws Exception {
                if (!e.isDisposed()) {
                    ImageBean image = getDataFromCache(url);
                    e.onNext(image);
                    e.onComplete();
                }
            }
        }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
    }

    /**
     * 取出缓存数据
     * @param url
     * @return
     */
    public abstract ImageBean getDataFromCache(String url);

    /**
     * 缓存数据
     * @param image
     */
    public abstract void putDataToCache(ImageBean image);
}

内存子类:MemoryCacheObservable

public class MemoryCacheObservable extends CacheObservable {

    private int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
    private int cacheSize = maxMemory / 4;
    private LruCache<String, Bitmap> mLruCache = new LruCache<String, Bitmap>(cacheSize) {
        @Override
        protected int sizeOf(String key, Bitmap bitmap) {
            return bitmap.getRowBytes() * bitmap.getHeight() / 1024;
        }
    };

    @Override
    public ImageBean getDataFromCache(String url) {
        Log.e("getDataFromCache", "getDataFromMemoryCache");
        Bitmap bitmap = mLruCache.get(url);

        return new ImageBean(bitmap, url);


    }

    @Override
    public void putDataToCache(ImageBean image) {
        mLruCache.put(image.getUrl(), image.getBitmap());
        Log.e("putDataToCache", "putDataToCache");
    }
}

文件子类:DiskCacheObservable,文件缓存子类用的是 OKHTT3 的DiskLruCache

public class DiskCacheObservable extends CacheObservable {

    private Context mContext;
    private DiskLruCache mDiskLruCache;
    private final int maxSize = 10 * 1024 * 1024;

    public DiskCacheObservable(Context mContext) {
        this.mContext = mContext;
        initDiskLruCache();
    }

    @Override
    public ImageBean getDataFromCache(String url) {

        Bitmap bitmap = getDataFromDiskLruCache(url);
        Log.e("getDataFromCache", "bitmap.toString()");
        return new ImageBean(bitmap, url);
    }

    @Override
    public void putDataToCache(ImageBean imageBean) {
      RetrofitManager.getInstance().creatserver().getimage(imageBean.getUrl()).doOnNext(new Consumer<ResponseBody>() {
          @Override
          public void accept(ResponseBody responseBody) throws Throwable {

              String key = DiskCacheUtils.getMD5String(imageBean.getUrl());
              DiskLruCache.Editor editor = null;
              try {
                  editor = mDiskLruCache.edit(key);
              } catch (IOException e) {
                  e.printStackTrace();
              }
              Sink sink = editor.newSink(0);
              Log.e("sink", "sink");

              InputStream inputStream = null;
              try {
                  //long fileSize = body.contentLength();
                  //long fileSizeDownloaded = 0;
                  byte[] fileReader = new byte[4096];
                  Buffer buffer = new Buffer();
                  inputStream = responseBody.byteStream();

                  while (true) {
                      int read = inputStream.read(fileReader);
                      if (read == -1) {
                          break;
                      }
                      buffer.write(fileReader, 0, read);
                      //fileSizeDownloaded += read;
                      sink.write(buffer, read);
                      buffer.clear();
                  }
                  if (buffer != null) {
                      buffer.clear();
                      buffer.close();
                  }

                  if (inputStream != null) {
                      inputStream.close();
                  }

                  if (sink != null) {
                      sink.flush();
                      sink.close();
                  }
                  editor.commit();

              } catch (IOException e) {
                  e.printStackTrace();
              }

          }
      }).subscribe();
    }




    public void initDiskLruCache() {
        File cacheDir = DiskCacheUtils.getDiskCacheDir(mContext, "our22_cache");
        if (!cacheDir.exists()) {
            cacheDir.mkdirs();
            Log.e("cach---eDir", cacheDir.getPath());
        }
        int versionCode = DiskCacheUtils.getAppVersion(mContext);
        //这里需要注意参数二:缓存版本号,只要不同版本号,缓存都会被清除,重新使用新的
        mDiskLruCache = DiskLruCache.create(FileSystem.SYSTEM, cacheDir, versionCode, 1, maxSize);
    }

    /**
     * 获取文件缓存
     *
     * @param url
     * @return
     */
    private Bitmap getDataFromDiskLruCache(String url) {
        Bitmap bitmap = null;
        try {
            final String key = DiskCacheUtils.getMD5String(url);
            DiskLruCache.Snapshot snapshot = mDiskLruCache.get(key);
            if (snapshot == null) return null;
            //获取资源的输出流,Source类似InputStream
            Source source = snapshot.getSource(0);
            Buffer buffer = new Buffer();
            //读取4*1024数据放入buffer中并返回读取到的数据的字节长度
            long ret = source.read(buffer, 4 * 1024);
            //判断文件是否读完
            while (ret != -1) {
                ret = source.read(buffer, 4 * 1024);
            }
            //获取到buffer的inputStream对象
            InputStream inputStream = buffer.inputStream();
            bitmap = BitmapFactory.decodeStream(inputStream);
            if (inputStream != null) {
                inputStream.close();
            }
            if (buffer != null) {
                buffer.clear();
                buffer.close();
            }
            if (source != null) {
                source.close();
            }
            if (snapshot != null) {
                snapshot.close();
            }

            return bitmap;
        } catch (IOException e) {
            e.printStackTrace();
        }


        return bitmap;
    }


}

文件帮助类:网上抄袭来的,拿来主义,呵呵。DiskCacheUtils

public class DiskCacheUtils {

    /**
     * 获取缓存路径
     * @param context
     * @param uniqueName
     * @return
     */
    public static File getDiskCacheDir(Context context, String uniqueName) {
        String cachePath;
        if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())
                || !Environment.isExternalStorageRemovable()) {

            cachePath = context.getExternalCacheDir().getPath();
        } else {
            cachePath = context.getCacheDir().getPath();
        }
        Log.e("cachePath",cachePath);
        return new File(cachePath + File.separator + uniqueName);
    }

    /**
     * 获取App版本号
     * @param context
     * @return
     */
    public static int getAppVersion(Context context) {
        try {
            PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
            return info.versionCode;
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return 1;
    }

    /**
     * 获取加密后的MD5
     * @param key
     * @return
     */
    public static String getMD5String(String key) {
        String cacheKey;
        try {
            final MessageDigest mDigest = MessageDigest.getInstance("MD5");
            mDigest.update(key.getBytes());
            cacheKey = bytesToHexString(mDigest.digest());
        } catch (NoSuchAlgorithmException e) {
            cacheKey = String.valueOf(key.hashCode());
        }
        return cacheKey;
    }

    private static String bytesToHexString(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            String hex = Integer.toHexString(0xFF & bytes[i]);
            if (hex.length() == 1) {
                sb.append('0');
            }
            sb.append(hex);
        }
        return sb.toString();
    }

}

ImageBean 实体。
{ private String url;
private Bitmap bitmap;}

RequestCreator 构建者模式,链式调用。

public class RequestCreator {
    public MemoryCacheObservable memoryCacheObservable;
    public DiskCacheObservable diskCacheObservable;


    public RequestCreator(Context context) {
        memoryCacheObservable = new MemoryCacheObservable();
        diskCacheObservable = new DiskCacheObservable(context);

    }

    public Observable<ImageBean> getImageFromMemory(String url) {
        return memoryCacheObservable.getImage(url)
                .filter(new Predicate<ImageBean>() {
                    @Override
                    public boolean test(@NonNull ImageBean imageBean) throws Exception {
                        Bitmap bitmap = imageBean.getBitmap();
                        Log.e("getImageFromMemory", "null");
                        return bitmap != null;
                    }
                });

    }

    public Observable<ImageBean> getImageFromDisk(String url) {
        return diskCacheObservable.getImage(url)
                .filter(new Predicate<ImageBean>() {
                    @Override
                    public boolean test(@NonNull ImageBean imageBean) throws Exception {
                        Bitmap bitmap = imageBean.getBitmap();
                        if (bitmap != null) {
                            return true;
                        } else {
                            diskCacheObservable.putDataToCache(imageBean);
                            ImageBean imageBean1 = diskCacheObservable.getDataFromCache(imageBean.getUrl());
                            if (imageBean1.getBitmap() != null) {
                                Log.e("diskCacheObservable.putDataToCache", "true");
                                return true;
                            }
                        }
                        return true;
                    }
                }).doOnNext(new Consumer<ImageBean>() {
                    @Override
                    public void accept(@NonNull ImageBean imageBean) throws Exception {
                        //缓存内存
                        Log.e("memoryCacheObservable.putDataToCache", "缓存到内存");
                        memoryCacheObservable.putDataToCache(imageBean);
                    }
                });

    }

}

RxImageLoader 类

public class RxImageLoader {

    static RxImageLoader singleton;
    private String mUrl;
    private 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) {
        this.mUrl = url;
        return singleton;
    }

    public void into(final ImageView imageView) {
        Observable
                .concat(
                        requestCreator.getImageFromMemory(mUrl),
                        requestCreator.getImageFromDisk(mUrl)
                        //        requestCreator.getImageFromNetwork(mUrl)
                )
                .first(new ImageBean(null, mUrl)).toObservable()
                .retryWhen(new Function<Observable<Throwable>, ObservableSource<?>>() {
                    private int retryCount;
                    @Override
                    public ObservableSource<?> apply(Observable<Throwable> throwableObservable) throws Throwable {
                        return throwableObservable
                                .flatMap((Throwable throwable) -> {
                                    if (++retryCount <= 3) {
                                        // When this Observable calls onNext, the original Observable will be retried (i.e. re-subscribed).
                                        Log.e("get error, retry count " ,retryCount+"-");
                                        return Observable.just("" + retryCount).delay(5,TimeUnit.SECONDS);
                                    }
                                    // Max retries hit. Just pass the error along.
                                    return Observable.error(throwable);
                                });
                    }
                })
                .subscribe(new Observer<ImageBean>() {
                    @Override
                    public void onSubscribe(Disposable d) {

                    }

                    @Override
                    public void onNext(ImageBean imageBean) {
                        Log.e("onNext", imageBean.getBitmap() + "--" + imageBean.getUrl());
                        if (imageBean.getBitmap() != null) {

                            imageView.setImageBitmap(imageBean.getBitmap());
                        }
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.e("eeeeeeeee", e.getMessage());
                        e.printStackTrace();
                    }

                    @Override
                    public void onComplete() {
                        Log.e("onComplete", "onComplete");
                    }
                });
//
//        Observable.concat(requestCreator.getImageFromMemory(mUrl),
//                        requestCreator.getImageFromDisk(mUrl),
//                        requestCreator.getImageFromNetwork(mUrl)
//                )
//
//                .subscribeOn(Schedulers.io())
//                .firstElement()
//                .observeOn(AndroidSchedulers.mainThread())
//                .subscribe(new Consumer<ImageBean>() {
//                    @Override
//                    public void accept(ImageBean imageBean) throws Throwable {
//                        Log.e("imageBean", imageBean.getUrl());
//                    }
//                }, new Consumer<Throwable>() {
//                    @Override
//                    public void accept(Throwable throwable) throws Throwable {
//                        Log.e("throwable", throwable.getMessage());
//                    }
//                });

    }

    public static class Builder {

        private Context mContext;

        public Builder(Context mContext) {
            this.mContext = mContext;
        }

        public RxImageLoader build() {
            return new RxImageLoader(this);
        }
    }
}

在Test2Activity中调用就简单了,一句话解决:

 RxImageLoader.with(Test2Activity.this).load(url).into(iv);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值