国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android中Rxjava實現三級緩存的兩種方式

2019-12-12 03:09:51
字體:
來源:轉載
供稿:網友

本文正如標題所說的用rxjava實現數據的三級緩存分別為內存,磁盤,網絡,剛好最近在看Android源碼設計模式解析與實戰(受里面的ImageLoader的設計啟發)。

我把代碼放到了我的hot項目中,github地址

源碼下載地址:Rxjava_jb51.rar

1.使用concat()和first()的操作符。

2.使用BehaviorSubject。

先說BehaviorSubject的實現方法,廢話不多說直接上代碼,

/** * Created by wukewei on 16/6/20. */public class BehaviorSubjectFragment extends BaseFragment {  public static BehaviorSubjectFragment newInstance() {    BehaviorSubjectFragment fragment = new BehaviorSubjectFragment();    return fragment;  }  String diskData = null;  String networkData = "從服務器獲取的數據";  BehaviorSubject<String> cache;  View mView;  @Nullable  @Override  public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {    mView = inflater.inflate(R.layout.fragment_content, container, false);    init();    return mView;  }  private void init() {    mView.findViewById(R.id.get).setOnClickListener(new View.OnClickListener() {      @Override      public void onClick(View v) {        subscriptionData(new Observer<String>() {          @Override          public void onCompleted() {          }          @Override          public void onError(Throwable e) {          }          @Override          public void onNext(String s) {            Log.d("onNext", s);          }        });      }    });    mView.findViewById(R.id.memory).setOnClickListener(new View.OnClickListener() {      @Override      public void onClick(View v) {        BehaviorSubjectFragment.this.cache = null;      }    });    mView.findViewById(R.id.memory_disk).setOnClickListener(new View.OnClickListener() {      @Override      public void onClick(View v) {        BehaviorSubjectFragment.this.cache = null;        BehaviorSubjectFragment.this.diskData = null;      }    });  }  private void loadNewWork() {    Observable<String> o = Observable.just(networkData)        .doOnNext(new Action1<String>() {          @Override          public void call(String s) {            BehaviorSubjectFragment.this.diskData = s;            Log.d("寫入磁盤", "寫入磁盤");          }        });    o.subscribe(new Action1<String>() {      @Override      public void call(String s) {        cache.onNext(s);      }    }, new Action1<Throwable>() {      @Override      public void call(Throwable throwable) {      }    });  }  private Subscription subscriptionData(@NonNull Observer<String> observer) {    if (cache == null) {      cache = BehaviorSubject.create();      Observable.create(new Observable.OnSubscribe<String>() {        @Override        public void call(Subscriber<? super String> subscriber) {          String data = diskData;          if (data == null) {            Log.d("來自網絡", "來自網絡");            loadNewWork();          } else {            Log.d("來自磁盤", "來自磁盤");            subscriber.onNext(data);          }        }      })          .subscribeOn(Schedulers.io())          .subscribe(cache);    } else {      Log.d("來自內存", "來自內存");    }    return cache.observeOn(AndroidSchedulers.mainThread()).subscribe(observer);  }}

其中最主要的是subscriptionData()這個方法,就是先判斷 cache是否存在要是存在的話就返回內存中數據,再去判斷磁盤數據是否存在,如果存在就返回,要是前面兩種都不存在的時候,再去網絡中獲取數據。還有最重要的是當你從網絡獲取數據的時候要記得保存在內存中和保存在磁盤中,在磁盤獲取數據的時候把它賦值給內存。

接下來就說說用concat()和first()的操作符來實現,這是我在看Android源碼設計模式解析與實戰,作者在第一章的時候就介紹ImageLoader的設計。

在內存中存儲的方式LruCache來實現的,磁盤存儲的方式就是序列化存儲。

1.定義一個接口:

/** * Created by wukewei on 16/6/19. */public interface ICache {  <T> Observable<T> get(String key, Class<T> cls);  <T> void put(String key, T t);}

2.內存存儲的實現

/** * Created by wukewei on 16/6/19. */public class MemoryCache implements ICache{  private LruCache<String, String> mCache;  public MemoryCache() {    final int maxMemory = (int) Runtime.getRuntime().maxMemory();    final int cacheSize = maxMemory / 8;    mCache = new LruCache<String, String>(cacheSize) {      @Override      protected int sizeOf(String key, String value) {        try {          return value.getBytes("UTF-8").length;        } catch (UnsupportedEncodingException e) {          e.printStackTrace();          return value.getBytes().length;        }      }    };  }  @Override  public <T> Observable<T> get(final String key, final Class<T> cls) {    return Observable.create(new Observable.OnSubscribe<T>() {      @Override      public void call(Subscriber<? super T> subscriber) {        String result = mCache.get(key);        if (subscriber.isUnsubscribed()) {          return;        }        if (TextUtils.isEmpty(result)) {          subscriber.onNext(null);        } else {          T t = new Gson().fromJson(result, cls);          subscriber.onNext(t);        }        subscriber.onCompleted();      }    });  }  @Override  public <T> void put(String key, T t) {    if (null != t) {      mCache.put(key, new Gson().toJson(t));    }  }  public void clearMemory(String key) {    mCache.remove(key);  }}

3.磁盤存儲的實現

/** * Created by wukewei on 16/6/19. */public class DiskCache implements ICache{  private static final String NAME = ".db";  public static long OTHER_CACHE_TIME = 10 * 60 * 1000;  public static long WIFI_CACHE_TIME = 30 * 60 * 1000;  File fileDir;  public DiskCache() {    fileDir = CacheLoader.getApplication().getCacheDir();  }  @Override  public <T> Observable<T> get(final String key, final Class<T> cls) {    return Observable.create(new Observable.OnSubscribe<T>() {      @Override      public void call(Subscriber<? super T> subscriber) {        T t = (T) getDiskData1(key + NAME);        if (subscriber.isUnsubscribed()) {          return;        }        if (t == null) {          subscriber.onNext(null);        } else {          subscriber.onNext(t);        }        subscriber.onCompleted();      }    })        .subscribeOn(Schedulers.io())        .observeOn(AndroidSchedulers.mainThread());  }  @Override  public <T> void put(final String key, final T t) {    Observable.create(new Observable.OnSubscribe<T>() {      @Override      public void call(Subscriber<? super T> subscriber) {        boolean isSuccess = isSave(key + NAME, t);        if (!subscriber.isUnsubscribed() && isSuccess) {          subscriber.onNext(t);          subscriber.onCompleted();        }      }    })        .subscribeOn(Schedulers.io())        .observeOn(AndroidSchedulers.mainThread())        .subscribe();  }  /**   * 保存數據   */  private <T> boolean isSave(String fileName, T t) {    File file = new File(fileDir, fileName);    ObjectOutputStream objectOut = null;    boolean isSuccess = false;    try {      FileOutputStream out = new FileOutputStream(file);          objectOut = new ObjectOutputStream(out);      objectOut.writeObject(t);      objectOut.flush();      isSuccess=true;    } catch (IOException e) {      Log.e("寫入緩存錯誤",e.getMessage());    } catch (Exception e) {      Log.e("寫入緩存錯誤",e.getMessage());    } finally {      closeSilently(objectOut);    }    return isSuccess;  }  /**   * 獲取保存的數據   */  private Object getDiskData1(String fileName) {    File file = new File(fileDir, fileName);    if (isCacheDataFailure(file)) {      return null;    }    if (!file.exists()) {      return null;    }    Object o = null;    ObjectInputStream read = null;    try {      read = new ObjectInputStream(new FileInputStream(file));      o = read.readObject();    } catch (StreamCorruptedException e) {      Log.e("讀取錯誤", e.getMessage());    } catch (IOException e) {      Log.e("讀取錯誤", e.getMessage());    } catch (ClassNotFoundException e) {      Log.e("錯誤", e.getMessage());    } finally {      closeSilently(read);    }    return o;  }  private void closeSilently(Closeable closeable) {    if (closeable != null) {      try {        closeable.close();      } catch (Exception ignored) {      }    }  }  /**   * 判斷緩存是否已經失效   */  private boolean isCacheDataFailure(File dataFile) {    if (!dataFile.exists()) {      return false;    }    long existTime = System.currentTimeMillis() - dataFile.lastModified();    boolean failure = false;    if (NetWorkUtil.getNetworkType(CacheLoader.getApplication()) == NetWorkUtil.NETTYPE_WIFI) {      failure = existTime > WIFI_CACHE_TIME ? true : false;    } else {      failure = existTime > OTHER_CACHE_TIME ? true : false;    }    return failure;  }  public void clearDisk(String key) {    File file = new File(fileDir, key + NAME);    if (file.exists()) file.delete();  }}

isCacheDataFailure()方式中就是判斷當前的數據是否失效,我是根據當前的網絡狀況來分wifi狀況和非wifi狀況,wifi狀態下數據過期時間比較短,其他狀態過期時間比較長。

4.CacheLoader的設計

/** * Created by wukewei on 16/6/19. */public class CacheLoader {  private static Application application;  public static Application getApplication() {    return application;  }  private ICache mMemoryCache, mDiskCache;  private CacheLoader() {    mMemoryCache = new MemoryCache();    mDiskCache = new DiskCache();  }  private static CacheLoader loader;  public static CacheLoader getInstance(Context context) {    application = (Application) context.getApplicationContext();    if (loader == null) {      synchronized (CacheLoader.class) {        if (loader == null) {          loader = new CacheLoader();        }      }    }    return loader;  }  public <T> Observable<T> asDataObservable(String key, Class<T> cls, NetworkCache<T> networkCache) {    Observable observable = Observable.concat(        memory(key, cls),        disk(key, cls),        network(key, cls, networkCache))        .first(new Func1<T, Boolean>() {          @Override          public Boolean call(T t) {            return t != null;          }        });    return observable;  }  private <T> Observable<T> memory(String key, Class<T> cls) {    return mMemoryCache.get(key, cls).doOnNext(new Action1<T>() {      @Override      public void call(T t) {        if (null != t) {          Log.d("我是來自內存","我是來自內存");        }      }    });  }  private <T> Observable<T> disk(final String key, Class<T> cls) {    return mDiskCache.get(key, cls)        .doOnNext(new Action1<T>() {          @Override          public void call(T t) {            if (null != t) {              Log.d("我是來自磁盤","我是來自磁盤");              mMemoryCache.put(key, t);            }          }        });  }  private <T> Observable<T> network(final String key, Class<T> cls      , NetworkCache<T> networkCache) {    return networkCache.get(key, cls)        .doOnNext(new Action1<T>() {          @Override          public void call(T t) {            if (null != t) {              Log.d("我是來自網絡","我是來自網絡");              mDiskCache.put(key, t);              mMemoryCache.put(key, t);            }          }        });  }  public void clearMemory(String key) {    ((MemoryCache)mMemoryCache).clearMemory(key);  }  public void clearMemoryDisk(String key) {    ((MemoryCache)mMemoryCache).clearMemory(key);    ((DiskCache)mDiskCache).clearDisk(key);  }}

5.網絡獲取的NetworkCache:

/** * Created by wukewei on 16/6/19. */public abstract class NetworkCache<T> {  public abstract Observable<T> get(String key, final Class<T> cls);}

6.接下來看怎么使用

/** * Created by wukewei on 16/5/30. */public class ItemPresenter extends BasePresenter<ItemContract.View> implements ItemContract.Presenter {  private static final String key = "new_list";  protected int pn = 1;  protected void replacePn() {    pn = 1;  }  private boolean isRefresh() {    return pn == 1;  }  private NetworkCache<ListPopular> networkCache;  public ItemPresenter(Activity activity, ItemContract.View view) {    super(activity, view);  }  @Override  public void getListData(String type) {    if (isRefresh()) mView.showLoading();    networkCache = new NetworkCache<ListPopular>() {      @Override      public Observable<ListPopular> get(String key, Class<ListPopular> cls) {        return mHotApi.getPopular(ItemPresenter.this.pn, Constants.PAGE_SIZE, type)            .compose(SchedulersCompat.applyIoSchedulers())            .compose(RxResultHelper.handleResult())            .flatMap(populars -> {              ListPopular popular = new ListPopular(populars);              return Observable.just(popular);            });      }    };    Subscription subscription = CacheLoader.getInstance(mActivity)        .asDataObservable(key + type + ItemPresenter.this.pn, ListPopular.class, networkCache)        .map(listPopular -> listPopular.data)        .subscribe(populars -> {          mView.showContent();          if (isRefresh()) {            if (populars.size() == 0) mView.showNotdata();            mView.addRefreshData(populars);          } else {            mView.addLoadMoreData(populars);          }        }, throwable -> {          if (isRefresh())          mView.showError(ErrorHanding.handleError(throwable));          handleError(throwable);        });    addSubscrebe(subscription);  }}

一定要給個key,我是根據key來獲取數據的,還要就是給個類型。

但是這個我設計的這個緩存還是不是很理想,接來下想要實現的就是在傳入的時候類的class都不用給明,要是有好的實現的方式,歡迎告訴我。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 靖江市| 商河县| 育儿| 策勒县| 蒲城县| 江西省| 雷山县| 扎兰屯市| 忻州市| 龙岩市| 吴桥县| 玉树县| 寿光市| 夏河县| 凌云县| 禄丰县| 潢川县| 宿迁市| 上高县| 富阳市| 肇源县| 江山市| 固始县| 彭州市| 酒泉市| 富裕县| 金寨县| 元谋县| 贺兰县| 藁城市| 司法| 迭部县| 桦南县| 阿鲁科尔沁旗| 兴国县| 西青区| 尖扎县| 交口县| 平谷区| 迁西县| 柳河县|