喜欢该项目可以给作者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使用
- 依赖添加
//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();
}
}