Rxjava, RxAndroid, Retrofit 等庫的使用

RxJava 是他們的基礎組件,RxAndroid, Retrofit, RxCache等等都要用到它。javascript

 

RxJava的基本用法:css

關於 unSubscribe() 的調用問題:html

There is no need to unsubscribe in onCompleted. Take a look at The Observable Contractjava

When an Observable issues an OnError or OnComplete notification to its observers, this ends the subscription. Observers do not need to issue an Unsubscribe notification to end subscriptions that are ended by the Observable in this way.react

On the other hand, you definitely should unsubscribe in onDestroy in order to prevent memory leaks.android

上面的話可知,若是你調用過 subscriber.OnError() 或者 subscriber.OnComplete(),則就不須要調用unSubscribe()了,由於它會自動調用unSubscribe()。 但強烈建議在界面消失的 onDestroy() 裏調用 unSubscribe()來手動的將 subscription 註銷掉,由於有些時候界面退出時,subscriber.OnError 或者 subscriber.OnComplete還沒來得及執行。git

 

 

一個例子

RxJava的強大之處,在於它提供了很是豐富且功能強悍的操做符,經過使用和組合這些操做符,你幾乎能完成全部你想要完成的任務,舉個例子以下:github

如今有一個需求:app啓動時顯示一張圖片(通常是app的logo),也就是咱們所說的歡迎頁,2-3秒後自動跳轉到主頁面。這不就是幾乎每一個app都有的啓動頁需求嗎?幾乎不用思考,代碼以下:sql

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_welcome);

        ImageView view = (ImageView) findViewById(R.id.iv_welcome);
        view.setImageResource(R.drawable.welcome);
        Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                startActivity(new Intent(WelcomeActivity.this, MainActivity.class));
                finish();
            }
        },2000);
    }

使用RxJava的代碼實現以下:json

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_welcome);

        ImageView view = (ImageView) findViewById(R.id.iv_welcome);
        view.setImageResource(R.drawable.welcome);
        Observable.timer(2, TimeUnit.SECONDS, AndroidSchedulers.mainThread()).map(l->{
            startActivity(new Intent(this, MainActivity.class));
            finish();
            return null;
        }).subscribe();
    }

操做符分類

經過上面的例子,你們應該看到了RxJava操做符的威力,下面我按類別把經常使用操做符分別介紹,其實不少內容都是來自於ReactiveX的官方網站,英文比較好的朋友能夠參考(http://reactivex.io/)。
按照官方的分類,操做符大體分爲如下幾種:

  • Creating            Observables(Observable的建立操做符),好比:Observable.create()、Observable.just()、Observable.from()等等;
  • Transforming      Observables(Observable的轉換操做符),好比:observable.map()、observable.flatMap()、observable.buffer()等等;
  • Filtering         Observables(Observable的過濾操做符),好比:observable.filter()、observable.sample()、observable.take()等等;
  • Combining         Observables(Observable的組合操做符),好比:observable.join()、observable.merge()、observable.combineLatest()等等;
  • Error Handling Operators(Observable的錯誤處理操做符),好比:observable.onErrorResumeNext()、observable.retry()等等;
  • Observable Utility Operators(Observable的功能性操做符),好比:observable.subscribeOn()、observable.observeOn()、observable.delay()等等;
  • Conditional and Boolean Operators(Observable的條件操做符),好比:observable.amb()、observable.contains()、observable.skipUntil()等等;
  • Mathematical and Aggregate Operators(Observable數學運算及聚合操做符),好比:observable.count()、observable.reduce()、observable.concat()等等;
  • 其餘如observable.toList()、observable.connect()、observable.publish()等等;

defer操做符

defer操做符是直到有訂閱者訂閱時,才經過Observable的工廠方法建立Observable並執行,defer操做符可以保證Observable的狀態是最新的,其流程實例以下:

下面經過比較defer操做符和just操做符的運行結果做比較:

  i=10;
        Observable justObservable = Observable.just(i);
        i=12;
        Observable deferObservable = Observable.defer(new Func0<Observable<Object>>() {
            @Override
            public Observable<Object> call() {
                return Observable.just(i);
            }
        });
        i=15;

        justObservable.subscribe(new Subscriber() {
            @Override
            public void onCompleted() {

            }

            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onNext(Object o) {
                System.out.println("just result:" + o.toString());
            }
        });

        deferObservable.subscribe(new Subscriber() {
            @Override
            public void onCompleted() {

            }

            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onNext(Object o) {
                System.out.println("defer result:" + o.toString());
            }
        });
   }

其中i是類的成員變量,運行結果以下:
just result:10
defer result:15

能夠看到,just操做符是在建立Observable就進行了賦值操做,而defer是在訂閱者訂閱時才建立Observable,此時才進行真正的賦值操做

timer操做符

timer操做符是建立一串連續的數字,產生這些數字的時間間隔是必定的;這裏有兩種狀況:

一種是隔一段時間產生一個數字,而後就結束,能夠理解爲延遲產生數字,其流程實例以下:

一種是每隔一段時間就產生一個數字,沒有結束符,也就是是能夠產生無限個連續的數字,其流程實例以下:

timer操做符默認狀況下是運行在一個新線程上的,固然你能夠經過傳入參數來修改其運行的線程。
下面是調用例子:

//每隔兩秒產生一個數字
        Observable.timer(2, 2, TimeUnit.SECONDS).subscribe(new Subscriber<Long>() {
            @Override
            public void onCompleted() {
                System.out.println("Sequence complete.");
            }

            @Override
            public void onError(Throwable e) {
                System.out.println("error:" + e.getMessage());
            }

            @Override
            public void onNext(Long aLong) {
                System.out.println("Next:" + aLong.toString());
            }
        });

運行結果以下:
Next:0
Next:1
Next:2
Next:3
……

interval操做符

interval操做符是每隔一段時間就產生一個數字,這些數字從0開始,一次遞增1直至無窮大;interval操做符的實現效果跟上面的timer操做符的第二種情形同樣。如下是流程實例:

interval操做符默認狀況下是運行在一個新線程上的,固然你能夠經過傳入參數來修改其運行的線程。

調用例子就不列出了,基本跟上面timer的調用例子同樣。

repeat/repeatWhen操做符

repeat操做符是對某一個Observable,重複產生屢次結果,其流程實例以下:

 

 

 

 

 

 

 

Retrofit用法詳解

Retrofit是Square公司開發的一款針對Android網絡請求的框架,Retrofit2底層基於OkHttp實現的,OkHttp如今已經獲得Google官方承認,大量的app都採用OkHttp作網絡請求,其源碼詳見 OkHttp Github

本文所有是在Retrofit2.0+版本基礎上論述,所用例子所有來自豆瓣Api

首先先來看一個完整Get請求是如何實現:

  1. 建立業務請求接口,具體代碼以下:

    public interface BlueService { @GET("book/search") Call<BookSearchResponse> getSearchBooks(@Query("q") String name, @Query("tag") String tag, @Query("start") int start, @Query("count") int count); } 

    這裏須要稍做說明,@GET註解就表示get請求,@Query表示請求參數,將會以key=value的方式拼接在url後面

  2. 須要建立一個Retrofit的示例,並完成相應的配置

    Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("https://api.douban.com/v2/")
        .addConverterFactory(GsonConverterFactory.create()) .build(); BlueService service = retrofit.create(BlueService.class); 

    這裏的baseUrl就是網絡請求URL相對固定的地址,通常包括請求協議(如Http)、域名或IP地址、端口號等,固然還會有不少 其餘的配置,下文會詳細介紹。還有addConverterFactory方法表示須要用什麼轉換器來解析返回 值,GsonConverterFactory.create()表示調用Gson庫來解析json返回值,具體的下文還會作詳細介紹。

  3. 調用請求方法,並獲得Call實例

    Call<BookSearchResponse> call = mBlueService.getSearchBooks("小王子", "", 0, 3); 

    Call其實在Retrofit中就是行使網絡請求並處理返回值的類,調用的時候會把須要拼接的參數傳遞進去,此處最後獲得的url完整地址爲

    https://api.douban.com/v2/book/search?q=%E5%B0%8F%E7%8E%8B%E5%AD%90&tag=&start=0&count=3

  4. 使用Call實例完成同步或異步請求

    • 同步請求

      BookSearchResponse response = call.execute().body(); 

      這裏須要注意的是網絡請求必定要在子線程中完成,不能直接在UI線程執行,否則會crash

    • 異步請求

      call.enqueue(new Callback<BookSearchResponse>() { @Override public void onResponse(Call<BookSearchResponse> call, Response<BookSearchResponse> response) { asyncText.setText("異步請求結果: " + response.body().books.get(0).altTitle); } @Override public void onFailure(Call<BookSearchResponse> call, Throwable t) { } }); 

2、如何使用

首先須要在build.gradle文件中引入須要的第三包,配置以下:

compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'

引入完第三包接下來就可使用Retrofit來進行網絡請求了。接下來會對不一樣的請求方式作進一步的說明。

Get方法

1. @Query

Get方法請求參數都會以key=value的方式拼接在url後面,Retrofit提供了兩種方式設置請求參數。第一種就是像上文提到的直 接在interface中添加@Query註解,還有一種方式是經過Interceptor實現,直接看如何經過Interceptor實現請求參數的添 加。

public class CustomInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); HttpUrl httpUrl = request.url().newBuilder() .addQueryParameter("token", "tokenValue") .build(); request = request.newBuilder().url(httpUrl).build(); return chain.proceed(request); } } 

addQueryParameter就是添加請求參數的具體代碼,這種方式比較適用於全部的請求都須要添加的參數,通常如今的網絡請求都會添加token做爲用戶標識,那麼這種方式就比較適合。

建立完成自定義的Interceptor後,還須要在Retrofit建立client處完成添加

addInterceptor(new CustomInterceptor())

2. @QueryMap

若是Query參數比較多,那麼能夠經過@QueryMap方式將全部的參數集成在一個Map統一傳遞,還以上文中的get請求方法爲例

public interface BlueService {
    @GET("book/search")
    Call<BookSearchResponse> getSearchBooks(@QueryMap Map<String, String> options); } 

調用的時候將全部的參數集合在統一的map中便可

Map<String, String> options = new HashMap<>(); map.put("q", "小王子"); map.put("tag", null); map.put("start", "0"); map.put("count", "3"); Call<BookSearchResponse> call = mBlueService.getSearchBooks(options); 

3. Query集合

假如你須要添加相同Key值,可是value卻有多個的狀況,一種方式是添加多個@Query參數,還有一種簡便的方式是將全部的value放置在列表中,而後在同一個@Query下完成添加,實例代碼以下:

public interface BlueService {
    @GET("book/search")
    Call<BookSearchResponse> getSearchBooks(@Query("q") List<String> name); } 

最後獲得的url地址爲

https://api.douban.com/v2/book/search?q=leadership&q=beyond%20feelings 

4. Query非必填

若是請求參數爲非必填,也就是說即便不傳該參數,服務端也能夠正常解析,那麼如何實現呢?其實也很簡單,請求方法定義處仍是須要完整的Query註解,某次請求若是不須要傳該參數的話,只需填充null便可。

針對文章開頭提到的get的請求,加入按如下方式調用

Call<BookSearchResponse> call = mBlueService.getSearchBooks("小王子", null, 0, 3); 

那麼獲得的url地址爲

https://api.douban.com/v2/book/search?q=%E5%B0%8F%E7%8E%8B%E5%AD%90&start=0&count=3 

5. @Path

若是請求的相對地址也是須要調用方傳遞,那麼可使用@Path註解,示例代碼以下:

@GET("book/{id}") Call<BookResponse> getBook(@Path("id") String id); 

業務方想要在地址後面拼接書籍id,那麼經過Path註解能夠在具體的調用場景中動態傳遞,具體的調用方式以下:

Call<BookResponse> call = mBlueService.getBook("1003078"); 

此時的url地址爲

https://api.douban.com/v2/book/1003078

@Path能夠用於任何請求方式,包括Post,Put,Delete等等

Post請求

1. @field

Post請求須要把請求參數放置在請求體中,而非拼接在url後面,先來看一個簡單的例子

@FormUrlEncoded
@POST("book/reviews") Call<String> addReviews(@Field("book") String bookId, @Field("title") String title, @Field("content") String content, @Field("rating") String rating); 

這裏有幾點須要說明的

  • @FormUrlEncoded將會自動將請求參數的類型調整爲application/x-www-form-urlencoded,假如content傳遞的參數爲Good Luck,那麼最後獲得的請求體就是

    content=Good+Luck 

    FormUrlEncoded不能用於Get請求

  • @Field註解將每個請求參數都存放至請求體中,還能夠添加encoded參數,該參數爲boolean型,具體的用法爲

    @Field(value = "book", encoded = true) String book 

    encoded參數爲true的話,key-value-pair將會被編碼,即將中文和特殊字符進行編碼轉換

2. @FieldMap

上述Post請求有4個請求參數,假如說有更多的請求參數,那麼經過一個一個的參數傳遞就顯得很麻煩並且容易出錯,這個時候就能夠用FieldMap

@FormUrlEncoded
@POST("book/reviews")
Call<String> addReviews(@FieldMap Map<String, String> fields); 

3. @Body

若是Post請求參數有多個,那麼統一封裝到類中應該會更好,這樣維護起來會很是方便

@FormUrlEncoded
@POST("book/reviews") Call<String> addReviews(@Body Reviews reviews); public class Reviews { public String book; public String title; public String content; public String rating; } 

其餘請求方式

除了Get和Post請求,Http請求還包括Put,Delete等等,用法和Post類似,因此就再也不單獨介紹了。

上傳

上傳由於須要用到Multipart,因此須要單獨拿出來介紹,先看一個具體上傳的例子

首先仍是須要新建一個interface用於定義上傳方法

public interface FileUploadService { // 上傳單個文件 @Multipart @POST("upload") Call<ResponseBody> uploadFile( @Part("description") RequestBody description, @Part MultipartBody.Part file); // 上傳多個文件 @Multipart @POST("upload") Call<ResponseBody> uploadMultipleFiles( @Part("description") RequestBody description, @Part MultipartBody.Part file1, @Part MultipartBody.Part file2); } 

接下來咱們還須要在Activity和Fragment中實現兩個工具方法,代碼以下:

public static final String MULTIPART_FORM_DATA = "multipart/form-data"; @NonNull private RequestBody createPartFromString(String descriptionString) { return RequestBody.create( MediaType.parse(MULTIPART_FORM_DATA), descriptionString); } @NonNull private MultipartBody.Part prepareFilePart(String partName, Uri fileUri) { File file = FileUtils.getFile(this, fileUri); // 爲file創建RequestBody實例 RequestBody requestFile = RequestBody.create(MediaType.parse(MULTIPART_FORM_DATA), file); // MultipartBody.Part藉助文件名完成最終的上傳 return MultipartBody.Part.createFormData(partName, file.getName(), requestFile); } 

好了,接下來就是最終的上傳文件代碼了

Uri file1Uri = ... // 從文件選擇器或者攝像頭中獲取 
Uri file2Uri = ... 

// 建立上傳的service實例
FileUploadService service =  
        ServiceGenerator.createService(FileUploadService.class);

// 建立文件的part (photo, video, ...)
MultipartBody.Part body1 = prepareFilePart("video", file1Uri);  
MultipartBody.Part body2 = prepareFilePart("thumbnail", file2Uri);

// 添加其餘的part
RequestBody description = createPartFromString("hello, this is description speaking");

// 最後執行異步請求操做
Call<ResponseBody> call = service.uploadMultipleFiles(description, body1, body2); call.enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { Log.v("Upload", "success"); } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { Log.e("Upload error:", t.getMessage()); } }); 

3、其餘必須知道的事項

1. 添加自定義的header

Retrofit提供了兩個方式定義Http請求頭參數:靜態方法和動態方法,靜態方法不能隨不一樣的請求進行變化,頭部信息在初始化的時候就固定了。而動態方法則必須爲每一個請求都要單獨設置。

  • 靜態方法

    public interface BlueService {  @Headers("Cache-Control: max-age=640000") @GET("book/search") Call<BookSearchResponse> getSearchBooks(@Query("q") String name, @Query("tag") String tag, @Query("start") int start, @Query("count") int count); } 

    固然你想添加多個header參數也是能夠的,寫法也很簡單

    public interface BlueService {  @Headers({ "Accept: application/vnd.yourapi.v1.full+json", "User-Agent: Your-App-Name" }) @GET("book/search") Call<BookSearchResponse> getSearchBooks(@Query("q") String name, @Query("tag") String tag, @Query("start") int start, @Query("count") int count); } 

    此外也能夠經過Interceptor來定義靜態請求頭

    public class RequestInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { Request original = chain.request(); Request request = original.newBuilder() .header("User-Agent", "Your-App-Name") .header("Accept", "application/vnd.yourapi.v1.full+json") .method(original.method(), original.body()) .build(); return chain.proceed(request); } } 

    添加header參數Request提供了兩個方法,一個是 header(key, value) ,另外一個是 .addHeader(key, value) ,二者的區別是,header()若是有重名的將會覆蓋,而addHeader()容許相同key值的header存在

    而後在OkHttp建立Client實例時,添加RequestInterceptor便可

    private static OkHttpClient getNewClient(){ return new OkHttpClient.Builder() .addInterceptor(new RequestInterceptor()) .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS) .build(); } 
  • 動態方法

    public interface BlueService { @GET("book/search") Call<BookSearchResponse> getSearchBooks( @Header("Content-Range") String contentRange, @Query("q") String name, @Query("tag") String tag, @Query("start") int start, @Query("count") int count); } 

2. 網絡請求日誌

調試網絡請求的時候常常須要關注一下請求參數和返回值,以便判斷和定位問題出在哪裏,Retrofit官方提供了一個很方便查看日誌的Interceptor,你能夠控制你須要的打印信息類型,使用方法也很簡單。

首先須要在build.gradle文件中引入logging-interceptor

compile 'com.squareup.okhttp3:logging-interceptor:3.4.1'

同上文提到的CustomInterceptor和RequestInterceptor同樣,添加到OkHttpClient建立處便可,完整的示例代碼以下:

private static OkHttpClient getNewClient(){ HttpLoggingInterceptor logging = new HttpLoggingInterceptor(); logging.setLevel(HttpLoggingInterceptor.Level.BODY); return new OkHttpClient.Builder() .addInterceptor(new CustomInterceptor()) .addInterceptor(logging) .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS) .build(); } 

HttpLoggingInterceptor提供了4中控制打印信息類型的等級,分別是NONE,BASIC,HEADERS,BODY,接下來分別來講一下相應的打印信息類型。

  • NONE

    沒有任何日誌信息

  • Basic

    打印請求類型,URL,請求體大小,返回值狀態以及返回值的大小

    D/HttpLoggingInterceptor$Logger: --> POST /upload HTTP/1.1 (277-byte body) D/HttpLoggingInterceptor$Logger: <-- HTTP/1.1 200 OK (543ms, -1-byte body)
  • Headers

    打印返回請求和返回值的頭部信息,請求類型,URL以及返回值狀態碼

    <-- 200 OK https://api.douban.com/v2/book/search?q=%E5%B0%8F%E7%8E%8B%E5%AD%90&start=0&count=3&token=tokenValue (3787ms) D/OkHttp: Date: Sat, 06 Aug 2016 14:26:03 GMT D/OkHttp: Content-Type: application/json; charset=utf-8 D/OkHttp: Transfer-Encoding: chunked D/OkHttp: Connection: keep-alive D/OkHttp: Keep-Alive: timeout=30 D/OkHttp: Vary: Accept-Encoding D/OkHttp: Expires: Sun, 1 Jan 2006 01:00:00 GMT D/OkHttp: Pragma: no-cache D/OkHttp: Cache-Control: must-revalidate, no-cache, private D/OkHttp: Set-Cookie: bid=D6UtQR5N9I4; Expires=Sun, 06-Aug-17 14:26:03 GMT; Domain=.douban.com; Path=/ D/OkHttp: X-DOUBAN-NEWBID: D6UtQR5N9I4 D/OkHttp: X-DAE-Node: dis17 D/OkHttp: X-DAE-App: book D/OkHttp: Server: dae D/OkHttp: <-- END HTTP 
  • Body

    打印請求和返回值的頭部和body信息

    <-- 200 OK https://api.douban.com/v2/book/search?q=%E5%B0%8F%E7%8E%8B%E5%AD%90&tag=&start=0&count=3&token=tokenValue (3583ms) D/OkHttp: Connection: keep-alive D/OkHttp: Date: Sat, 06 Aug 2016 14:29:11 GMT D/OkHttp: Keep-Alive: timeout=30 D/OkHttp: Content-Type: application/json; charset=utf-8 D/OkHttp: Vary: Accept-Encoding D/OkHttp: Expires: Sun, 1 Jan 2006 01:00:00 GMT D/OkHttp: Transfer-Encoding: chunked D/OkHttp: Pragma: no-cache D/OkHttp: Connection: keep-alive D/OkHttp: Cache-Control: must-revalidate, no-cache, private D/OkHttp: Keep-Alive: timeout=30 D/OkHttp: Set-Cookie: bid=ESnahto1_Os; Expires=Sun, 06-Aug-17 14:29:11 GMT; Domain=.douban.com; Path=/ D/OkHttp: Vary: Accept-Encoding D/OkHttp: X-DOUBAN-NEWBID: ESnahto1_Os D/OkHttp: Expires: Sun, 1 Jan 2006 01:00:00 GMT D/OkHttp: X-DAE-Node: dis5 D/OkHttp: Pragma: no-cache D/OkHttp: X-DAE-App: book D/OkHttp: Cache-Control: must-revalidate, no-cache, private D/OkHttp: Server: dae D/OkHttp: Set-Cookie: bid=5qefVyUZ3KU; Expires=Sun, 06-Aug-17 14:29:11 GMT; Domain=.douban.com; Path=/ D/OkHttp: X-DOUBAN-NEWBID: 5qefVyUZ3KU D/OkHttp: X-DAE-Node: dis17 D/OkHttp: X-DAE-App: book D/OkHttp: Server: dae D/OkHttp: {"count":3,"start":0,"total":778,"books":[{"rating":{"max":10,"numRaters":202900,"average":"9.0","min":0},"subtitle":"","author":["[法] 聖埃克蘇佩裏"],"pubdate":"2003-8","tags":[{"count":49322,"name":"小王子","title":"小王子"},{"count":41381,"name":"童話","title":"童話"},{"count":19773,"name":"聖埃克蘇佩裏","title":"聖埃克蘇佩裏"} D/OkHttp: <-- END HTTP (13758-byte body) 

3. 爲某個請求設置完整的URL

​ 假如說你的某一個請求不是以base_url開頭該怎麼辦呢?彆着急,辦法很簡單,看下面這個例子你就懂了

public interface BlueService { @GET public Call<ResponseBody> profilePicture(@Url String url); } Retrofit retrofit = Retrofit.Builder() .baseUrl("https://your.api.url/"); .build(); BlueService service = retrofit.create(BlueService.class); service.profilePicture("https://s3.amazon.com/profile-picture/path"); 

​ 直接用@Url註解的方式傳遞完整的url地址便可。

4. 取消請求

Call提供了cancel方法能夠取消請求,前提是該請求尚未執行

String fileUrl = "http://futurestud.io/test.mp4";  
Call<ResponseBody> call = downloadService.downloadFileWithDynamicUrlSync(fileUrl); call.enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { Log.d(TAG, "request success"); } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { if (call.isCanceled()) { Log.e(TAG, "request was cancelled"); } else { Log.e(TAG, "other larger issue, i.e. no network connection?"); } } }); } // 觸發某個動做,例如用戶點擊了取消請求的按鈕 call.cancel(); } 

4、結語

關於Retrofit經常使用的方法基本上已經介紹完了,有些請求因爲工做保密性的緣由,因此就沒有放出來,可是基本的方法和操做都是有的,仿照文中提到的代碼就能夠實現你想要的功能。參考了 國外的一則系列教程 liangfei的一篇文章 圖解 Retrofit - ServiceMethod ,因爲本人能力有限,有錯誤或者表述不許確的地方還望多多留言指正

相關文章
相關標籤/搜索