转载

从零开始的Android新项目5 - Repository层 - Retrofit & Realm

未完

如期而至的Repository篇,内部实现则由Realm、Retrofit,以及内存级LruCache组成。Repository,顾名思义,即仓库,向上层屏蔽了数据来源和内部实现细节,不需要了解货物来源,只需要拿走就行了。

Why Repository

首先,为什么我们需要Repository层呢?一言以蔽之,屏蔽细节。

上层(activity/fragment/presenter)不需要知道数据的细节,来自于网络、数据库,亦或是内存等等。举些例子:

  • 当现在是无网状态,我希望列表能直接显示上一次的数据,而不会是空页面。
  • 除非好友的用户数据过期(比如超过一天),否则希望直接使用本地缓存中的,但如果缓存没有,或者过期,则需要拉取并更新。
  • 点赞后,即便请求还没发送或者没有收到response,仍然希望显示点赞后的状态。
    等等。

如果这些需求,我们都要实现在View或者Presenter中,就会导致充斥大量数据逻辑,目的不单一,难以维护。而Repository层就是来封装这些逻辑的。

Retrofit

OkHttpClient

自底向上地,我们需要一个OkHttpClient来设置给Retrofit,这里作为实例,放出一段包含大部分你可能会用到的功能的Client创建代码,可以根据需要进行调整。

private OkHttpClient getClient() {
// log用拦截器
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();

// 开发模式记录整个body,否则只记录基本信息如返回200,http协议版本等
if (IS_DEV) {
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
} else {
logging.setLevel(HttpLoggingInterceptor.Level.BASIC);
}

// 如果使用到HTTPS,我们需要创建SSLSocketFactory,并设置到client
SSLSocketFactory sslSocketFactory = null;

try {
// 这里直接创建一个不做证书串验证的TrustManager
final TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {

}

@Override
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {

}

@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[]{};
}
}
};

// Install the all-trusting trust manager
final SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
// Create an ssl socket factory with our all-trusting manager
sslSocketFactory = sslContext.getSocketFactory();
} catch (Exception e) {
Logger.e(TAG, e.getMessage());
}

return new OkHttpClient.Builder()
// HeadInterceptor实现了Interceptor,用来往Request Header添加一些业务相关数据,如APP版本,token信息
.addInterceptor(new HeadInterceptor())
.addInterceptor(logging)
// 连接超时时间设置
.connectTimeout(10, TimeUnit.SECONDS)
// 读取超时时间设置
.readTimeout(10, TimeUnit.SECONDS)
.sslSocketFactory(sslSocketFactory)
// 信任所有主机名
.hostnameVerifier((hostname, session) -> true)
// 这里我们使用host name作为cookie保存的key
.cookieJar(new CookieJar() {
private final HashMap<HttpUrl, List<Cookie>> cookieStore = new HashMap<>();

@Override
public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
cookieStore.put(HttpUrl.parse(url.host()), cookies);
}

@Override
public List<Cookie> loadForRequest(HttpUrl url) {
List<Cookie> cookies = cookieStore.get(HttpUrl.parse(url.host()));
return cookies != null ? cookies : new ArrayList<>();
}
})
.build();
}

RxJava异步请求

public static MrService getInstance() {
if (mInstance == null) {
synchronized (MrService.class) {
if (mInstance == null) {
mInstance = new MrService();
}
}
}
return mInstance;
}

private MrService() {
this(true);
}

private MrService(boolean useRxJava) {
Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl(IS_DEV ? API_DEV_URL : API_PRODUCT_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(getClient());
if (useRxJava) {
builder.addCallAdapterFactory(RxJavaCallAdapterFactory.create());
}
mRetrofit = builder.build();
}

对应API请求类如

public interface SystemApi {
...
@FormUrlEncoded
@POST("user/feedback")
Observable<MrResponse> feedback(@Field("content") String content,
@Field("model_name") String modelName,
@Field("system_version") String systemVersion,
@Field("img_keys") List<String> imageKeyList);

}

同步请求

有时候我们需要做同步请求,比如提供结果给一些第三方库,它们可能需要直接返回对应数据(像我最近碰到的融云….)

这时候就需要创建一个同步的retrofit客户端,其实就是不要去使用RxJava的adapter啦。

public static MrService getSynchronousInstance() {
if (mSyncInstance == null) {
synchronized (MrService.class) {
if (mSyncInstance == null) {
mSyncInstance = new MrService(false);
}
}
}
return mSyncInstance;
}

对应地,我们需要定义请求类,这里我们需要使用Call<>去包一下最终解析对象的类。

public interface RongCloudApi {
@FormUrlEncoded
@POST("im/getGroupInfo")
Call<MrResponse> getGroupInfoSynchronous(@Field("group_id") String groupId);

@FormUrlEncoded
@POST("user/nameCardLite")
Call<MrResponse> getNameCardLiteSynchronous(@Field("uid") String userId);
}

数据格式解析

Realm

LruCache

Repository层组装

统一异常处理

原文  http://blog.zhaiyifan.cn/2016/04/30/android-new-project-from-0-p5/
正文到此结束
Loading...