RxCacheDemo 源码泛读及Okhttp缓存使用

地址

喜欢该项目可以给作者start

Dagger2的使用
  • AppModule类,对外提供上下文。
@Module
public class AppModule {
    private Context mContext;
    public AppModule(Context context) {
        mContext = context;
    }
    @Provides
    @Singleton
    Context provideApplicationContext() {//对AppComponent注射器提供context上下文
        return mContext;
    }
}
  • AppComponent类,注射器。
@Singleton
@Component(modules = {AppModule.class})
public interface AppComponent {
    void inject(App app);
    Context getContext();//
}
  • AppComponent注射器的使用。
public class App extends Application {
    public static AppComponent appComponent;
    @Override
    public void onCreate() {
        super.onCreate();
        setupGraph();
    }
    private void setupGraph() {
        appComponent = DaggerAppComponent.builder().appModule(new AppModule(this)).build();//在这个App类中,如果某个变量被标记了Inject,并且刚刚好该对象的创建需要context,那么创建该变量对象的时候需要使用的context就是AppComponent注射器所提供的Context对象.
        appComponent.inject(this);
    }
}
  • MainModule类,对外提供view与retrofit对象
@Module
public class MainModule {
    private static final String GITHUB_BASE_URL = "https://api.github.com/";
    private MainContract.View mView;
    public MainModule(MainContract.View view) {
        mView = view;//创建MainModule对象的时候需要传入view对象
    }
    @Provides
    @ActivityScope
    MainContract.View provideMainView() {
        return mView;//对Component注射器提供mView对象
    }
    @Provides
    @ActivityScope
    Retrofit provideRetrofit() {
        return new Retrofit.Builder()//对Component注射器提供Retrofit对象
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .baseUrl(GITHUB_BASE_URL)
                .build();
    }
}
  • MainComponent类,注射器,将MainModule类中对外提供的对象与AppComponent类中对外提供的对象都注入到MainActivity类中。
@ActivityScope
@Component(modules = {MainModule.class}, dependencies = {AppComponent.class})
public interface MainComponent {
    void inject(MainActivity mainActivity);
}
  • MainActivity中使用Dagger2
 @Override
 public void setupComponent(AppComponent appComponent) {
     MainComponent component = DaggerMainComponent.builder()
             .appComponent(appComponent)//appComponent 对象是从APP类中得到的
             .mainModule(new MainModule(this))
             .build();
     component.inject(this);
 }
  • MainPresenter对象的创建,在MainActivity中被Inject标记的变量创建时,会从注射器中寻找构造所需要的参数。
 /**
  *
  * @param mView 由MainModule 中提供
  * @param githubInteractor 该对象构造被Inject标记,需要构造参数,这些构造函数最终由MainComponent注射器提供,在MainActivity界面注入进MainPresenter中
  * @param mySchedulerProvider 该对象构造被Inject标记 构造参数为没有
  * @param systemWrapper 该对象构造被Inject标记 构造参数为没有
  */
 @Inject
 public MainPresenter(MainContract.View mView, GithubInteractor githubInteractor, MySchedulerProvider mySchedulerProvider, SystemWrapper systemWrapper) {
     this.mView = mView;
     this.githubInteractor = githubInteractor;
     this.mySchedulerProvider = mySchedulerProvider;
     this.systemWrapper = systemWrapper;
 }
RxCache使用

地址

参考文章1

参考文章2

  • 依赖添加
//RxCache在内部使用 Jolyglot 对数据进行序列化和反序列化,需要选择对应的依赖项
dependencies {
    compile "com.github.VictorAlbertos.RxCache:runtime:1.8.1-2.x"
    // To use Gson 
    compile 'com.github.VictorAlbertos.Jolyglot:gson:0.0.3'
    
    // To use Jackson
    compile 'com.github.VictorAlbertos.Jolyglot:jackson:0.0.3'
    
    // To use Moshi
    compile 'com.github.VictorAlbertos.Jolyglot:moshi:0.0.3'
}

  • 需要缓存的Retrofit API接口必须创建一个对应的缓存API方法
//Retrofit 对应的API
public interface GithubApi {
    @GET("search/repositories")
    Single<GithubResponse> searchGithub(@Query("q") String query);
}
//RxCache 缓存对应的API
public interface CacheProviders {
    @LifeCache(duration = 5, timeUnit = TimeUnit.MINUTES)
    Single<GithubResponse> searchGithub(Single<GithubResponse> githubResponseSinglervable, DynamicKey query, EvictDynamicKey update);
}
  • 创建缓存API代理请求接口
@ActivityScope
public class GithubInteractor {
    private GithubApi githubApi;
    private CacheProviders cacheProviders;
    private MySchedulerProvider mySchedulerProvider;
	//缓存API被Inject标记,他可以为其他对象的构造提供参数,但前提是自己所需的构造参数也能够有人提供。
    @Inject
    public GithubInteractor(Context context, Retrofit retrofit, MySchedulerProvider mySchedulerProvider) {
        this.mySchedulerProvider = mySchedulerProvider;
        //Retrofit API
        githubApi = retrofit.create(GithubApi.class);
        //缓存提供,该对象应该设置为单例
        cacheProviders = new RxCache.Builder()
                .setMaxMBPersistenceCache(5)//最大缓存5M
                .persistence(context.getFilesDir(), new GsonSpeaker())//缓存地方
                .using(CacheProviders.class);
    }
	
    public Single<GithubResponse> searchGithub(String query, boolean update) {
        //最终的返回值也是一个Observerble对象
        return cacheProviders.searchGithub(githubApi.searchGithub(query), new DynamicKey(query), new EvictDynamicKey(update))
                .observeOn(mySchedulerProvider.io())
                .subscribeOn(mySchedulerProvider.io());
    }
}
  • 剩下的使用方式和Retrofit一致
githubInteractor.searchGithub(query, update)
        .observeOn(mySchedulerProvider.ui())
        .subscribe(githubResponse -> {
                    mView.displayData(githubResponse, systemWrapper.currentTimeMillis() - startTime);
                    mView.displayGithubText(true);
                },
                error -> {
                    error.printStackTrace();
                    mView.displayError(true);
                });
  • RxCache中的参数

    • DynamicKey 缓存标识符,构造方法。标记dynamicKey所映射的数据。
    public DynamicKey(Object dynamicKey) {
      this.dynamicKey = dynamicKey;
    }
    
    • DynamicKeyGroup 缓存标识符,构造方法。标记dynamicKey和group共同决定所映射的数据。如果DynamicKey与DynamicKeyGroup两个参数都传入RxCache API中的时候,缓存数据的唯一标识符会先取DynamicKey,再取DynamicKeyGroup中的group,二者结合起来作为缓存数据的唯一标识符。当使用RxCache API的时候,传入这两个参数会返回所对应的缓存数据。
    public DynamicKeyGroup(Object dynamicKey, Object group) {
      this.dynamicKey = dynamicKey;
      this.group = group;
    }
    
    • EvictDynamicKeyGroup :删除动态组缓存,会先通过dynamicKey标识符下的group缓存数据。
    • EvictDynamicKey :删除缓存,会删除dynamicKey标识符下的缓存,
    • EvictProvider :删除缓存提供者,会删除当前接口下的所有缓存。如果什么都不传,默认是不会清理该接口下的任何缓存的。
  • RxCache注解

    • @LifeCache:用来定义缓存时间
    • @EncryptKey:使用在接口上,用来给缓存数据加密
    • @Encrypt:作用在方法上,同样是用来给缓存数据加密。
    • @Expirable:当缓存空间满了以后,RxCache会清楚数据,被次注解标注的接口下的缓存数据将不会被清除。
Okhttp缓存使用

参考文章

项目地址

如果服务器响应的数据中包含Cache-control响应头,在无论网络链接是否正常的情况下请求接口数据,只要是在缓存有效期即Cache-Control:max-age=60这个范围内,会从缓存中取数据,超过有效期会重新请求接口获取数据。

  • 拦截器:当服务器的响应数据中不包含Cache-control响应头,则需要手动设置拦截器。
  • addInterceptor与addNetworkInterceptor都是增加OkHttp的网络请求拦截器,但是其中是有一定区别的,前者是添加在与服务器连接之前和之后,后者是添加在与服务器建立连接和发起请求的之间。
//构造拦截器
public class NetCacheInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        Response originResponse = chain.proceed(request);

        if (!TextUtils.isEmpty(request.header("Cache-Control"))) {
            //设置响应的缓存时间,即设置Cache-Control头,并移除pragma消息头,因为pragma也是控制缓存的一个消息头属性

//    must-revalidate,一旦缓存过期,必须向服务器重新请求,不得使用过期内容
//    no-cache,不使用缓存
//    no-store,不缓存请求的响应
//    no-transform,不得对响应进行转换或转变
//    public,任何响应都可以被缓存,即使响应默认是不可缓存或仅私有缓存可存的
//    private,表明响应只能被单个用户缓存,不能作为共享缓存(即代理服务器不能缓存它)
//    proxy-revalidate,与must-revalidate类似,但它仅适用于共享缓存(例如代理),并被私有缓存忽略。
//    max-age,缓存的有效时间
//    s-maxage,指定响应在公共缓存中的最大存活时间,它覆盖max-age和expires字段。
            originResponse = originResponse.newBuilder()
                    .removeHeader("pragma")
                    .header("Cache-Control", "max-age=60")
                    .build();
        }

        return originResponse;
    }
}
//使用拦截器
private OkHttpManager() {
    // 缓存目录
    File file = new File(Environment.getExternalStorageDirectory(), "a_cache");
    // 缓存大小
    int cacheSize = 10 * 1024 * 1024;
    client = new OkHttpClient.Builder()
            .cache(new Cache(file, cacheSize))
            .addNetworkInterceptor(new NetCacheInterceptor())//使用拦截器
            .connectTimeout(10, TimeUnit.SECONDS)
            .writeTimeout(10, TimeUnit.SECONDS)
            .readTimeout(10, TimeUnit.SECONDS)
            .build();
}

  • 使用拦截器添加缓存时间会导致所有接口都会被强制缓存,另外一种方式是对特定的接口设置缓存机制。
    public void asyncGet(Callback callback) {
        CacheControl cacheControl = new CacheControl.Builder()
//        noCache(),不使用缓存,使用网络请求
//        noStore(),不使用缓存也不存储缓存数据
//        maxAge(),缓存的有效时间,超过该时间会重新请求数据
//        maxStale(),超过缓存有效时间后,可继续使用旧缓存的时间,之后需要重新请求数据
//        minFresh(),增加额外的缓存的有效时间,之后需要重新请求数据
//        onlyIfCached(),使用缓存,不使用网络请求
//        noTransform(),不接受经过转码的响应
//        immutable(),缓存有效时间内,响应不会变化,避免服务器处理304响应
                .maxStale(10, TimeUnit.SECONDS)
                .maxAge(10, TimeUnit.SECONDS)
                .build();
        Request request = new Request.Builder()
//                .url("http://www.wanandroid.com/banner/json")
                .url("http://publicobject.com/helloworld.txt")
                .cacheControl(cacheControl)
                .build();
        client.newCall(request).enqueue(callback);
    }
RxLifecycle使用

参考文章

  • 依赖
// RxLifecycle基础库
compile 'com.trello.rxlifecycle2:rxlifecycle:2.1.0'

// Android使用的库,里面使用了Android的生命周期方法
// 内部引用了基础库,如果使用此库则无需再引用基础库
compile 'com.trello.rxlifecycle2:rxlifecycle-android:2.1.0'

// Android组件库,里面定义了例如RxAppCompatActivity、RxFragment之类的Android组件
// 内部引用了基础库和Android库,如果使用此库则无需再重复引用
compile 'com.trello.rxlifecycle2:rxlifecycle-components:2.1.0'

// Android使用的库,继承NaviActivity使用
compile 'com.trello.rxlifecycle2:rxlifecycle-navi:2.1.0'

// Android使用的库,继承LifecycleActivity使用
// 需要引入Google的仓库支持,用法和rxlifecycle-navi类似
compile 'com.trello.rxlifecycle2:rxlifecycle-android-lifecycle:2.1.0'

// Google的仓库支持
allprojects {
    repositories {
        jcenter()
        maven { url 'https://dl.google.com/dl/android/maven2/' }
    }
}

// 支持Kotlin语法的RxLifecycle基础库
compile 'com.trello.rxlifecycle2:rxlifecycle-kotlin:2.1.0'

// 支持Kotlin语法的Android库
compile 'com.trello.rxlifecycle2:rxlifecycle-android-lifecycle-kotlin:2.1.0'
  • rxlifecycle-components,使用compose(this.bindToLifecycle())方法绑定Activity生命周期,在onStart方法中绑定,在onStop方法被调用猴就会解除绑定。
public class RxLifecycleComponentsActivity extends RxAppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_rxlifecycle_components);
    }

    @Override
    protected void onStart() {
        super.onStart();
        Observable.interval(1, TimeUnit.SECONDS)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .compose(this.<Long>bindToLifecycle())
                .subscribe();
    }
}
  • 使用compose(this.bindUntilEvent(ActivityEvent.DESTROY))方法指定在onDestroy方法被调用时取消订阅。
public class RxLifecycleComponentsActivity extends RxAppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_rxlifecycle_components);
        ButterKnife.bind(this);

        initData();
    }

    private void initData() {
        Observable.interval(1, TimeUnit.SECONDS)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .compose(this.<Long>bindUntilEvent(ActivityEvent.DESTROY))
                .subscribe();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值