Retrofit+Rxjava 網路請求的完美封裝(二)(觀察者模式)
上一篇是Retrofit+Rxjava簡單封裝,是在MainActivity中構建的請求體,這篇博文是將請求體Request也置入到Rxjava中
Retrofit+Rxjava 網路請求的簡單封裝(一)(觀察者模式)
如果想對RxJava進行簡單的瞭解,可以參考我如下的博文
RxJava響應式程式設計之初級瞭解
我通過公司一個上線App介面來進行Retrofit+Rxjava 的簡單學習
http://x-phone.cn/api/v1.0/DeletePrivateContact
當然你直接訪問上面的url是無法獲取伺服器Json資料的,因為是需要封裝請求體,如下是在沒有封裝請求體,返回的錯誤介面
Method Not Allowed
The method is not allowed for the requested URL.
首先看下請求的Json格式如下
[getJuheResult]requestJsonStr =
{
"contact_ids": [
"1475920950100"
],
"godin_id": "4c59396301ab6274bd7892f0b31df36e",
"imei": "123456789012345",
"phone_num": "18612185929"
}
返回的Json格式如下,如下是一種返回的格式:
[getJuheResult.onNext]Head{statuscode='000009', statusmsg='device and user not match'}
這篇部落格就對上篇部落格的進行Retrofit+Rxjava 簡單封裝在進行請求體的封裝
首先看看上篇部落格在MainActivity中封裝的HttpRequest請求
ArrayList<String> contact_ids = new ArrayList<>();
contact_ids.add("1475920950100");
HttpRequest httpRequest = new HttpRequest();
httpRequest.setPhone_num("18612185929");
httpRequest.setImei("123456789012345");
httpRequest.setGodin_id("4c59396301ab6274bd7892f0b31df36e");
httpRequest.setContact_ids(contact_ids);
封裝之後呢?在上篇部落格中,在通過引數傳遞進來
public void postClickAppInfoParameterJsonBody(HttpRequest request) {
if (request == null) {
throw new NullPointerException("Argument request cannot be null.");
}
Log.d(TAG,"[getJuheResult]requestJsonStr = \n"+gson.toJson(jsonParser.parse(gson.toJson(request))));
FactoryInters.PostClickAppInfoParameterJsonBody server = retrofit.create(FactoryInters.PostClickAppInfoParameterJsonBody.class);
//觀察者
Subscriber subscriber = new HttpResultSubscriber("getJuheResult");
server.getJuheResult(request)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(subscriber);
}
如上的方式,其實我們可以將它也放到Rxjava中封裝起來,通過Rxjava直接傳遞進來
1、在Rxjava中構建HttpRequest進行傳遞或者根據業務需要進行轉換(當然如果請求業務多了,可以另起一個類統一管理)
/**
* 設定執行緒
*/
public <T> Observable<T> setThread(Observable<T> observable) {
observable.subscribeOn(Schedulers.from(exector))
.observeOn(AndroidSchedulers.mainThread());
return observable;
}
/**
* 上傳伺服器刪除聯絡人操作
*/
public void postClickAppInfoParameterJsonBody() {
//被觀察者。。。
RxJavaHelper.getInstance().setThread(Observable.create(new Observable.OnSubscribe<HttpRequest>() {
@Override
public void call(Subscriber<? super HttpRequest> subscriber) {
ArrayList<String> contact_ids = new ArrayList<>();
contact_ids.add("1475920950100");
HttpRequest httpRequest = new HttpRequest();
httpRequest.setPhone_num("18612185929");
httpRequest.setImei("123456789012345");
httpRequest.setGodin_id("4c59396301ab6274bd7892f0b31df36e");
httpRequest.setContact_ids(contact_ids);
subscriber.onNext(httpRequest);
}
}))
.subscribe(new Action1<HttpRequest>() {
@Override
public void call(HttpRequest request) {
RetrofitManger.getInstance().postClickAppInfoParameterJsonBody(request);
}
});
}
2、將HttpRequest傳遞過來之後,就開始進行Retrofit方面的封裝首先看基類RetrofitBase
protected RetrofitBase(){
retrofit = new Retrofit.Builder()
.baseUrl(BASEURL)
.client(client())
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
}
private OkHttpClient client(){
LauncherTrust launcherTrust = new LauncherTrust();
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.connectTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
.readTimeout(TIMEOUT,TimeUnit.MILLISECONDS)
.sslSocketFactory(sslSocketFactory(launcherTrust),launcherTrust)
.hostnameVerifier(new AllowAllHostnameVerifier())
.build();
return okHttpClient;
}
3、我們看下Retrofit通過特有的註解方式,配置請求HttpRequest,返回HttpResult的程式碼介面,跟Rxjava結合起來,然後在第4步操作中,通過Rxjava的觀察者模式進行響應操作
public interface FactoryInters {
//http://x-phone.cn/api/v1.0/DeletePrivateContact
interface PostClickAppInfoParameterJsonBody{
@Headers({"Content-Type: application/json","Accept: application/json"})
@POST("DeletePrivateContact")
Observable<HttpResult> getJuheResult(@Body HttpRequest request);
}
}
4、然後看Retrofit主類,主要處理請求返回資料的傳遞,非同步響應操作
/**
* {"phone_num": "18612185929", "imei": "123456789012345", "godin_id": "4c59396301ab6274bd7892f0b31df36e", "contact_ids": ["1475920950100"]}
*/
public void postClickAppInfoParameterJsonBody(HttpRequest request) {
if (request == null) {
throw new NullPointerException("Argument request cannot be null.");
}
Log.d(TAG,"[getJuheResult]requestJsonStr = \n"+gson.toJson(jsonParser.parse(gson.toJson(request))));
FactoryInters.PostClickAppInfoParameterJsonBody server = retrofit.create(FactoryInters.PostClickAppInfoParameterJsonBody.class);
//觀察者
Subscriber subscriber = new HttpResultSubscriber("getJuheResult");
server.getJuheResult(request)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(subscriber);
}
private class HttpResultSubscriber extends Subscriber<HttpResult>{
private String method;
public HttpResultSubscriber(String methodTag){
this.method = methodTag;
}
@Override
public void onCompleted() {
Log.i(TAG, "onCompleted");
}
@Override
public void onError(Throwable e) {
StringBuffer sb = new StringBuffer();
sb.append("[").append(method).append(".onError]").append(e);
Log.e(TAG,sb.toString());
}
@Override
public void onNext(HttpResult httpResult) {
StringBuffer sb = new StringBuffer();
sb.append("[").append(method).append(".onNext]")
.append(httpResult.getHead().toString());
Log.i(TAG,sb.toString());
}
}
如下的程式碼,就是Rxjava觀察者模式的使用,就是通過傳遞HttpRequest,獲取HttpResult結果,然後在通過構建被觀察者,觀察者進行事件傳遞,響應操作和處理
server.getJuheResult(request)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(subscriber);
最後再次看下請求體,響應結果如下:
11-03 14:48:23.526 31285-31285/? D/RetrofitManger: [getJuheResult]requestJsonStr =
{
"contact_ids": [
"1475920950100"
],
"godin_id": "4c59396301ab6274bd7892f0b31df36e",
"imei": "123456789012345",
"phone_num": "18612185929"
}
11-03 14:48:23.758 31285-31285/? I/RetrofitManger: [getJuheResult.onNext]Head{statuscode='000009', statusmsg='device and user not match'}
糾錯
/**
* 設定執行緒
*/
public <T> Observable<T> setThread(Observable<T> observable) {
observable.subscribeOn(Schedulers.from(exector))
.observeOn(AndroidSchedulers.mainThread());
return observable;
}
這個經過測試,是執行在主執行緒的,應該將其拿出來,放到分執行緒中
———————————————以下是程式碼區———————————————
配置檔案:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.godinsec.db" >
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
HttpRequest
package com.godinsec.db;
import java.util.ArrayList;
/**
* 刪除聯絡人封裝的請求體
* {"phone_num": "18612185929", "imei": "123456789012345", "godin_id": "4c59396301ab6274bd7892f0b31df36e", "contact_ids": ["1475920950100"]}
*/
public class HttpRequest {
private String phone_num;
private String imei;
private String godin_id;
private ArrayList<String> contact_ids;
public ArrayList<String> getContact_ids() {
return contact_ids;
}
public void setContact_ids(ArrayList<String> contact_ids) {
this.contact_ids = contact_ids;
}
public String getPhone_num() {
return phone_num;
}
public void setPhone_num(String phone_num) {
this.phone_num = phone_num;
}
public String getImei() {
return imei;
}
public void setImei(String imei) {
this.imei = imei;
}
public String getGodin_id() {
return godin_id;
}
public void setGodin_id(String godin_id) {
this.godin_id = godin_id;
}
@Override
public String toString() {
return "HttpRequest{" +
"phone_num='" + phone_num + '\'' +
", imei='" + imei + '\'' +
", godin_id='" + godin_id + '\'' +
", contact_ids=" + contact_ids +
'}';
}
}
HttpResult
package com.godinsec.db;
import java.util.ArrayList;
/**
* 刪除正確返回的json格式
* {"head": {
* "statuscode": "000000",
* "statusmsg": "success"
* }
* }
*/
public class HttpResult {
@Override
public String toString() {
return "HttpResult{" +
"head=" + head +
'}';
}
private Head head;
public Head getHead() {
return head;
}
public void setHead(Head head) {
this.head = head;
}
public static class Head {
private String statuscode;
private String statusmsg;
public String getStatuscode() {
return statuscode;
}
public void setStatuscode(String statuscode) {
this.statuscode = statuscode;
}
public String getStatusmsg() {
return statusmsg;
}
public void setStatusmsg(String statusmsg) {
this.statusmsg = statusmsg;
}
@Override
public String toString() {
return "Head{" +
"statuscode='" + statuscode + '\'' +
", statusmsg='" + statusmsg + '\'' +
'}';
}
}
}
RxJavaHelper
package com.godinsec.db;
import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
import rx.Observable;
import rx.Subscriber;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Action1;
import rx.schedulers.Schedulers;
/**
* Created by Safly on 2016/11/3.
*/
public final class RxJavaHelper {
private ExecutorService exector = null;
private RxJavaHelper() {
exector = Executors.newFixedThreadPool(5, new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
AtomicInteger mCount = new AtomicInteger(1);
Thread thread = new Thread(r, "PrivacyLauncherThread_id:" + mCount.getAndIncrement());
thread.setPriority(Thread.NORM_PRIORITY - 1);
return thread;
}
});
}
private static final class Factory {
private static final RxJavaHelper instance = new RxJavaHelper();
}
public static RxJavaHelper getInstance() {
return Factory.instance;
}
/**
* 設定執行緒
*/
public <T> Observable<T> setThread(Observable<T> observable) {
observable.subscribeOn(Schedulers.from(exector))
.observeOn(AndroidSchedulers.mainThread());
return observable;
}
/**
* 上傳伺服器刪除聯絡人操作
*/
public void postClickAppInfoParameterJsonBody() {
//被觀察者。。。
RxJavaHelper.getInstance().setThread(Observable.create(new Observable.OnSubscribe<HttpRequest>() {
@Override
public void call(Subscriber<? super HttpRequest> subscriber) {
ArrayList<String> contact_ids = new ArrayList<>();
contact_ids.add("1475920950100");
HttpRequest httpRequest = new HttpRequest();
httpRequest.setPhone_num("18612185929");
httpRequest.setImei("123456789012345");
httpRequest.setGodin_id("4c59396301ab6274bd7892f0b31df36e");
httpRequest.setContact_ids(contact_ids);
subscriber.onNext(httpRequest);
}
}))
.subscribe(new Action1<HttpRequest>() {
@Override
public void call(HttpRequest request) {
RetrofitManger.getInstance().postClickAppInfoParameterJsonBody(request);
}
});
}
}
RetrofitBase
package com.godinsec.db;
import com.godinsec.db.RxJavaHelper;
import org.apache.http.conn.ssl.AllowAllHostnameVerifier;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
/**
* Created by Seeker on 2016/9/13.
*/
public abstract class RetrofitBase {
// private static final String BASEURL = "http://10.0.5.97:9000/api/v1.0/";
private static final String BASEURL = "http://x-phone.cn/api/v1.0/";
private static final long TIMEOUT = 5 * 1000;
protected Retrofit retrofit;
protected RetrofitBase(){
retrofit = new Retrofit.Builder()
.baseUrl(BASEURL)
.client(client())
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
}
private OkHttpClient client(){
LauncherTrust launcherTrust = new LauncherTrust();
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.connectTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
.readTimeout(TIMEOUT,TimeUnit.MILLISECONDS)
.sslSocketFactory(sslSocketFactory(launcherTrust),launcherTrust)
.hostnameVerifier(new AllowAllHostnameVerifier())
.build();
return okHttpClient;
}
private SSLSocketFactory sslSocketFactory(LauncherTrust launcherTrust){
try {
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null,new TrustManager[]{launcherTrust},new SecureRandom());
return sslContext.getSocketFactory();
} catch (NoSuchAlgorithmException | KeyManagementException e) {
e.printStackTrace();
}
return null;
}
static class LauncherTrust implements X509TrustManager {
@Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}
}
RetrofitManger
package com.godinsec.db;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonParser;
import java.util.ArrayList;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import rx.Subscriber;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
/**
* {"resultcode":"101","reason":"錯誤的請求KEY!","result":null,"error_code":10001}
*/
public class RetrofitManger extends RetrofitBase {
private static final String TAG = "RetrofitManger";
private Gson gson;
private JsonParser jsonParser;
private RetrofitManger() {
super();
gson = new GsonBuilder().setPrettyPrinting().create();
jsonParser = new JsonParser();
}
private static final class Factory {
private static final RetrofitManger instance = new RetrofitManger();
}
public static RetrofitManger getInstance() {
return Factory.instance;
}
/**
* {"phone_num": "18612185929", "imei": "123456789012345", "godin_id": "4c59396301ab6274bd7892f0b31df36e", "contact_ids": ["1475920950100"]}
*/
public void postClickAppInfoParameterJsonBody(HttpRequest request) {
if (request == null) {
throw new NullPointerException("Argument request cannot be null.");
}
Log.d(TAG,"[getJuheResult]requestJsonStr = \n"+gson.toJson(jsonParser.parse(gson.toJson(request))));
FactoryInters.PostClickAppInfoParameterJsonBody server = retrofit.create(FactoryInters.PostClickAppInfoParameterJsonBody.class);
//觀察者
Subscriber subscriber = new HttpResultSubscriber("getJuheResult");
server.getJuheResult(request)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(subscriber);
}
private class HttpResultSubscriber extends Subscriber<HttpResult>{
private String method;
public HttpResultSubscriber(String methodTag){
this.method = methodTag;
}
@Override
public void onCompleted() {
Log.i(TAG, "onCompleted");
}
@Override
public void onError(Throwable e) {
StringBuffer sb = new StringBuffer();
sb.append("[").append(method).append(".onError]").append(e);
Log.e(TAG,sb.toString());
}
@Override
public void onNext(HttpResult httpResult) {
StringBuffer sb = new StringBuffer();
sb.append("[").append(method).append(".onNext]")
.append(httpResult.getHead().toString());
Log.i(TAG,sb.toString());
}
}
}
FactoryInters
package com.godinsec.db;
import java.util.Map;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.GET;
import retrofit2.http.Headers;
import retrofit2.http.POST;
import retrofit2.http.Query;
import retrofit2.http.QueryMap;
import rx.Observable;
public interface FactoryInters {
//http://x-phone.cn/api/v1.0/DeletePrivateContact
interface PostClickAppInfoParameterJsonBody{
@Headers({"Content-Type: application/json","Accept: application/json"})
@POST("DeletePrivateContact")
Observable<HttpResult> getJuheResult(@Body HttpRequest request);
}
}
MainActivity
package com.godinsec.db;
import android.app.Activity;
import android.os.Bundle;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RxJavaHelper.getInstance().postClickAppInfoParameterJsonBody();
}
}