RxJava +retrofit2實現(xiàn)安卓中網(wǎng)絡(luò)操作

#RxJava +retrofit2實現(xiàn)安卓中網(wǎng)絡(luò)操作~

在安卓中想實現(xiàn)網(wǎng)絡(luò)操作有多種方式,可能許多沒有經(jīng)歷過團隊開發(fā)的安卓工程師,經(jīng)常使用到的是第三方的云后臺,但是其實它們的底層使用的也一定是安卓中網(wǎng)絡(luò)的通信框架,例如:volley,nohttp,okhttp等。


今天我們要介紹的retrofit2底層就是用的okhttp的通信方式,下面簡單介紹一下為什么寫這篇文章吧,在開發(fā)團隊項目以前,我也和我小伙伴交流過,我說咱們一直采用第三方的云后臺,你說咱們怎么和真正的服務(wù)器做聯(lián)系啊,我們那個時候異口同聲的說不知道,后來在我做的第一個團隊項目“黑大盒子”的時候,我就學(xué)習(xí)了okHttp,那個時候感覺很好用啊,代碼也挺簡潔的,直至后來在一次,和我學(xué)長的交流過程中了解了可以用RxJava +retrofit2實現(xiàn)網(wǎng)絡(luò)的通信,那個時候我真的是下了很大的功夫研究,結(jié)果是毫無頭緒,因為那個時候,我對觀察者模式,和rxjava的系統(tǒng)的思想就是非常的不夠的。在后來我學(xué)習(xí)了觀察者模式,又一直在找rxjava的資料使我對這種網(wǎng)絡(luò)通信有了一定的了解。

使用RxJava +retrofit2實現(xiàn)網(wǎng)絡(luò)通信的優(yōu)勢

  • 請求時間和返回時間短(性能上的優(yōu)勢)
  • 代碼簡介,已經(jīng)把封裝實現(xiàn)到了極致

毫不夸張的說,如果公司沒有自己的網(wǎng)絡(luò)操作的框架,采用這種方式一定是最佳選擇之一

RxJava的簡介

鏈接:https://github.com/ReactiveX/RxJava
RxJava采用的思想便是觀察者模式,可以異步實現(xiàn)實現(xiàn)我們的需求,簡單的說,RxJava并不是輪詢?nèi)z測被觀察的對象,而是當(dāng)被觀察的對象有任何舉動的時候都會告訴我們,我們便可以根據(jù)這個消息決定要做什么處理。

retrofit2的簡介

鏈接:https://github.com/square/retrofit
retrofit這個庫的功能非常的強大,它可以直接向Gson添加依賴,解析我們返回的json數(shù)據(jù)非常的輕松,而且我們實現(xiàn)網(wǎng)絡(luò)操作也非常的便捷,非常輕松的就可以實現(xiàn)在工作線程請求網(wǎng)絡(luò)操作,在主線程實現(xiàn)對網(wǎng)絡(luò)操作結(jié)果的處理。

在這里我要非常正式的聲明一下,不是筆者懶,用兩句話,就把這么傳奇的兩個第三方開源庫就給介紹完了,而且本文主要的目的是教大家怎么用它們實現(xiàn)網(wǎng)絡(luò)操作,我接下來的文章會非常認(rèn)真的介紹,觀察者模式、RxJava、retrofit,這三方面的知識。
ps:我始終認(rèn)為,在你學(xué)習(xí)一個編程上的知識的時候,你最先要做的不是弄明白它,而是要用明白它,然后跟著代碼的邏輯走一遍,看看它是怎么實現(xiàn)的,然后可以看看人家的官方文檔,或者大神們的博客學(xué)習(xí)一下,最后我們還可以閱讀以下源碼,這樣學(xué)起來可能會輕松,也會比較高效。


RxJava +retrofit2的使用?。?!

第一步:在build.gradle中添加依賴

// RxJava Android 支持
compile 'io.reactivex:rxjava:1.1.6'
compile 'io.reactivex:rxandroid:1.2.1'
// Retrofit 網(wǎng)絡(luò)支持
compile 'com.squareup.retrofit2:retrofit:2.1.0'compile 'com.squareup.retrofit2:converter-gson:2.1.0'
// Gson 適配器
compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'

第二步:添加必要的權(quán)限

<uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
    <uses-permission android:name="android.permission.CHANGE_CONFIGURATION"/>
    <uses-permission android:name="android.permission.WRITE_SETTINGS"/>

第三步:定義一個接口,實現(xiàn)網(wǎng)絡(luò)操作
這個類,是在我們主URL后面鏈上的字段,然后泛型的是要返回數(shù)據(jù)我要將它解析成什么樣子,里面的參數(shù)就是post請求需要攜帶的參數(shù)了。

/**
 * Created by lin_sir on 2016/6/29.網(wǎng)絡(luò)協(xié)議
 */

public interface Api {

    @FormUrlEncoded
    @POST("getCode")
    Observable<ResponseModel_nolist> getCode(@Field("tel") String tel);

    @FormUrlEncoded
    @POST("register")
    Observable<ResponseModel_nolist> register(@Field("tel") String tel, @Field("password") String password, @Field("code") String code);
            
}

第四步:實現(xiàn)剛才泛型的類
為了讓大家使用起來毫無難度,我就在這里把這個簡單的類也粘出來了

/**
 * Created by lin_sir on 2016/7/7.結(jié)果中不帶有l(wèi)ist的網(wǎng)絡(luò)返回結(jié)果
 */
public class ResponseModel_nolist {

    private int code;
    private String msg;

    private obj obj;

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public com.example.lin_sir_one.tripbuyer.model.obj getObj() {
        return obj;
    }

    public void setObj(com.example.lin_sir_one.tripbuyer.model.obj obj) {
        this.obj = obj;
    }
}

第五步:實現(xiàn)一個BASE_URL,以后我們的網(wǎng)絡(luò)操作走的url都是在這些url后面加字段
當(dāng)然我打星號的,都是我們公司后臺暴露出來的接口啦,雖然我們做了負(fù)載均衡,也做了防止別人攻擊的處理啦,但是在這里暴露出來好像也還是不太好~



/* Created by lin_sir on 2016/6/29.全局常量定義
 */
public class Constant {

    public static final String BASE_URL = "http://xxx.xxx.xxx.xxx:8080/lxms-user/member/api/";

    public static final String BASE_BUY_URL = "http://xxx.xxx.xxx.xxx:8080//lxms-user/buyer/api/";

    public static final String BASE_SELL_URL = "http://xxx.xxx.xxx.xxx:8080/lxms-user/seller/api/";

}

第六步:實現(xiàn)一個Apiservice,這個類的作用就是實現(xiàn)我們的網(wǎng)絡(luò)操作的直接方式~



/**
 * Created by lin_sir on 2016/7/7.調(diào)用api接口,獲取驗證碼和注冊采用這個接口
 */
public class ApiService {

    private Api mApi;
    private Context mContext;
    private static ApiService mInstance;

//-------- 存在內(nèi)存泄漏的寫法,如果傳入 Activity 的 Context,會導(dǎo)致 Activity 無法被回收-------------------
//    private ApiService(Context mContext) {
//        this.mContext = mContext;
//        mApi = RetrofitClient.getClient(mContext).create(Api.class);
//    }
//
//    public static ApiService getInstance(Context mContext) {
//        if (mInstance == null) {
//            mInstance = new ApiService(mContext);
//        }
//        return mInstance;
//    }
//------------------------------------------------------------------------------------------------

    private ApiService() {
        this.mContext = BaseApplication.get().getAppContext();
        mApi = RetrofitClient.getClient(mContext).create(Api.class);
    }

    public static ApiService getInstance() {
        if (mInstance == null) {
            mInstance = new ApiService();
        }
        return mInstance;
    }

    /**
     * 獲取驗證碼
     */
    public void getCode(HttpResultListener<Boolean> listener, final String tel) {
        mApi.getCode(tel)
                .map(new HttpResultFuncNoList())
                .map(new Func1<String, Boolean>() {
                    @Override
                    public Boolean call(String s) {
                        if (s.equals("ok")) {
                            return true;
                        } else {
                            return false;
                        }
                    }
                })
                .subscribeOn(Schedulers.io())//在工作線程請求網(wǎng)絡(luò)
                .observeOn(AndroidSchedulers.mainThread())//在主線程處理結(jié)果
                .subscribe(new HttpResultSubscriber<>(listener));
    }




    private static class HttpResultSubscriber<T> extends Subscriber<T> {

        private HttpResultListener<T> mListener;

        public HttpResultSubscriber(HttpResultListener<T> listener) {
            mListener = listener;
        }


        @Override
        public void onCompleted() {

        }

        @Override
        public void onError(Throwable e) {
            if (mListener != null) {
                mListener.onError(e);
            }
        }

        @Override
        public void onNext(T t) {
            if (mListener != null) {
                mListener.onSuccess(t);
            }
        }
    }

    /**
     * 對返回結(jié)果做統(tǒng)一處理,只有當(dāng)結(jié)果碼為 100 時,才返回正常,否則返回錯誤,不帶list的
     */
    private class HttpResultFuncNoList implements Func1<ResponseModel_nolist, String> {

        @Override
        public String call(ResponseModel_nolist responseModel) {

            if (responseModel.getCode() == NetworkException.REQUEST_OK) {
                Log.i("lin", "---lin--->  目前沒發(fā)生錯誤:  " + responseModel.getCode());
                return responseModel.getMsg();
            } else {
                Log.i("lin", "---lin--->  錯誤代碼:  " + responseModel.getCode());
                throw new NetworkException(responseModel.getCode());
            }
        }
    }

}



第七步:實現(xiàn)網(wǎng)絡(luò)操作的回調(diào)接口



/**
 * Created by lin_sir on 2016/7/7.網(wǎng)絡(luò)操作的回調(diào)接口
 */
public interface HttpResultListener<T> {

    void onSuccess(T t);

    void onError(Throwable e);

}



第八步:實現(xiàn)retrifit2客戶端
在這個客戶端里面,我們不僅實現(xiàn)了Gson的適配器,也實現(xiàn)了Rxjava的適配器,還為我們的操作添加了主URL就可以了。


public class RetrofitClient {

    /**
     * 采用base_url
     */
    public static Retrofit getClient(Context context) {
        return new Retrofit.Builder()
                .baseUrl(Constant.BASE_URL)
                //.client(httpClient(context))
                .addConverterFactory(GsonConverterFactory.create())//Gson 適配器
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())// RxJava 適配器
                .build();
    }
}


其實我們的網(wǎng)絡(luò)操作就已經(jīng)實現(xiàn)完了,如果我們代碼習(xí)慣比較好的話,可以把所有的服務(wù)器返回的狀態(tài)嗎放在一起進行統(tǒng)一的處理。

統(tǒng)一處理后臺返回狀態(tài)碼的代碼:



/**
 * Created by tc on 6/21/16. 網(wǎng)絡(luò)操作錯誤
 */
public class NetworkException extends RuntimeException {

    public static final int REQUEST_OK = 100;
    public static final int REQUEST_FAIL = 101;
    public static final int METHOD_NOT_ALLOWED = 102;
    public static final int PARAMETER_ERROR = 103;
    public static final int UID_OR_PWD_ERROR = 104;
    public static final int SERVER_INTERNAL_ERROR = 105;
    public static final int REQUEST_TIMEOUT = 106;
    public static final int CONNECTION_ERROR = 107;
    public static final int VERIFY_EXPIRED = 108;
    public static final int NO_DATA = 109;


    public NetworkException(int resultCode) {
        this(getNetworkExceptionMessage(resultCode));
    }

    public NetworkException(String detailMessage) {
        super(detailMessage);
    }

    /**
     * 將結(jié)果碼轉(zhuǎn)換成對應(yīng)的文本信息
     */
    private static String getNetworkExceptionMessage(int code) {
        String message = "";
        switch (code) {
            case REQUEST_OK:
                message = "請求成功";
                break;
            case REQUEST_FAIL:
                message = "請求失敗";
                break;

            case METHOD_NOT_ALLOWED:
                message = "請求方式不允許";
                break;
            case PARAMETER_ERROR:
                message = "用戶不存在";
                break;
            case UID_OR_PWD_ERROR:
                message = "用戶名或密碼錯誤";
                break;
            case SERVER_INTERNAL_ERROR:
                message = "服務(wù)器內(nèi)部錯誤";
                break;
            case REQUEST_TIMEOUT:
                message = "請求超時";
                break;
            case CONNECTION_ERROR:
                message = "連接錯誤";
                break;
            case VERIFY_EXPIRED:
                message = "驗證過期";
                break;
            case NO_DATA:
                message = "沒有數(shù)據(jù)";
                break;
            case 110:
                message = "該用戶已存在";
                break;
            default:
                message = "未知錯誤";
        }
        return message;
    }
}


好了,我們已經(jīng)可以使用RxJava +retrofit2實現(xiàn)網(wǎng)絡(luò)操作了:


HttpResultListener<List<JourneyModel>> listener = new HttpResultListener<List<JourneyModel>>() {
            @Override
            public void onSuccess(List<JourneyModel> journeyModels) {
                KLog.d("----lin---->  成功");
            }

            @Override
            public void onError(Throwable e) {
                KLog.d("----lin---->  失敗" + e.toString());
            }
        };
        ApiService6.getInstance().route2(listener, "1");


到這里我們就已經(jīng)把網(wǎng)絡(luò)通信徹底的研究了一遍啦,雖然看起來稍微有一點點小復(fù)雜,但是我們要想的是,整個工程的網(wǎng)絡(luò)通信,我這點代碼就已經(jīng)都寫完了啊,以后用起來可就非常的方便啦。

在這里,我們對RxJava,Retrofit2已經(jīng)有了一個了解了,初步我們已經(jīng)會使用了這些知識,在接下來的文章里,我不會再這么詳細(xì)的介紹它們的使用,而是要介紹它們的實現(xiàn)的原理,和它們思想上的一些東西。

聲明:以上內(nèi)容為linSir本人原創(chuàng),這些知識都是我的小手下tc孜孜不倦教給我的,哈哈哈,他的個人網(wǎng)站是:www.classtc.com ,里面也有許多和編程有關(guān)的知識~如果大家,對這些知識有什么疑問,可以留言,我會第一時間回復(fù)的。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,733評論 25 709
  • 本博客為作者原創(chuàng),如需轉(zhuǎn)載請注明原博客出處:WONDER'TWO 0X00 寫在前面 相信做過And...
    一只酸奶牛哇閱讀 4,498評論 9 34
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,506評論 19 139
  • 做了一年的前端,一個應(yīng)屆畢業(yè)生現(xiàn)在已經(jīng)變成了半個老人了,互聯(lián)網(wǎng)企業(yè)的流動性真的還挺大的。 數(shù)據(jù)實習(xí),了解了數(shù)據(jù)的整...
    大喬是個美少女閱讀 320評論 0 1
  • 文/寺主人 我一直都不是個情商很高的人,在青春期很長的一段時間里甚至是一個低情商的人。 我不能夠準(zhǔn)確地識別自己的情...
    寺主人閱讀 3,712評論 2 37

友情鏈接更多精彩內(nèi)容