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

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

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


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

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

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

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

RxJava的簡介

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

retrofit2的簡介

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

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


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"/>

第三步:定義一個(gè)接口,實(shí)現(xiàn)網(wǎng)絡(luò)操作
這個(gè)類,是在我們主URL后面鏈上的字段,然后泛型的是要返回?cái)?shù)據(jù)我要將它解析成什么樣子,里面的參數(shù)就是post請(qǐng)求需要攜帶的參數(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);
            
}

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

/**
 * 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;
    }
}

第五步:實(shí)現(xiàn)一個(gè)BASE_URL,以后我們的網(wǎng)絡(luò)操作走的url都是在這些url后面加字段
當(dāng)然我打星號(hào)的,都是我們公司后臺(tái)暴露出來的接口啦,雖然我們做了負(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/";

}

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



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

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

//-------- 存在內(nèi)存泄漏的寫法,如果傳入 Activity 的 Context,會(huì)導(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;
    }

    /**
     * 獲取驗(yàn)證碼
     */
    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())//在工作線程請(qǐng)求網(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);
            }
        }
    }

    /**
     * 對(duì)返回結(jié)果做統(tǒng)一處理,只有當(dāng)結(jié)果碼為 100 時(shí),才返回正常,否則返回錯(cuò)誤,不帶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ā)生錯(cuò)誤:  " + responseModel.getCode());
                return responseModel.getMsg();
            } else {
                Log.i("lin", "---lin--->  錯(cuò)誤代碼:  " + responseModel.getCode());
                throw new NetworkException(responseModel.getCode());
            }
        }
    }

}



第七步:實(shí)現(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);

}



第八步:實(shí)現(xiàn)retrifit2客戶端
在這個(gè)客戶端里面,我們不僅實(shí)現(xiàn)了Gson的適配器,也實(shí)現(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();
    }
}


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

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



/**
 * Created by tc on 6/21/16. 網(wǎng)絡(luò)操作錯(cuò)誤
 */
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)換成對(duì)應(yīng)的文本信息
     */
    private static String getNetworkExceptionMessage(int code) {
        String message = "";
        switch (code) {
            case REQUEST_OK:
                message = "請(qǐng)求成功";
                break;
            case REQUEST_FAIL:
                message = "請(qǐng)求失敗";
                break;

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


好了,我們已經(jīng)可以使用RxJava +retrofit2實(shí)現(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ò)通信徹底的研究了一遍啦,雖然看起來稍微有一點(diǎn)點(diǎn)小復(fù)雜,但是我們要想的是,整個(gè)工程的網(wǎng)絡(luò)通信,我這點(diǎn)代碼就已經(jīng)都寫完了啊,以后用起來可就非常的方便啦。

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

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

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

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

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

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