1. 程式人生 > >Unable to create call adapter for rx.Observable

Unable to create call adapter for rx.Observable

Rxjava+RxAndroid+Retrofit組合時,會出現一個問題,先看log:

Unable to create call adapter for rx.Observable<com.baidu.retrofit.bean.IpInfo>

在build.gradle中中增加一個依賴項即可解決問題:

compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0-beta4'

Retrofit使用時增加addCallAdapterFactory

this.retrofit = new Retrofit.Builder
() .baseUrl(GankApi.BASE_URL) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .addConverterFactory(GsonConverterFactory.create(this.gson)) .client(okHttpClient) .build();

build.gradle中retorfit的版本一定要一致,否則就會出各種問題。

compile 'com.squareup.okhttp3:okhttp:3.2.0'
compile 'com.squareup.retrofit2:retrofit:2.0.0-beta4' compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta4' compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0-beta4' compile 'io.reactivex:rxandroid:1.1.0' compile 'io.reactivex:rxjava:1.1.0'

延伸: Retrofit2.0 中使用問題

從2015 年開始,Retrofit 2.0 雖說一直是 Beta 版本迭代,相對於1.9來說,改動還是相當的大的。

特別提示:

由於2.0的版本中, retrofit:2.0.0-beta2 和 beta3 以後的版本改變較大。包括包名和引用方式,如果要升級的同學請慎重。

改變之處:

  1. OKHttpClient和OKHttpClient3的不同
  2. com.squareup.retrofit和com.squareup.retrofit2的不同
  3. 攔截器新增方法的不同
  4. 內部結構和使用方式的不同等

新增Gradle依賴

retrofit:2.0.0-beta2

compile 'com.squareup.retrofit:retrofit:2.0.0-beta2' // retrofit
compile 'com.google.code.gson:gson:2.5' // gson
compile 'com.squareup.retrofit:converter-gson:2.0.0-beta2' // gson convertor with retrofit
compile 'com.squareup.retrofit:adapter-rxjava:2.0.0-beta2' // rxjava extension with retrofit
compile 'com.squareup.okhttp:logging-interceptor:2.7.0'

retrofit:2.0.0-beta4

compile 'com.squareup.retrofit2:retrofit:2.0.0-beta4' // retrofit
compile 'com.google.code.gson:gson:2.5' // gson
compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta4' 
compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0-beta4' 
compile 'com.squareup.okhttp3:logging-interceptor:3.1.2'
compile 'com.squareup.okhttp3:okhttp:3.1.2'

建立 Retrofit 常規例項

public static Retrofit initRetrofit(){
       OkHttpClient httpClient = new OkHttpClient();
       if (BuildConfig.DEBUG) {
            HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
httpClient = new OkHttpClient.Builder().addInterceptor(logging).build();
        }
        Gson gson = new GsonBuilder()
                .setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
                .create();//使用 gson coverter,統一日期請求格式
        return new Retrofit.Builder()
                .baseUrl(BaseUtil.getGlivecApiUrl())
                .addConverterFactory(GsonConverterFactory.create(gson))
                .client(httpClient)
                .build();
     }

    /**
     * 建立 RetrofitManage 服務
     *
     * @return ApiService
     */
    public static ApiService createApiService() {
        return initRetrofit().create(ApiService.class);
    }

攔截器:

攔截器是應用在不同場合下需要的,比如列印日誌,請求新增標頭檔案。

//注意此處和 beta3 之前的版本寫法不同:
OkHttpClient client =new OkHttpClient.Builder().addInterceptor.(new Interceptor() {  
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request original = chain.request();
        // Customize the request header
        Request request = original.newBuilder()
                .header("Accept", "application/json")
                .header("Authorization", "auth-token")
                .method(original.method(), original.body())
                .build();

        Response response = chain.proceed(request);

        // Customize or return the response 
        return response;
    }
});

轉換器

目前 beta-4 開始支援以下幾種 converter:

Gson: com.squareup.retrofit2:converter-gson
Jackson: com.squareup.retrofit2:converter-jackson
Moshi: com.squareup.retrofit2:converter-moshi
Protobuf: com.squareup.retrofit2:converter-protobuf
Wire: com.squareup.retrofit2:converter-wire
Simple XML: com.squareup.retrofit2:converter-simplexml
Scalars (primitives, boxed, and String): com.squareup.retrofit2:converter-scalars

同步和非同步請求

和1.9不同在2.0 版本中,請求只需要一種寫法

import retrofit.Call
/*Retrofit 2.0*/

public interfase ApiService{
    @POST("/list")
    Call<Repo> loadRepo();

    //支援動態url
    @POST
    Call<Repo> loadRepo(@Url String url);

}

非同步呼叫

Call<Repo> call = service.loadRepo();
call.enqueue(new Callback<Repo>(){
    @Override
    public void onResponse(Response<Repo> response){
        //從response.body()中獲取結果
    }
    @Override
    public void onFailure(Throwable t){

    }
});

同步呼叫

Call<Repo> call = service.loadRepo();
Repo repo = call.excute();

在Android中不能在主執行緒中呼叫,否則會丟擲NetworkOnMainThreadException

取消請求

服務模式變成Call的原因是正在進行中的請求事務可以被取消,只用簡單的使用call.cancel()就可以了。

call.cancel();

特殊需求:

如果在使用的過程中,不需要Gson以及其他轉換器,只是單純的返回 JSONObject,那這樣怎麼處理呢?

通過閱讀原始碼發現,可以通過自定義轉換器的方式操作:

import retrofit.Call
/*Retrofit 2.0*/

public interfase ApiService{
    @POST("/list")
    Call<JSONObject> loadRepo();
}

同步操作:

Call<JSONObject> call = service.loadRepo();
Repo repo = call.excute()

非同步操作:

Call<JSONObject> call = service.loadRepo();
call.enqueue(new Callback<JSONObject>(){
    @Override
    public void onResponse(Response<JSONObject> response){
        //從response.body()中獲取結果
    }
    @Override
    public void onFailure(Throwable t){

    }
});

這樣就完了麼?不。

  1. GsonConverterFactory.create(gson)換成 JsonConverterFactory.create()

程式碼如下:

private static Retrofit initRetrofit() {
        OkHttpClient httpClient = new OkHttpClient();
        if (BuildConfig.DEBUG) {
            HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
            logging.setLevel(HttpLoggingInterceptor.Level.BODY);
            httpClient = new OkHttpClient.Builder().addInterceptor(logging).build();
        }
        return new Retrofit.Builder()
                .baseUrl(BaseUtil.getApiUrl())
                .addConverterFactory(JsonConverterFactory.create())
                .client(httpClient)
                .build();
    }

在最新版本中,retroit預設的網路請求就是用的OkHttpClient,因此,初始化Retrofit下面程式碼就可以了:

mRetrofit = new Retrofit.Builder().baseUrl(url)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .build();

最後再丟擲完整程式碼:

package com.baidu.retrofit;

import android.content.Context;

import retrofit2.Retrofit;
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;

public class RetrofitWrapper {
    private static RetrofitWrapper instance;
    private Context mContext;
    private Retrofit mRetrofit;

    public RetrofitWrapper(String url) {
        mRetrofit = new Retrofit.Builder().baseUrl(url)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .build();
    }

    public  static RetrofitWrapper getInstance(String url){

        if(null == instance){
            synchronized (RetrofitWrapper.class){
                instance = new RetrofitWrapper(url);
            }
        }
        return instance;
    }

    public <T> T create(final Class<T> service) {
        return mRetrofit.create(service);
    }
}