Android Mvp+Rxjava+Retrofit實戰
目錄結構
build.gradle
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:24.0.0'
compile 'com.orhanobut:logger:1.8'
compile 'io.reactivex:rxjava:1.1.7'
compile 'io.reactivex:rxandroid:1.2.1'
compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.google.code.gson:gson:2.7'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
}
Rxjava+Retrofit統一Http的封裝
HttpService
Retrofit的配置
public interface HttpService {
/**
* 測量多點之間的直線距離
*
* @param waypoints 需要測距的點的經緯度坐标;需傳入兩個或更多的點。兩個點之間用 “; ”進行分割開,單個點的經緯度用“,”分隔開;例如: waypoints=118
* .77147503233,32.054128923368;116.3521416286, 39.965780080447;116
* .28215586757,39.965780080447
* @param ak
* @param output
* @return
*/
@FormUrlEncoded
@POST("distance?")
Observable<BaseHttpResult<List<String>>> getDistance(@Field("waypoints") String waypoints,
@Field("ak") String ak,
@Field("output") String output);
}
HttpUtil
Retrofit和Rxjava進行結合 封裝網絡請求類
public class HttpUtil {
/**
* 逾時時間
*/
private static final int DEFAULT_TIMEOUT = 10;
/**
* retrofit
*/
private Retrofit retrofit;
/**
* 接口請求
*/
private HttpService httpService;
public HttpService getHttpService() {
return httpService;
}
private HttpUtil() {
//建立一個OkHttpClient并設定逾時時間
OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();
httpClientBuilder.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
//添加疊代器
httpClientBuilder.addInterceptor(new LoggerInterceptor());
retrofit = new Retrofit.Builder()
.client(httpClientBuilder.build())
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.baseUrl(StaticCode.BASE_URL)
.build();
httpService = retrofit.create(HttpService.class);
}
//在通路HttpUtil時建立單例
private static class SingletonHolder {
private static final HttpUtil INSTANCE = new HttpUtil();
}
//擷取單例
public static HttpUtil getInstance() {
return SingletonHolder.INSTANCE;
}
/**
* 組裝Observable
*
* @param observable
*/
public Observable packageObservable(Observable observable) {
return observable.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
/**
* 擷取網絡資料不轉化
*
* @param observable
*/
public Subscription sendHttp(Observable observable, HttpSubscriber listener) {
return packageObservable(observable)
.subscribe(listener);
}
/**
* 擷取網絡資料轉化
*
* @param observable
*/
public <T> Subscription sendHttpWithMap(Observable observable, HttpSubscriber<T>
listener) {
return observable.compose(this.<T>applySchedulers())
.subscribe(listener);
}
/**
* Observable 轉化
*
* @param <T>
* @return
*/
<T> Observable.Transformer<BaseHttpResult<T>, T> applySchedulers() {
return new Observable.Transformer<BaseHttpResult<T>, T>() {
@Override
public Observable<T> call(Observable<BaseHttpResult<T>> baseHttpResultObservable) {
return baseHttpResultObservable.map(new HttpFunc<T>())
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
};
}
/**
* 用來統一處理Http請求到的資料,并将資料解析成對應的Model傳回
*
* @param <T> Subscriber真正需要的資料類型
*/
private class HttpFunc<T> implements Func1<BaseHttpResult<T>, T> {
@Override
public T call(BaseHttpResult<T> baseHttpResult) {
//擷取資料失敗則抛出異常 會進入到subscriber的onError中
if (!baseHttpResult.getStatus().equals(StaticCode.HTTP_RESPONSE_SUCCESS))
throw new RuntimeException(baseHttpResult.getStatus());
return baseHttpResult.getResults();
}
}
}
LoggerInterceptor
日志列印和請求頭的增加
public class LoggerInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request().newBuilder().addHeader("version", "1.0")
.addHeader("clientSort", "android").addHeader("Charset", "UTF-8")
.build();
printRequestLog(originalRequest);
Response response = null;
try {
//發送網絡請求
response = chain.proceed(originalRequest);
printResult(response);
} catch (SocketTimeoutException e) {
//此處不抛異常 連接配接逾時會crash 沒有找到其他好的方法
e.printStackTrace();
}
return response;
}
/**
* 列印請求日志
*
* @param originalRequest
* @return
* @throws IOException
*/
private void printRequestLog(Request originalRequest) throws IOException {
FormBody.Builder formBuilder = new FormBody.Builder();
String msg = originalRequest.url() + "\n";
RequestBody oidBody = originalRequest.body();
if (oidBody instanceof FormBody) {
FormBody formBody = (FormBody) oidBody;
for (int i = 0; i < formBody.size(); i++) {
String name = URLDecoder.decode(formBody.encodedName(i), "utf-8");
String value = URLDecoder.decode(formBody.encodedValue(i), "utf-8");
if (!TextUtils.isEmpty(value)) {
formBuilder.add(name, value);
msg += name + " = " + value + "\n";
}
}
}
Logger.i(msg);
}
/**
* 列印傳回日志
*
* @param response
* @throws IOException
*/
private void printResult(Response response) throws IOException {
ResponseBody responseBody = response.body();
BufferedSource source = responseBody.source();
source.request(Long.MAX_VALUE); // Buffer the entire body.
Buffer buffer = source.buffer();
Charset UTF8 = Charset.forName("UTF-8");
MediaType contentType = responseBody.contentType();
if (contentType != null) {
UTF8 = contentType.charset(UTF8);
}
String a = buffer.clone().readString(UTF8);
Logger.i(a);
}
}
BaseHttpResult
public class BaseHttpResult<T> {
public String status;
private T results;
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public T getResults() {
return results;
}
public void setResults(T results) {
this.results = results;
}
}
HttpSubscriber
Rxjava的回調
public abstract class HttpSubscriber<T> extends Subscriber<T> {
/**
* 請求标示
*/
private int tag;
public HttpSubscriber(int tag) {
this.tag = tag;
}
@Override
public void onCompleted() {
_complete();
}
@Override
public void onError(Throwable e) {
_complete();
onError(e.getMessage(), tag);
}
@Override
public void onNext(T t) {
onSuccess(t, tag);
}
public abstract void onSuccess(T t, int tag);
public abstract void onError(String msg, int tag);
public abstract void _complete();
}
Mvp的加入
MvpView
public interface MvpView {
void showLoadingDialog();
void dismissLoadingDialog();
}
IBasePresenter
public interface IBasePresenter<V extends MvpView> {
void subscribe();
void unsubscribe();
}
BasePresenter
對Presenter公共部分進行初始化
public abstract class BasePresenter
使用示例
MainActivity
Activity中實作View
public class MainActivity extends AppCompatActivity implements MainContract.IMainView {
private MainPre mainPre;
private android.widget.TextView getDistance;
private android.widget.TextView firstToSecondDistance;
private android.widget.TextView secondToThreeDistance;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.secondToThreeDistance = (TextView) findViewById(R.id.second_to_three_distance);
this.firstToSecondDistance = (TextView) findViewById(R.id.first_to_second_distance);
this.getDistance = (TextView) findViewById(R.id.get_distance);
mainPre = new MainPre(this);
getDistance.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mainPre.subscribe();
}
});
}
@Override
public void setFirstPointToSecondPointDistance(String distance) {
firstToSecondDistance.setText(distance);
}
@Override
public void setSecondPointToThreePointDistance(String distance) {
secondToThreeDistance.setText(distance);
}
@Override
public void showLoadingDialog() {
//這邊可以做Dialog的顯示
Logger.e("請求開始");
}
@Override
public void dismissLoadingDialog() {
//這邊可以做Dialog的隐藏
Logger.e("請求結束");
}
}
MainContract
public class MainContract {
/**
* Created by huangweizhou on 16/8/10.
*/
public interface IMainView extends MvpView {
/**
* 第一個點和第二個點之間的距離
*
* @param distance
*/
void setFirstPointToSecondPointDistance(String distance);
/**
* 第二個點和第三個點之間的距離
*
* @param distance
*/
void setSecondPointToThreePointDistance(String distance);
}
}
MainPre
presenter中綁定對應的View和解析的類型
public class MainPre extends BasePresenter<MainContract.IMainView, List<String>> {
public MainPre(MainContract.IMainView view) {
super(view);
}
@Override
public void onSuccess(List<String> strings, int tag) {
baseView.setFirstPointToSecondPointDistance(strings.get(0));
baseView.setSecondPointToThreePointDistance(strings.get(1));
}
@Override
public void onError(String msg, int tag) {
Logger.e(msg);
}
@Override
public void subscribe() {
sendHttpWithMap(httpService.getDistance("118.77147503233,32.054128923368;\n" +
" 116.3521416286,39.965780080447;116.28215586757,39\n" +
" .965780080447", "6cyEpstfAo1HSFGPSeshRXa459p3TyT0", "json"));
}
}
StaticCode
public class StaticCode {
/**
* Java位址
*/
public static final String BASE_URL = "http://api.map.baidu.com/telematics/v3/";
/**
* 擷取網絡資料成功
*/
public static final String HTTP_RESPONSE_SUCCESS = "Success";
}
源碼位址
Mvp-RxJava-Retrofit