1. 程式人生 > >Retrofit2+RxJava封裝的網路框架(上)

Retrofit2+RxJava封裝的網路框架(上)

在2016年7月份,有幸封裝了Retrofit2+RxJava+Builder設計模式的網路框架。在今年去面試的過程中,被面試官提及Retrofit2和RxJava的知識,我竟有些答不出來,這令我非常難過。看來就算自己做過的東西也難免會忘的一乾二淨,這裡呢,我將重新封裝一下這個網路框架,並整理成部落格,供大家相互學習,並加深一下自己的印象,避免不必要的尷尬。

我計劃在今年(2018)年底將我的快速開發框架上傳Github,到時候我會在這篇博文中貼出地址,望大家到時候支援一下喲。可能有人會問這麼一個問題:都有那麼多輪子了,你為什麼還要造輪子呢?針對於這個問題我會針對於兩個方向進行回答。

1.針對於公司,當然是用現成的輪子,因為專案當然是越快結項越好呀,自己造輪子耗時耗力。
2.針對於你自己,如果你想成長,就必須有造輪子的能力,這個快速開發框架是我閒的時候,工作之餘搭建的,耗時兩個月,期間既痛苦又快樂。
當完成的那一刻,向同事推薦出去,收到了讚賞和意見。都要虛心接受喲。這個封裝好的網路框架就是其中之一。

廢話不多說,大家現在看一下我封裝的目錄結構


解析:

1.bean目錄 -- 用來參與解析的實體類
2.cookie目錄 -- 主要用來持久化cookie的
3.gsonutil目錄 -- GSON解析的封裝,本來打算用大<T>解析的,
但是我一直未找到讓GSON支援大<T>的解決辦法,GSON只能處於解析實體類的地步。
所以就用了String解析。
4.loggingInterceptors目錄 -- Log的封裝,這是從網上下載的,是對HttpLoggingInterceptor的再次封裝,友好的列印網路日誌,序列化後縮排分明,展示清晰。
5.BaseRetrofitConfig -- 配置檔案,包括baseUrl、追加公共引數等資訊
6.BaseRetrofitFactory -- (1).配置OkHttpClient、新增攔截器 
    (2).新增HttpLoggingInterceptorM 日誌攔截 (3).配置Retrofit
7.BaseRetrofitTwoService -- 網路請求介面Retrofit 2.+
8.NetModle -- 實現get post等方法,可在外部直接使用,極其方便。
9.NetSubscriber -- 可以在本類中對 Subscriber 獲取到的資料進行處理。
10.OnNetSubscriberListener -- 自定義網路資料回撥介面
11.tool目錄 -- 工具類,包含LogUtil
12.Switch -- 有個方法控制是否列印Log,正式釋出後關閉這個功能,其他功能不在介紹。

正文開始

第一步:建立快速開發框架(Moudle方式)

Moudle方式的好處是可隨便移植,靈活性高,高效便捷。如果不懂的話請看我整理的另一篇博文,專門講解Moudle的用法。《Android中Moudle的詳細使用教程》

第二步:修改剛建立好的Moudle中的build.gradle檔案

/* - 返回型別支援String - */
compile 'com.squareup.retrofit2:converter-scalars:2.0.0'//retrofit 框架   優化新增 +001

之上的程式碼,都是網路框架所用到的,包括這個,後面都有備註。我加的其他控制元件是快速開發框架裡別的東西,你們做網路框架,只需要新增8個retrofit的依賴就行了,看備註後面有1/8r、2/8r的那8個

dependencies {
    compile 'com.android.support:appcompat-v7:25.3.1'
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    /* - (可選)okhttp3日誌攔截器 除錯使用,專案中存在自己封裝的!!!,本包可不用 - */
//    compile 'com.squareup.okhttp3:logging-interceptor:3.4.1'//okhttp log攔截 版本必須和okhttp一致    1/8r

    /* - okhttp3 - */
    compile 'com.squareup.okhttp3:okhttp:3.4.1'//picasso + okHttp 2/2p  retrofit 框架  2/8r

    /* - retrofit2 - */
    compile 'com.squareup.retrofit2:retrofit:2.1.0'//retrofit 框架                         3/8r

    /* - gson - */
    compile 'com.google.code.gson:gson:2.7'//retrofit 框架                         4/8r

    /* - retrofit2使用gson需要新增這個包 - */
    compile 'com.squareup.retrofit2:converter-gson:2.1.0'//retrofit 框架                         5/8r

    /* - retrofit2使用rxjava需要新增這個包 - */
    compile 'com.squareup.retrofit2:adapter-rxjava:2.0.2'//retrofit 框架                         6/8r

    /* - 執行緒問題使用rxjava需要使用這個包 - */
    compile 'io.reactivex:rxandroid:1.1.0'//retrofit 框架                         7/8r

    /* - rxjava - */
    compile 'io.reactivex:rxjava:1.1.0'//retrofit 框架                         8/8r

    /* - 返回型別支援String - */
    compile 'com.squareup.retrofit2:converter-scalars:2.0.0'//retrofit 框架   優化新增 +001

    /* - 圖片選擇器 - */
//    compile 'com.lzy.widget:imagepicker:0.3.2'  //指定版本
    compile 'com.lzy.widget:imagepicker:0.5.5'  //指定版本
    compile 'com.github.nanchen2251:CompressHelper:1.0.5' //壓縮配套使用

    /* - picasso - */
    compile 'com.squareup.picasso:picasso:2.5.2'//picasso + okHttp 1/2p

    /* - butterknife - */
    //臨時沒有有效方法可以讓本控制元件支援library
//    compile 'com.jakewharton:butterknife:8.4.0'          //butterknife
//
//    apt 'com.jakewharton:butterknife-compiler:8.4.0'     //butterknife

    /* - 基於frame的新型下拉重新整理控制元件 - */
    compile 'com.lcodecorex:tkrefreshlayout:1.0.5'


    //掃碼思密達
    compile 'com.google.zxing:core:3.2.1'
    //掃碼所需包
    compile 'pub.devrel:easypermissions:0.1.7'
    //許可權
    compile 'cn.bingoogolapple:bga-qrcodecore:[email protected]'
    //掃碼所需包
    compile 'cn.bingoogolapple:bga-zxing:[email protected]'

}

第三步:開始寫程式碼

這篇文件我是分了上下兩篇分開寫的,上篇主要是講的是重點程式碼,下篇講的是輔助程式碼和用法。

重點程式碼只有這六個

5.BaseRetrofitConfig -- 配置檔案,包括baseUrl、追加公共引數等資訊
6.BaseRetrofitFactory -- (1).配置OkHttpClient、新增攔截器 
    (2).新增HttpLoggingInterceptorM 日誌攔截 (3).配置Retrofit
7.BaseRetrofitTwoService -- 網路請求介面Retrofit 2.+
8.NetModle -- 實現get post等方法,可在外部直接使用,極其方便。
9.NetSubscriber -- 可以在本類中對 Subscriber 獲取到的資料進行處理。
10.OnNetSubscriberListener -- 自定義網路資料回撥介面

我將按順序貼出程式碼,並講解

這個是配置檔案類,主要功能是設定引數,初始地址和超時時間等。初始化http的header響應頭方便進行驗籤。

package com.abysskitty.frame.network;

import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.util.ArrayMap;
import android.util.Log;

import com.abysskitty.frame.base.BaseApplication;
import com.abysskitty.frame.tool.DateUtil;
import com.abysskitty.frame.tool.EncryptUtil;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by AbyssKitty on 2016/10/9.
 * Version 1.0
 * 配置檔案,包括baseUrl、追加公共引數等資訊
 */
public class BaseRetrofitConfig {

    /**
     * 總url路徑 - 注意:Retrofit2.0 的baseUrl必須以“ / ”結尾,不然會丟擲IllegalArgumentException異常
     * Retrofit2.0 支援全URL路徑輸入 所以在這裡的路徑就是個擺設,但卻不能缺少
     * */
    public static final String baseUrl = "http://127.0.0.1:8080/api/v1/";

    /**
     * 連線超時時間,預設15s
     * */
    public static final int OKHTTP_OVERTIME = 15;


    /**
     * 需要追加的公共引數
     * Parame ->  未訪問伺服器之前,把此map拼接到上傳的引數中
     * hander ->  開始訪問伺服器之前,把此map新增到hander響應頭
     * */
    private static Map<String,String> Parame = new HashMap<>();
    private static Map<String,String> header = new HashMap<>();

    /**
     * 對 NetModle 開放獲取公共引數的方法,此引數直接追加在parame中
     * 過時方法,已摒棄,需要在程式中動態新增
     * */
    @Deprecated
    public static Map getCommonParameter(){
        Parame.clear();
        Parame = new HashMap<>();
        //Parame.put("","");
        return Parame;
    }
    /**
     * 對 NetModle 開放獲取公共引數方法,此方法追加在headers裡
     * 過時方法,已摒棄,根據專案需求,-必須或者需要-在程式中動態新增
     * */
    @Deprecated
    public static Map getHanderCommonParameter() {
        header.clear();
//        header = getHeasers();
        header = new HashMap<>();
        //hander.put("","");
        return header;
    }

    private static String SoftVersion = "v1";//介面版本

    private static String AppKey = "4bafd51*********************23fe";

    private static String AppToken = "2e02b2***********************044";

    private static String SecretKey = "HON************************HOU";

    private static String Accept = "application/json";//接收的資料型別,如json、xml。

    private static String code = "055************************c56"; //動態的使用者id

    private static String str = "";

    private static String str2 = "";

    private static String str3 = "";

    private static String str4 = "";

    public static Map<String,String> getHeasers(){
        Map<String,String> header = new HashMap<>();
        String AppVersion = BaseRetrofitConfig.getAppVersionName(BaseApplication.context);
        String AppName = BaseRetrofitConfig.getApplicationName(BaseApplication.context);
        try {
            str = EncryptUtil.base64Encoder(AppKey + ":" + AppToken + ":" + AppName + ":" + AppVersion + ":" + BaseRetrofitConfig.getTimestap());
            str2 = EncryptUtil.base64Encoder(SoftVersion);
            str3 = EncryptUtil.base64Encoder(code);
            str4 = EncryptUtil.createSignature(AppKey, AppToken, SecretKey);
        } catch (Exception e) {
            System.err.println("app驗證錯誤!");
        }
        header.put("Accept", Accept);
        header.put("AppInfo", str);
        header.put("SoftVersion", str2);
        header.put("accountSid", str3);
        header.put("sig",str4);
        return header;
    }

    /**
     * 時間戳(只是伺服器做記錄)
     * @return
     */
    public static String getTimestap() {
        return DateUtil.format(new Date(), DateUtil.PIN_PATTERN_DATE_MINUTE);
    }

    /**
     * 返回當前版本名
     */
    public static String getAppVersionName(Context context) {
        String versionName = "";
        try {
            PackageManager pm = context.getPackageManager();
            PackageInfo pi = pm.getPackageInfo(context.getPackageName(), 0);
            versionName = pi.versionName;
            if (versionName == null || versionName.length() <= 0) {
                return "";
            }
        } catch (Exception e) {
            Log.e("VersionInfo", "Exception", e);
            e.printStackTrace();
        }
        return versionName;
    }

    /**
     * 獲取當前應用名
     * @param context
     * @return
     */
    public static String getApplicationName(Context context) {
        PackageManager packageManager = null;
        ApplicationInfo applicationInfo = null;
        try {
            packageManager = context.getPackageManager();
            applicationInfo = packageManager.getApplicationInfo(context.getPackageName(), 0);
        } catch (PackageManager.NameNotFoundException e) {
            applicationInfo = null;
        }
        String applicationName =
                (String) packageManager.getApplicationLabel(applicationInfo);
        return applicationName;
    }
}

這個是重中之重,進行各種初始化,詳情請見註釋。通過builder模式初始化所用功能。

初始化retrofit,並加入日誌攔截、快取cookie、錯誤重連、超時時間、攔截新增header

並進行okhttp攔截。

package com.abysskitty.frame.network;

import com.abysskitty.frame.Switch;
import com.abysskitty.frame.base.BaseApplication;
import com.abysskitty.frame.network.cookie.CookieManger;
import com.abysskitty.frame.network.loggingInterceptors.okHttpLog.HttpLoggingInterceptorM;
import com.abysskitty.frame.network.loggingInterceptors.okHttpLog.LogInterceptor;

import java.io.IOException;
import java.net.SocketTimeoutException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.converter.scalars.ScalarsConverterFactory;

/**
 * Created by AbyssKitty on 2016/10/9.
 * Version 1.0
 * 初始化Retrofit 2.+
 * 1.配置OkHttpClient、新增攔截器
 * 2.新增HttpLoggingInterceptorM 日誌攔截
 * 3.配置Retrofit
 */
public class BaseRetrofitFactory {

    /**
     * 新增header響應頭的集合,用於存放追加的header頭的資料
     * */
    private Map<String,String> map = new HashMap<>();

    /**
     * 自定義Interceptor物件,用於在網路請求發出之前將header攔截新增進響應頭
     * */
    private MyInterceptor myInterceptor = null;

    /**
     * 構造器,通過builder方式傳入header響應頭並初始化自定義攔截器Interceptor
     * */
    private BaseRetrofitFactory(Builder builder){
        map.clear();
        this.map = builder.map;
        myInterceptor = new MyInterceptor(map);
    }

    /**
     * okhttp的日誌攔截,可在正式釋出時關閉
     * */
//    private HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY);
    /**
     * 自定義okhttp的日誌攔截,可在正式釋出時關閉
     * */
    private HttpLoggingInterceptorM interceptorM = new HttpLoggingInterceptorM(new LogInterceptor()).setLevel(HttpLoggingInterceptorM.Level.BODY);

    /**
     * 建立自定義OkHttpClient物件,初始化日誌攔截、錯誤重連、超時、響應頭等資訊
     * */
    private OkHttpClient getClient(){
        OkHttpClient client = null;
        if(Switch.isDebug){
            client = new OkHttpClient.Builder()
                    .addInterceptor(interceptorM)                                           //日誌攔截
                    .cookieJar(new CookieManger(BaseApplication.context))                   //快取cookie
                    .retryOnConnectionFailure(true)                                         //錯誤重連
                    .connectTimeout(BaseRetrofitConfig.OKHTTP_OVERTIME, TimeUnit.SECONDS)   //超時時間
                    .addNetworkInterceptor(myInterceptor)                                   //攔截新增響應頭
                    .build();
        }else{
            client = new OkHttpClient.Builder()
                    .cookieJar(new CookieManger(BaseApplication.context))                   //快取cookie
                    .retryOnConnectionFailure(true)                                         //錯誤重連
                    .connectTimeout(BaseRetrofitConfig.OKHTTP_OVERTIME, TimeUnit.SECONDS)   //超時時間
                    .addNetworkInterceptor(myInterceptor)                                   //攔截新增響應頭
                    .build();
        }
        return client;
    }

    /**
     * 初始化Retrofit物件,包括baseUrl、使用Gson解析、是用RxJava等。
     * */
    private Retrofit getRetrofit(){
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(BaseRetrofitConfig.baseUrl)                                    //base地址
                .addConverterFactory(ScalarsConverterFactory.create())                  //新增解析方式為String
                .addConverterFactory(GsonConverterFactory.create())                     //新增解析方式為Gson
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())               //新增網路RxJava
                .client(getClient())                                                    //新增自定義OkHttpClient
                .build();
        return retrofit;
    }

    /**
     * 建立Retrofit例項
     * */
    public BaseRetrofitTwoService getRetrofitService(){

        BaseRetrofitTwoService service = getRetrofit().create(BaseRetrofitTwoService.class);

        return service;
    }

    /**
     * Builder
     * */
    public static class Builder{

        Map<String,String> map = new HashMap<>();

        public Builder setHeaders(Map<String,String> map){
            this.map = map;
            return this;
        }

        public BaseRetrofitFactory build(){
            return new BaseRetrofitFactory(this);
        }
    }

    /**
     * create by AbyssKitty on 2016/10/09.
     * Version 1.0
     * 每次ping 攜帶請求頭 從OkHttp中攔截,Retrofit2只能使用註解方式新增headers
     * */
    public class MyInterceptor implements Interceptor {

        private Map<String, String> headers;

        public MyInterceptor(Map<String, String> headers) {
            this.headers = headers;
        }

        @Override
        public Response intercept(Chain chain) throws IOException {

            Response response = null;

            //同步 避免溢位
            synchronized (this){
                Request.Builder builder = chain.request()
                        .newBuilder();

                if (headers != null && headers.size() > 0) {

                    Set<String> keys = headers.keySet();

                    for (String headerKey : keys) {

                        builder.addHeader(headerKey, headers.get(headerKey)).build();

                    }

                    try{

                        response = chain.proceed(builder.build());

                    }catch (SocketTimeoutException e){
                        e.getLocalizedMessage();
                    }
                }else{

                    response = chain.proceed(builder.build());

                }
            }
//            獲取error code 暫時不用
//            Response responseError = chain.proceed(chain.request());
//            responseError.code();
            return response;
        }

    }
}

把Retrofit的介面集合化使用,集合成一個介面,複用高效。

package com.abysskitty.frame.network;

import java.util.Map;

import okhttp3.MultipartBody;
import okhttp3.RequestBody;
import retrofit2.http.Body;
import retrofit2.http.FieldMap;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.GET;
import retrofit2.http.Multipart;
import retrofit2.http.POST;
import retrofit2.http.Part;
import retrofit2.http.PartMap;
import retrofit2.http.QueryMap;
import retrofit2.http.Streaming;
import retrofit2.http.Url;
import rx.Observable;

/**
 * Created by AbyssKitty on 2016/10/6.
 * Version 1.0
 * 網路請求介面Retrofit 2.+
 */
public interface BaseRetrofitTwoService {
    /**
     * create by AbyssKitty on 2016/10/06.
     * 以get方式的網路請求介面
     * @param url 可傳全路徑或者只傳baseUrl之後的路徑
     * @param map 鍵值對引數
     * */
    @GET("")
    Observable<String> get(@Url String url, @QueryMap Map<String, String> map);

    /**
     * create by AbyssKitty on 2016/10/06.
     * 以post方式的網路請求介面
     * @param url 可傳全路徑或者只傳baseUrl之後的路徑
     * @param map 鍵值對引數
     * */
    @POST("")
    Observable<String> post(@Url String url, @QueryMap Map<String, String> map);


    /**
     * post實體
     * */
    @POST("")
    Observable<String> postBody(@Url String url, @Body String body);

    /**
     * post表單
     * */
    @FormUrlEncoded
    @POST("")
    Observable<String> postField(@Url String url, @FieldMap Map<String, String> map);

    /**
     * 單圖上傳
     * */
    @Multipart
    @POST("")
    Observable<String> upLoadFile(
            @Url String url,
            @Part MultipartBody.Part file
    );

    /**
     * 測試中 多圖上傳
     * */
    @Multipart
    @POST("")
    Observable<String> uploadFiles(
            @Url String url,
            @Part("filename") String description,
            @PartMap() Map<String, RequestBody> maps);


    /**
     * 測試中 下載
     * */
    @Streaming
    @GET
    Observable<String> downloadFile(@Url String fileUrl);


}

自定義的Net操作類,簡單化呼叫過程

package com.abysskitty.frame.network;

import com.abysskitty.frame.network.bean.RespBean;
import com.google.gson.Gson;

import java.io.File;
import java.util.HashMap;
import java.util.Map;

import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
import rx.Subscriber;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;

/**
 * Created by AbyssKitty on 2016/10/11.
 * Version 1.0
 * Net 自定義封裝
 * 實現get post等方法,可在外部直接使用。
 */
public class NetModle<T> {

    /* - resp裡的list - */
    public final static int RESP_LIST = 0x560001;

    /* - resp裡的obj - */
    public final static int RESP_OBJ = 0x560002;

    /* - resp裡的info - */
    public final static int RESP_INFO = 0x560003;

    /* - list - */
    public final static int LIST = 0x560004;

    /* - obj - */
    public final static int OBJ = 0x560005;

    /* - info - */
    public final static int INFO = 0x560006;

    /**
     * 單例物件初始化,必須使用private修飾
     * */
    private NetModle(){}

    /**
     * 全域性handers
     * */
    private Map<String,String> map = new HashMap<>();
    private Map<String,String> dmap = new HashMap<>();

    /**
     * Builder模式的初始化,保留
     * */
    private NetModle(Builder builder){
        this.map = builder.map;
    }

    /**
     * 獲取單例
     * */
    public static NetModle getInstance(){
        return NetMoudleHolder.netModle;
    }

    /**
     * 靜態內部類,實現執行緒安全、延遲載入、高效的單例模式。
     * */
    private static class NetMoudleHolder{
        private static NetModle netModle = new NetModle();
    }

    /**
     * get方式
     * @param url      地址
     * @param params   資料集合
     * @param onNetSubscriberListener    回撥
     * */
    public void get(String url, Map<String,String> params , OnNetSubscriberListener onNetSubscriberListener){
        get(url,params,0,null,onNetSubscriberListener);
    }
    /**
     * @param url      地址
     * @param params   資料集合
     * @param type     返回的資料型別
     * @param onNetSubscriberListener    回撥
     * */
    public void get(String url, Map<String,String> params, int type , OnNetSubscriberListener onNetSubscriberListener){
        get(url,params,type,null,onNetSubscriberListener);
    }
    /**
     * get方式
     * @param url      地址
     * @param params   資料集合
     * @param type     返回的資料型別
     * @param map      自定義的header集合
     * @param onNetSubscriberListener    回撥
     * */
    public void get(String url, Map<String,String> params, int type, Map<String,String> map, OnNetSubscriberListener onNetSubscriberListener){
        //params = addParams(params);
        getBaseRetrofitFactory(map)
                .getRetrofitService()
                .get(url,params)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(netNSListener(type,onNetSubscriberListener));
    }
    /**
     * post方式
     * @param url      地址
     * @param params   資料集合
     * @param onNetSubscriberListener    回撥
     * */
    public void post(String url, Map<String,String> params , OnNetSubscriberListener onNetSubscriberListener){
        post(url,params,0,null,onNetSubscriberListener);
    }
    /**
     * post方式
     * @param url      地址
     * @param params   資料集合
     * @param type     返回的資料型別
     * @param onNetSubscriberListener    回撥
     * */
    public void post(String url, Map<String,String> params, int type , OnNetSubscriberListener onNetSubscriberListener){
        post(url,params,type,null,onNetSubscriberListener);
    }
    /**
     * post方式
     * @param url   地址
     * @param params    資料集合
     * @param type     返回的資料型別
     * @param map   自定義的header集合,不傳的話使用預設的header
     * @param onNetSubscriberListener    回撥
     * */
    public void post(String url, Map<String,String> params, int type, Map<String,String> map, OnNetSubscriberListener onNetSubscriberListener){
        //params = addParams(params);
        getBaseRetrofitFactory(map)
                .getRetrofitService()
                .post(url,params)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(netNSListener(type,onNetSubscriberListener));
    }

    /**
     * post傳實體
     * */
    public void postBody(String url, String json, int type, Map<String,String> map, OnNetSubscriberListener onNetSubscriberListener){
//        RequestBody body = RequestBody.create(okhttp3.MediaType.parse("application/json"),json);
//        if(body != null){
//            LogUtil.d("-----------------------------1"+body.toString());
//
//        }else{
//            LogUtil.d("-----------------------------2");
//        }
        getBaseRetrofitFactory(map)
                .getRetrofitService()
                .postBody(url,json)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(netNSListener(type,onNetSubscriberListener));

    }
    /**
     * post傳表單FieldMap
     * */
    public void postField(String url, Map<String,String> parme, int type, Map<String,String> map, OnNetSubscriberListener onNetSubscriberListener){
        getBaseRetrofitFactory(map)
                .getRetrofitService()
                .postField(url,parme)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(netNSListener(type,onNetSubscriberListener));
    }

    /**
     * 圖片上傳post方式
     * @param url   地址
     * @param path   圖片地址
     * @param onNetSubscriberListener    回撥
     * */
    public void upload(String url, String path, OnNetSubscriberListener onNetSubscriberListener){
        upload(url,path,0,null,onNetSubscriberListener);
    }

    /**
     * 圖片上傳post方式
     * @param url   地址
     * @param path   圖片地址
     * @param type     返回的資料型別
     * @param map   自定義的header集合,不傳的話使用預設的header
     * @param onNetSubscriberListener    回撥
     * */
    public void upload(String url, String path, int type, Map<String,String> map, OnNetSubscriberListener onNetSubscriberListener){
        //Subscription d =
        getBaseRetrofitFactory(map)
                .getRetrofitService()
                .upLoadFile(url,getMultipartBodyPart(path))
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(netNSListener(type,onNetSubscriberListener));
    }
    /**
     * 圖片上傳post方式
     * @param url   地址
     * @param file   圖片檔案
     * @param type     返回的資料型別
     * @param map   自定義的header集合,不傳的話使用預設的header
     * @param onNetSubscriberListener    回撥
     * */
    public void upload(String url, File file, int type, Map<String,String> map, OnNetSubscriberListener onNetSubscriberListener){
        //Subscription d =
        getBaseRetrofitFactory(map)
                .getRetrofitService()
                .upLoadFile(url,getMultipartBodyPart(file))
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(netNSListener(type,onNetSubscriberListener));
    }
    /**
     * Subscriber 預處理
     * */
    private Subscriber netNSListener(final int type, final OnNetSubscriberListener onNetSubscriberListener){
        NetSubscriber<String> stringSubscriber = new NetSubscriber<String>() {
            @Override
            public void onCompleted() {
                super.onCompleted(); //執行預處理
//                if(onNetSubscriberListener != null){
//                    onNetSubscriberListener.onCompleted();
//                }
            }

            @Override
            public void onError(Throwable e){
                super.onError(e); //執行預處理
                if(onNetSubscriberListener != null){
                    onNetSubscriberListener.onError(e);
                }
            }

            @Override
            public void onNext(String s){
                super.onNext(s); //執行預處理
                Gson gson = new Gson();

                //去掉根節點 資料預處理,根據伺服器資料修改!!!
                RespBean rb = gson.fromJson(s, RespBean.class);
//                    Object o = jsonGetObj(type,rb);
//                    if(onNetSubscriberListener != null){
//                        onNetSubscriberListener.onNext(rb,o);
                if(onNetSubscriberListener != null){
                    onNetSubscriberListener.onNext(rb);
                }
            }
        };
        return stringSubscriber;
    }
    /**
     * 初始資料預處理
     * */
    @Deprecated
    public Object jsonGetObj(int type, RespBean rb){
        Object o = null;
        Gson gson = new Gson();
        switch (type){
            case RESP_LIST:
                o = rb.resp.list;
                break;
            case RESP_INFO:
                o = gson.toJson(rb.resp.info);
                break;
            case RESP_OBJ:
                o = gson.toJson(rb.resp.obj);
                break;
            case LIST:
                o = rb.list;
                break;
            case INFO:
                o = gson.toJson(rb.info);
                break;
            case OBJ:
                o = gson.toJson(rb.obj);
                break;
            default:
        }
        return o;
    }
    /**
     * 檔案上傳
     * */
    private MultipartBody.Part getMultipartBodyPart(String mPath){
        File file = new File(mPath);
        //multipart/form-data 格式
        RequestBody requestFile =
                RequestBody.create(MediaType.parse("multipart/form-data"), file);
        //file - 為上傳引數的 鍵名
        MultipartBody.Part body =
                MultipartBody.Part.createFormData("file", file.getName(), requestFile);
        return body;
    }
    /**
     * 檔案上傳
     * */
    private MultipartBody.Part getMultipartBodyPart(File file){
        //multipart/form-data 格式
        RequestBody requestFile =
                RequestBody.create(MediaType.parse("multipart/form-data"), file);
        //file - 為上傳引數的 鍵名
        MultipartBody.Part body =
                MultipartBody.Part.createFormData("file", file.getName(), requestFile);
        return body;
    }

    /**
     * 獲取RetrofitFactory物件
     * */
    private BaseRetrofitFactory getBaseRetrofitFactory(Map<String,String> map){

        BaseRetrofitFactory baseRetrofitFactory = null;

        if(map != null){

            baseRetrofitFactory = new BaseRetrofitFactory.Builder()
                    .setHeaders(map)
                    .build();
        }else{
            /* 在這裡新增預設的 handers */
            dmap = BaseRetrofitConfig.getHanderCommonParameter();
            //LogUtil.d("getHanderCommonParameter="+dmap.size()+" moren");
            baseRetrofitFactory = new BaseRetrofitFactory.Builder()
                    .setHeaders(dmap)
                    .build();
        }
        return baseRetrofitFactory;
    }

    /**
     * 追加params資料
     * 可不用此方法,已摒棄
     * */
    @Deprecated
    private Map addParams(Map parame){
        Map<String,String> p = null;
        p = BaseRetrofitConfig.getCommonParameter();
        if(p != null){
            parame.putAll(p);
        }
        return parame;
    }

    /**
     * Builder,留用 暫時未用 ,當前是以靜態方法方式實現的
     * */
    public class Builder{

        Map<String,String> map;

        Map<String,String> params;

        public Builder setHander(Map<String,String> map){
            this.map = map;
            return this;
        }

        public Builder setMap(Map<String,String> params){
            this.params = params;
            return this;
        }

        public NetModle build(){
            return new NetModle(this);
        }
    }
}