RxJava+Retrofit+ViewModel+LiveDa
2018-09-19 本文已影响93人
大虾啊啊啊
前言
我们可以在github上看到当今比较流行的架构方式有:todo-mvp,todo-mvp-clean,todo-mvvm,todo-mvp-rxjava等等(可以参考:https://github.com/googlesamples/android-architecture),而当今比较流行的技术莫过于:
1.响应式编程+异步任务
RxJava,RxAndroid系列
2.网络框架
Retrofit,Okhttp
3.Android Jetpack系列
LiveData ,ViewModel,Room等 (可以在Android官网看到https://developer.android.google.cn/jetpack/)
因此我做了一个demo对RxJava+Retrofit+ViewModel+LiveData的封装;
源码传送门:https://github.com/daxiaaaaaaaaaaaaa/SmartArchitecture
1.RxJava+Retrofit网络框架的封装
package com.architecturedemo.http;
import com.architecturedemo.base.BaseDto;
import com.architecturedemo.dto.LoginDto;
import com.architecturedemo.utils.HttpUtil;
import com.mujin.keji.architecturedemo.vo.LoginVo;
import io.reactivex.Flowable;
public class Api {
/**
* 登录接口
*
* @param vo
* @return
*/
public static Flowable<BaseDto<LoginDto>> login(LoginVo vo) {
return RequetRetrofit.getInstance().login(HttpUtil.convertVo2Params(vo));
}
}
package com.architecturedemo.http;
import com.architecturedemo.base.BaseDto;
import com.architecturedemo.dto.LoginDto;
import java.util.Map;
import io.reactivex.Flowable;
import retrofit2.http.FieldMap;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.POST;
/**
* api接口
*
* @author weishixiong
* @Time 2018-04-2
*/
public interface ApiService {
/**
* 登录
* post
* 表单提交
*
* @param map
* @return
*/
@FormUrlEncoded
@POST("login")
Flowable<BaseDto<LoginDto>> login(@FieldMap Map<String, String> map);
}
package com.architecturedemo.http;
import android.util.Log;
import com.architecturedemo.CcsApplication;
import com.architecturedemo.Constant;
import com.architecturedemo.interceptor.AddCookiesInterceptor;
import com.architecturedemo.interceptor.ReceivedCookiesInterceptor;
import com.facebook.stetho.okhttp3.StethoInterceptor;
import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import com.mujin.keji.architecturedemo.ssl.SafeHostnameVerifier;
import com.mujin.keji.architecturedemo.ssl.SafeTrustManager;
import java.util.concurrent.TimeUnit;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
/**
* 普通的网络请求用到的Retrofit
*/
public class RequetRetrofit {
private static final String TAG = "RequetRetrofit";
/**
* 创建okhttp相关对象
*/
private static OkHttpClient okHttpClient;
/**
* 创建Retrofit相关对象
*/
private static Retrofit retrofit;
public static ApiService getInstance() {
if (okHttpClient == null) {
/**
* 创建okhttp相关对象
*/
okHttpClient = new OkHttpClient.Builder()
.addInterceptor(new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
@Override
public void log(String message) { //访问网络请求,和服务端响应请求时。将数据拦截并输出
Log.e(TAG, "log: " + message);
}
}).setLevel(HttpLoggingInterceptor.Level.BODY)) //Log等级
.connectTimeout(Constant.Server.TIME_OUT, TimeUnit.SECONDS) //超时时间
.readTimeout(Constant.Server.TIME_OUT, TimeUnit.SECONDS)
.writeTimeout(Constant.Server.TIME_OUT, TimeUnit.SECONDS)
.addNetworkInterceptor(new StethoInterceptor())
.addInterceptor(new AddCookiesInterceptor()) //这部分
.addInterceptor(new ReceivedCookiesInterceptor()) //这部分
.hostnameVerifier(new SafeHostnameVerifier())
.sslSocketFactory(CcsApplication.getSslSocket(),new SafeTrustManager())
//
.build();
}
if (retrofit == null) {
retrofit = new Retrofit.Builder()
.baseUrl(Constant.Server.ROOT_URL) //BaseUrl
.client(okHttpClient) //请求的网络框架
.addConverterFactory(GsonConverterFactory.create()) //解析数据格式
.addCallAdapterFactory(RxJava2CallAdapterFactory.create()) // 使用RxJava作为回调适配器
.build();
}
return retrofit.create(ApiService.class);
}
}
2.自定义拦截器 实现登录校验,判断sessionId是否过期
package com.architecturedemo.interceptor;
import com.alibaba.fastjson.JSONObject;
import com.architecturedemo.Constant;
import com.architecturedemo.utils.SPUtil;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import okhttp3.Interceptor;
import okhttp3.Response;
/**
* 首次请求的处理
* @author : weishixiong
* @create : 18/05/03
*/
public class ReceivedCookiesInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Response originalResponse = chain.proceed(chain.request());
if (!originalResponse.headers("Set-Cookie").isEmpty()) {
List<String> cookies = new ArrayList<>();
for (String header : originalResponse.headers("Set-Cookie")) {
cookies.add(header);
}
String cookieStr = JSONObject.toJSONString(cookies);
SPUtil.putData(Constant.SP.SP, Constant.SP.SESSION_ID, cookieStr);
}
return originalResponse;
}
}
package com.architecturedemo.interceptor;
import android.util.Log;
import com.alibaba.fastjson.JSONObject;
import com.architecturedemo.Constant;
import com.architecturedemo.utils.SPUtil;
import java.io.IOException;
import java.util.List;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
/**
* 非首次请求的处理
* @author : weishixiong
* @create : 18/05/03
*/
public class AddCookiesInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request.Builder builder = chain.request().newBuilder();
String cookieStr = SPUtil.getData(Constant.SP.SP, Constant.SP.SESSION_ID, String.class, null);
List<String> cookies = JSONObject.parseArray(cookieStr, String.class);
if (cookies != null) {
for (String cookie : cookies) {
builder.addHeader("Cookie", cookie);
Log.v("OkHttp", "Adding Header: " + cookie); // This is done so I know which headers are being added; this interceptor is used after the normal logging of OkHttp
}
}
return chain.proceed(builder.build());
}
}
3.RxJava Subscriber的封装
package com.architecturedemo.base;
import android.arch.lifecycle.MutableLiveData;
import android.os.Build;
import android.support.annotation.RequiresApi;
import com.architecturedemo.Constant;
import com.architecturedemo.exception.ApiException;
import com.architecturedemo.exception.ExceptionEngine;
import com.architecturedemo.exception.ServerException;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;
/**
* 自定义请服务器被观察者
*
* @author weishixiong
* @Time 2018-04-12
*/
public class BaseHttpSubscriber<T> implements Subscriber<BaseDto<T>> {
//异常类
private ApiException ex;
public BaseHttpSubscriber() {
data = new MutableLiveData();
}
private MutableLiveData<BaseDto<T>> data;
public MutableLiveData<BaseDto<T>> get() {
return data;
}
public void set(BaseDto<T> t) {
this.data.setValue(t);
}
public void onFinish(BaseDto<T> t) {
set(t);
}
@Override
public void onSubscribe(Subscription s) {
// 观察者接收事件 = 1个
s.request(1);
}
@RequiresApi(api = Build.VERSION_CODES.HONEYCOMB)
@Override
public void onNext(BaseDto<T> t) {
if (t.getCode() == Constant.Server.SUCCESS_CODE) {
onFinish(t);
} else {
ex = ExceptionEngine.handleException(new ServerException(t.getCode(), t.getMsg()));
getErrorDto(ex);
}
}
@RequiresApi(api = Build.VERSION_CODES.HONEYCOMB)
@Override
public void onError(Throwable t) {
ex = ExceptionEngine.handleException(t);
getErrorDto(ex);
}
/**
* 初始化错误的dto
*
* @param ex
*/
private void getErrorDto(ApiException ex) {
BaseDto dto = new BaseDto();
dto.setCode(ex.getCode());
dto.setMsg(ex.getMsg());
onFinish((BaseDto<T>) dto);
}
@Override
public void onComplete() {
}
}
4.ViewModel+LiveData对数据的封装
package com.architecturedemo.viewmodel;
import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.ViewModel;
import com.architecturedemo.Constant;
import com.architecturedemo.base.BaseDto;
import com.architecturedemo.dto.LoginDto;
import com.architecturedemo.repository.ILoginRepository;
import com.architecturedemo.repository.LoginRepository;
import com.architecturedemo.utils.SPUtil;
import com.mujin.keji.architecturedemo.vo.LoginVo;
/**
* 登录viewmodel
*
* @author weishixiong
* @Time 2018-04-2
*/
public class LoginViewModel extends ViewModel {
private LiveData<BaseDto<LoginDto>> loginDtoLiveData;
private ILoginRepository loginRepository;
public LiveData<BaseDto<LoginDto>> getLoginDtoLiveData() {
return loginDtoLiveData;
}
/**
* 登录
* @param username
* @param password
*/
public void login(String username,String password){
SPUtil.clearData(Constant.SP.SP);
loginRepository = new LoginRepository();
LoginVo vo = new LoginVo();
vo.setPassword(password);
vo.setUsername(username);
this.loginDtoLiveData = loginRepository.login(vo);
}
}
因为代码比较多就不一一贴出来了,有兴趣的同学可以下载demo看看