Retrofit2.0 使用

一入偷、搭建聯(lián)網(wǎng)框架

使用Retrofit2搭建項(xiàng)目的網(wǎng)絡(luò)請求框架之前呵晚,我們需要先導(dǎo)入相關(guān)的三方庫

compile 'com.squareup.retrofit2:retrofit:2.2.0'
compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
compile 'com.squareup.retrofit2:converter-gson:2.2.0'
compile 'io.reactivex:rxandroid:1.2.1'
compile 'io.reactivex:rxjava:1.2.1'

1矾芙、發(fā)起請求

Retrofit2向web服務(wù)器發(fā)起請求的方式有兩種----Call 和rxjava

  • Call

Call是Retrofit2庫里發(fā)起請求的方法假抄,使用這種方式我們可以使用execute來進(jìn)行同步請求隧出,enqueue來進(jìn)行異步請求踏志,cancel來取消請求。實(shí)際的使用過程:

Retrofit 初始化

 public static final String baseUrl = "http://192.168.100.214:8090/peakBusiness/";  //內(nèi)網(wǎng)
   //--接口請求 
   private static NetworkService api;
    public static NetworkService api() {
        if (api == null) {
            Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl(baseUrl)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
            api = retrofit.create(NetworkService.class);
        }
        return api;
    }

定義接口請求的方法

@GET("front/user.htm")
Call<ReceiveData.BaseResponse > login(@QueryMap Map<String, String> options);

返回?cái)?shù)據(jù)解析

  //登錄
 public static class BaseResponse {
       public int code;
       public String msg;
 }

接口調(diào)用

private void login(String loginName,String password) {
        Map<String, String> options = new HashMap<>();
        options.put("method", "login");
        options.put("token", "123121");
        options.put("loginName", loginName);
        options.put("password", password);
        RestClient.api().login(options).enqueue(new Callback<ReceiveData.loginResponse>() {
            @Override
            public void onResponse(Call<ReceiveData.loginResponse> call, Response<ReceiveData.loginResponse> response) {
                if (response.body() == null) {
                    ToastUtil.showLong(LoginActivity.this,"登錄異常", Gravity.CENTER);
                    return;
                }
                if (response.body().code == 0) {
                    ToastUtil.showLong(LoginActivity.this,"登錄成功", Gravity.CENTER);
                    Gson gson = new Gson();
                    MyApplication.getInstance().setUserInfo(gson.toJson(response.body().obj));
                    finish();
                }else {
                    ToastUtil.showLong(LoginActivity.this,response.body().msg, Gravity.CENTER);
                }
            }

            @Override
            public void onFailure(Call<ReceiveData.loginResponse> call, Throwable t) {
                dialog.dismiss();
                ToastUtil.showLong(LoginActivity.this,"登錄失敗",Gravity.CENTER);
            }
        });
    }

  • rxjava

RxJava響應(yīng)式編程框架胀瞪,基于觀察者模式针余。使用這種方式進(jìn)行請求我們主要使用到了ObServable(被觀察者)和Subscribe(觀察者),關(guān)于RxJava和Observable的講解可以查看這篇文章RxJava—Observable
實(shí)際的使用過程:

Retrofit 初始化(HttpMethods.java)

    public static final String BASE_URL = "http://192.168.100.132:8080/cnbsExamInterface/";
    private static final int DEFAULT_TIMEOUT = 15;
    private NetworkService networkService;
    public static final int SuccessCode = 0;
    //構(gòu)造方法私有
    private HttpMethods() {
        OkHttpClient httpClient = new OkHttpClient.Builder()
                .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
                .readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
                .build();

        networkService = new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .client(httpClient)
                .build()
                .create(NetworkService.class);
    }

    //在訪問HttpMethods時(shí)創(chuàng)建單例
    private static class SingletonHolder {
        private static final HttpMethods INSTANCE = new HttpMethods();
    }

    //獲取單例
    public static HttpMethods getInstance() {
        return SingletonHolder.INSTANCE;
    }

    private void toSubscribe(Observable o, Subscriber s) {
        o.subscribeOn(Schedulers.io()) // 指定 subscribe() 發(fā)生在 IO 線程
          .observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回調(diào)發(fā)生在主線程
          .subscribe(s);
    }

    //----------請求方法------------
    //登錄
    public void login(Subscriber<HttpResult.LoginResponse> subscriber, Map<String, String> options) {
        Observable observable = networkService.login(options);
        toSubscribe(observable, subscriber);
    }

定義接口請求的方法(NetworkService.java)

  //登錄
    @GET("front/logAct/log.html")
    Observable<HttpResult.LoginResponse> login(@QueryMap Map<String, String> options);

返回?cái)?shù)據(jù)解析(HttpResult.java)

   public static class BaseResponse {
        public String code;
        public String msg;
    }

接口調(diào)用

private void login(String user,String psw) {
        Map<String, String> map = new HashMap<>();
        map.put("loginName", user);
        map.put("passWord", psw);
        HttpMethods.getInstance().login(new Subscriber<HttpResult.LoginResponse>() {
            @Override
            public void onCompleted() {

            }

            @Override
            public void onError(Throwable e) {
                new CenterHintToast(LoginActivity.this,"登錄失敗凄诞,稍后重試圆雁!");
            }

            @Override
            public void onNext(HttpResult.LoginResponse response) {
                if ("0".equals(response.code)) {
                    UserBean bean = response.user;
                    MyApplication instance = MyApplication.getInstance();
                    instance.setUserInfo(bean);
                    Intent intent = new Intent(LoginActivity.this, MainActivity.class);
                    startActivity(intent);
                } else {
                    new CenterHintToast(LoginActivity.this, response.msg);
                }
            }
        }, map);
}

二、Retrofit2.0 注解的使用


  • 下面是常用的注解

1帆谍、Get請求

使用@GET注解伪朽,@Query 或 @QueryMap參數(shù)注解,示例:

  @GET("apisiness/inspectTasks/inspectTask")
  Observable<HttpResult.TaskDownResponse> downTask(@QueryMap Map<String, String> options);

2汛蝙、Post請求

使用@POST注解烈涮,@Field 或 @FieldMap參數(shù)注解,示例:

@POST("apisiness/inspectTasks/uploadTask")
Observable<HttpResult.TaskUploadResponse> uploadTask(@FieldMap Map<String, String> options);    
@Multipart
@POST("apisiness/uploadAct/uploadImgs")
Observable<HttpResult.TaskUploadResponse> uploadAdjunct(@FieldMap <String, String> options, @Part() List<MultipartBody.Part> parts);

Post請求還有以下常用的注解:
@Field和FieldMap -- 參數(shù)注解窖剑,用于發(fā)送一個(gè)表單請求坚洽。
@FormUrlEncoded -- 用于修飾Field注解和FieldMap注解,使用該注解,表示請求正文將使用表單網(wǎng)址編碼西土。
@Multipart -- 表示請求體是多部分的讶舰。 每一部分作為一個(gè)參數(shù),且用Part注解聲明。
@Part -- 參數(shù)注解需了,用于定義Multipart請求的每個(gè)part绘雁,參數(shù)值可以為空,為空時(shí),則忽略。
使用該注解定義的參數(shù)類型有以下3種方式可選:

  • 如果類型是okhttp3.MultipartBody.Part援所,內(nèi)容將被直接使用。 省略part中的名稱,即 @Part MultipartBody.Part part 欣除;
  • 如果類型是RequestBody住拭,那么該值將直接與其內(nèi)容類型一起使用。 在注釋中提供part名稱(例如历帚,@Part(“img”)RequestBody img);
  • 其他對象類型將通過使用轉(zhuǎn)換器轉(zhuǎn)換為適當(dāng)?shù)母袷剑ㄈ鐚?shí)體Bean對象的上傳)滔岳。 在注釋中提供part名稱(例如,@Part(“Image ”)Image photo)挽牢。

三谱煤、RxJava處理嵌套請求

這里就要用到RxJava的操作符flatMap了。以下代碼實(shí)現(xiàn)了上傳圖片和設(shè)置用戶頭像的兩個(gè)接口的嵌套使用禽拔,Demo代碼如下:

Map<String, String> options = new HashMap<>();
options.put("type", "userHeadImg");
Map<String, RequestBody> obj = new HashMap<>();
RequestBody photo = RequestBody.create(MediaType.parse("image/png"), os.toByteArray());
obj.put("Imgs\"; filename=\"icon.png",  photo);
RestClient.oapi().oUploadPic(options,obj)
                 .flatMap(new Func1<ReceiveData.OUpPhotoResponse, Observable<ReceiveData.OBaseResponse>>() {
                  @Override
                  public Observable<ReceiveData.OBaseResponse> call(ReceiveData.OUpPhotoResponse oUpPhotoResponse) {
                    thumPath = oUpPhotoResponse.piclist.get(0).getImg_path();
                    Map<String, String> options = new HashMap<>();
                    options.put("method", "updateImg");
                    options.put("userId", 5+"");
                    options.put("headImg",thumPath);
                    return RestClient.omapi().oResetUserImg(options);
                    }
                    })
                 .subscribeOn(Schedulers.io())
                 .observeOn(AndroidSchedulers.mainThread())
                 .subscribe(new Action1<ReceiveData.OBaseResponse>() {
                    @Override
                    public void call(ReceiveData.OBaseResponse oBaseResponse) {
                        if (oBaseResponse.code == 0){
                            showInfo.setText("嵌套請求成功A趵搿室叉!");
                            userimg.setImageURI(RestClient.imgUrl+thumPath);
                        }
                    }
                });

四、攔截器&Basic認(rèn)證

有兩種添加方式硫惕,一種是在每一個(gè)接口中加茧痕;第二種是在攔截器中加。

1恼除、認(rèn)證加密信息

private String username = "$";
private String password = "$";
// basic認(rèn)證信息
String credentials = username + ":" + password;
final String basic = "Basic " + Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP);

2踪旷、在接口中添加認(rèn)證信息

接口傳參時(shí),將上面的加密信息傳遞給接口豁辉,再進(jìn)行調(diào)用即可令野。

 @GET("loginAct/loginByVerifyCode.html")
 Observable<HttpResult.BaseResponse> base(@Header("Authorization") String auth,@QueryMap Map<String, String> options);

3、在攔截器中添加認(rèn)證信息

public class InterceptorUtils{
    //給請求添加一個(gè)頭
    public static Interceptor HeaderInterceptor(final String basic) {
        return new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {
                Request request = chain.request();
                Request.Builder builder = request.newBuilder();
                builder.addHeader("authorization", basic);
                return chain.proceed(builder.build());
            }
        };
    }
}

4徽级、實(shí)際使用

public class HttpMethods {
    private static final int DEFAULT_TIMEOUT = 15;
    public NetworkService networkService;
    private String username = "$";
    private String password = "$";
    // basic認(rèn)證信息
    String credentials = username + ":" + password;
    final String basic = "Basic " + Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP);
    private static HttpMethods httpMethodsods;

    //構(gòu)造方法私有
    private HttpMethods() {
        OkHttpClient httpClient = new OkHttpClient.Builder()
                .addInterceptor(InterceptorUtils.HeaderInterceptor(basic))
                .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
                .readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
                .build();

        //防止修改的url不合理
        try {
            networkService = new Retrofit.Builder()
                    .baseUrl(MyApplication.getInstance().getBaseURL())
                    .addConverterFactory(GsonConverterFactory.create())
                    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                    .client(httpClient)
                    .build()
                    .create(NetworkService.class);
        }catch (Exception e){
            e.printStackTrace();
        }

    }
...

五气破、錯(cuò)誤解決

1、post請求返回400

現(xiàn)象:retrofit2.0 post提交一直返回400,用httpurlconnection就可以

原因:我使用的post方式有問題灰追,雖然我使用了@post標(biāo)識這個(gè)請求堵幽,但是我傳參的地方用錯(cuò)標(biāo)簽了,@QueryMap是用于get請求的傳參標(biāo)簽弹澎,把他換成post的傳參標(biāo)簽@FieldMap就好了朴下。

  • 錯(cuò)誤的使用
    @POST("front/questionnaireResultsAct/resultSave.html")
    Observable<HttpResult.UploadResponse> uploadData(@QueryMap <String, String> options);
  • 正確的使用
    @FormUrlEncoded
    @POST("front/questionnaireResultsAct/resultSave.html")
    Observable<HttpResult.UploadResponse> uploadData(@FieldMap Map<String, String> options);
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市苦蒿,隨后出現(xiàn)的幾起案子殴胧,更是在濱河造成了極大的恐慌,老刑警劉巖佩迟,帶你破解...
    沈念sama閱讀 222,378評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件团滥,死亡現(xiàn)場離奇詭異,居然都是意外死亡报强,警方通過查閱死者的電腦和手機(jī)灸姊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,970評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來秉溉,“玉大人力惯,你說我怎么就攤上這事≌偎唬” “怎么了父晶?”我有些...
    開封第一講書人閱讀 168,983評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長弄跌。 經(jīng)常有香客問我甲喝,道長,這世上最難降的妖魔是什么铛只? 我笑而不...
    開封第一講書人閱讀 59,938評論 1 299
  • 正文 為了忘掉前任埠胖,我火速辦了婚禮糠溜,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘押袍。我一直安慰自己诵冒,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,955評論 6 398
  • 文/花漫 我一把揭開白布谊惭。 她就那樣靜靜地躺著汽馋,像睡著了一般。 火紅的嫁衣襯著肌膚如雪圈盔。 梳的紋絲不亂的頭發(fā)上豹芯,一...
    開封第一講書人閱讀 52,549評論 1 312
  • 那天,我揣著相機(jī)與錄音驱敲,去河邊找鬼铁蹈。 笑死,一個(gè)胖子當(dāng)著我的面吹牛众眨,可吹牛的內(nèi)容都是我干的握牧。 我是一名探鬼主播,決...
    沈念sama閱讀 41,063評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼娩梨,長吁一口氣:“原來是場噩夢啊……” “哼沿腰!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起狈定,我...
    開封第一講書人閱讀 39,991評論 0 277
  • 序言:老撾萬榮一對情侶失蹤颂龙,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后纽什,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體措嵌,經(jīng)...
    沈念sama閱讀 46,522評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,604評論 3 342
  • 正文 我和宋清朗相戀三年芦缰,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了企巢。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,742評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤荣挨,帶...
    沈念sama閱讀 36,413評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站罕容,受9級特大地震影響胳岂,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜找御,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,094評論 3 335
  • 文/蒙蒙 一元镀、第九天 我趴在偏房一處隱蔽的房頂上張望绍填。 院中可真熱鬧,春花似錦栖疑、人聲如沸讨永。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,572評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽卿闹。三九已至,卻和暖如春萝快,著一層夾襖步出監(jiān)牢的瞬間锻霎,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,671評論 1 274
  • 我被黑心中介騙來泰國打工揪漩, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留旋恼,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,159評論 3 378
  • 正文 我出身青樓奄容,卻偏偏與公主長得像冰更,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子昂勒,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,747評論 2 361

推薦閱讀更多精彩內(nèi)容