Retrofit2.0和Rxjava結合使用的簡單記錄

Gradle的配置(該配置是針對rxjava1.x的)

compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta4'
    compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0-beta4'
    //okhttp log 工具
    compile 'com.squareup.okhttp3:logging-interceptor:3.1.2'
    compile 'com.google.code.gson:gson:2.5'
    compile 'io.reactivex:rxandroid:1.1.0'
    compile 'io.reactivex:rxjava:1.1.0'
    compile 'com.squareup.retrofit2:retrofit:2.0.0-beta4'

##經常使用的註解php

@Path:該註解寫在方法中的參數類型(String)前面;用於指定@POST()或者@GET()請求中括號中的參數;該參數中不容許存在 斜槓 , 即只能表示一級,相似"目錄"; 能夠把全部的路徑都存在一個類中,在@Post()的括號中引用這個路徑,這樣@Path就不須要使用;除非相同路徑下都是最後一級不相同,可使用該註解。html

@ Url :該註解寫在方法的參數類型前面;表示完整的Url。java

@Query:用於自動拼接URL ?id=3&name=zhangsan&age=24;Post和Get請求中均可以使用react

@QueryMap :傳入一個Map類型,自動拼接URL;Post和Get請求中均可以使用android

@FormUrlEncoded 和Post一塊兒使用;提交沒有文件的表單數據;和參數註解@Field和@FieldMap配合使用git

@ Field:用於POST請求中,輸入拼接的請求體鍵值對;不帶文件上傳的表單提交github

@ FieldMap :用於POST請求中,輸入拼接的請求體鍵值對的Map對象;不帶文件上傳的表單提交json

@Streaming:下載文件必需要加上這個,保證下載的內容不會一會兒都加載到內存中去;表示和服務器是長鏈接,會邊下載流,邊處理(好比寫入存儲器中),使得內存不會有一直持有全部的流數據。api

@Multipart:提交帶有文件的表單使用;配合參數註解@Part和@PartMap使用;@PartMap的類型是 <String,RequestBody>服務器

@Part,@PartMap: 用於POST文件上傳 @PartMap接受的數據類型是HashMap<String,RequestBody> @Part用法:@Part("xxx") RequestBody body

@Body 若是上傳的內容不是用@MultiPart來修飾的,也不是要傳遞鍵值對。參數中不能用@Part或者@PartMap來修飾。此時選擇用@Body;好比傳遞一個json字符串給服務器,此時就須要body,還須要改一下Header

關於文件的上傳: 參見 :http://blog.csdn.net/zhangxing52077/article/details/52830045 文件的下載可使用 RxDownload

@Body:POST請求中的參數

@RequestBody

okhttp3.Media的常見type類型

eg: RequestBody.create(okhttp3.MediaType.parse("application/json; charset=utf-8"), jsonString);

text/html : HTML格式 text/plain :純文本格式
text/xml : XML格式 image/gif :gif圖片格式
image/jpeg :jpg圖片格式 image/png:png圖片格式 以application開頭的媒體格式類型:

application/xhtml+xml :XHTML格式 application/xml : XML數據格式 application/atom+xml :Atom XML聚合格式
application/json : JSON數據格式 application/pdf :pdf格式
application/msword : Word文檔格式 application/octet-stream : 二進制流數據(如常見的文件下載) application/x-www-form-urlencoded : <form encType=」」>中默認的encType,form表單數據被編碼爲key/value格式發送到服務器(表單默認的提交數據的格式)

另一種常見的媒體格式是上傳文件之時使用的: multipart/form-data : 須要在表單中進行文件上傳時,就須要使用該格式

@Headers :註解設置固定的請求頭,全部請求頭不會相互覆蓋,即便名字相同。

@Headers("Cache-Control: max-age=640000")
@GET("widget/list")
Call<List<Widget>> widgetList();
// 注意Headers括號中的鍵值對,冒號後面有一個空格!!!!
@Headers({ "Accept: application/vnd.github.v3.full+json","User-Agent: Retrofit-Sample-App"})
@GET("users/{username}")Call<User> getUser(@Path("username") String username);

@Header 使用 @Header 註解動態更新請求頭,匹配的參數必須提供給 @Header ,若參數值爲 null ,這個頭會被省略,不然,會使用參數值的 toString 方法的返回值。

@GET("user")
Call<User> getUser(@Header("Authorization") String authorization)

獲取Retrofit的實例

public class RetrofitClient {

    private static final String TAG = "RetrofitClient";

//    private static final String BASE_URL ="https://api.douban.com/v2/movie/";

    private static OkHttpClient client = new OkHttpClient.Builder()
            .addInterceptor(new Interceptor() {
                @Override
                public Response intercept(Chain chain) throws IOException {
//                    Log.v(TAG,chain.connection().route().address().toString());
                    Log.v(TAG,chain.request().url().toString());
                    Request.Builder builder = chain.request().newBuilder();
                    //添加共同的頭信息
//                    builder.addHeader("token", "abc");
                    return chain.proceed(builder.build());
                }
            })
            .connectTimeout(15, TimeUnit.SECONDS)
            .readTimeout(15, TimeUnit.SECONDS)
            .build();


    private static class Holder{
        private static Retrofit retrofit = new Retrofit.Builder()
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .addConverterFactory(StringConverterFactory.create())
                .baseUrl(UrlConst.BASE_URL)
                .client(client)
                .build();
    }


    public static Retrofit getRetrofitInstance() {
        return Holder.retrofit;
    }

    private static Retrofit retrofit2;

    public static Retrofit getStringRetrofitInstance(String url) {

        retrofit2 = new Retrofit.Builder()
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .addConverterFactory(StringConverterFactory.create())
                .baseUrl(url)
                .client(client)
                .build();
        return retrofit2;
    }

    public static Retrofit retrofit3;

    public static Retrofit getRetrofitInstance(String url)
    {
        retrofit3 = new Retrofit.Builder()
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .addConverterFactory(StringConverterFactory.create())
                .baseUrl(url)
                .client(client)
                .build();
        return retrofit3;
    }
}

建立Service的接口

GET請求

//具體的網絡url : 舉例子:https://api.douban.com/v2/movie/top250?start=2&count=4
public interface ApiService {

    @GET("top250")
    Observable<Entity> getMovies(@Query("start") int start,@Query("count") int count);
}
// 最好這麼寫,參數用變量代替
public interface ApiService {

    @GET("{url}")
    Observable<Entity> getMovies(@Path("url") String url, @Query("start") int start, @Query("count") int count);
}

POST請求

public interface MovieService { 
        //獲取豆瓣Top250 榜單 
       @FormUrlEncoded
       @POST("top250") 
       Observable<MovieSubject> getTop250(@Field("start") int start, @Field("count") int count);
}

關於Post請求須要注意的幾個地方:
必需要有@FormUrlEncoded 配合 Filed使用時

下載文件的GET請求

//必需要加上@Streaming,否則會把下載的東西所有讀到內存中去
    @Streaming
    @GET
    Observable<ResponseBody> downloadFile(@Url String url);

寫入ReponseBody到文件系統

/**
     * 將ResponseBody中的內容保存到本地路徑 ;該路徑必須已經存在
     *
     * @param body
     * @param localPath
     */
    public static void writeResponseBodyToDisk(ResponseBody body, String localPath) {
        File file = new File(localPath);

        InputStream is = null;

        OutputStream os = null;

        long totalLength = body.contentLength();
        long currentLength = 0;
        double rate = 0;

        byte[] bytes = new byte[4096];


        try {
            os = new FileOutputStream(file);
            is = body.byteStream();
            int length = -1;
            while ((length = is.read(bytes)) != -1) {
                os.write(bytes, 0, length);
                currentLength += length;
                rate = currentLength * 1.0 / totalLength;
            }

            os.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {

            try {
                if (is != null) {
                    is.close();
                }

                if (os != null) {
                    os.close();
                }

            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

踩過的坑:

1.Post請求中

//獲取 任務
    @POST("index.php/machine/{url}")
    Observable<String> getTask(@Path("url") String url, @Body RequestBody requestBody);

註解Post的括號中若是有引用方法的url時,那麼方法中的url不能包括斜槓 / ,也不能包括問號 ? 由於斜槓 / 會被轉義爲 %2F ; ? 會被轉義爲 %3F ;斜槓和問號只有寫在@POST的括號中才不會被轉義。

2.Post請求上傳多個文件和其餘字符串參數 文件上傳能夠用兩種方式來作: 1.使用MultipartBody.Part 類型修飾在函數的文件參數前面;文件的參數和字符串參數分開來作;字符串參數能夠用@PartMap來包裹

RequestBody apkBody = RequestBody.create(MediaType.parse("multipart/form-data"),file_apk);
  MultipartBody.Part partApk = MultipartBody.Part.createFormData("apk_url",file_apk.getName(),apkBody);

2.(用的少)使用@PartMap註解修飾參數類型前面 , 上傳多個文件,可是對建立文件的RequestBody作一步處理;這種方式實際上是把多個文件和字符串都放在@PartMap修飾的HasMap<String,RequestBody>中即:

RequestBody requestBody = RequestBody.create(MediaType.parse("multipart/form-data"), file);
 RequestBody requestBody1 = RequestBody.create(MediaType.parse("multipart/form-data"), file1);
 Map<String, RequestBody> params = new HashMap<>();

 params.put(key+"\"; filename=\""+ file.getName(), requestBody);
 params.put(key1+"\"; filename=\""+ file1.getName(), requestBody1);

3.若是服務器返回值不是一個json,而是一個字符串String。那麼咱們用的GsonConvertory的Retrofit就不可用了。須要自定義一個StringConvertory.

  1. 這種上傳方式沒有嘗試過:
MultipartBody.Part photo1part = 
            MultipartBody.Part.createFormData("pic1", "pic2", requestBody1);
@Multipart
    @POST("upload.php")
    Observable<ResponseBody> uploadFile(
         @Part() List<MultipartBody.Part > files );

5.文件和參數同時上傳的時候會遇到參數的value若是是String,會有兩個雙引號在外面。緣由是因爲使用了 Map<String,String>的方式,可使用Map<String,RequestBody>的方式來解決這個問題。

相關文章
相關標籤/搜索