Retrofit2學習番外——自定義Converter與CallAdapter

一個暱稱而已T發表於2017-03-16

在自己擼了一遍自定義Converter與CallAdapter之後,終於有了一點了解,即使是侷限與使用階段。(另外本次的Demo參考了Retrofit2 探索

原始碼地址:https://github.com/374901588/Retrofit2Demo.git
(注意:用於演示的Demo就是簡單的把請求的結果set到TextView上了,沒有做其他處理了)

用於測試的資料格式如下:
這裡寫圖片描述

Contributor.java為自定義的對應於上述資料的實體類,其中只包含login、id、contributions三個屬性。


1、首先是自定義Converter,我在這裡模仿實現了GsonConverter的功能,即在Demo中將Call<ResponseBody>轉換為Call<List<Contributor>>。主要程式碼如下:

private static class CustomConverter implements Converter<ResponseBody,List<Contributor>> {
        public static final CustomConverter INSTANCE=new CustomConverter();

        @Override
        public List<Contributor> convert(ResponseBody value) throws IOException {
            List<Contributor> list=new Gson().fromJson(value.string(),new TypeToken<List<Contributor>>(){}.getType());
            return list;
        }
    }

    public static class CustomConverterFactory extends Converter.Factory {
        public static final CustomConverterFactory INSTANCE = new CustomConverterFactory();

        public static CustomConverterFactory create() {
            return INSTANCE;
        }

        // 我們只關心從ResponseBody 到 List<Contributor>> 的轉換,所以其它方法可不覆蓋
        @Override
        public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
            //不能直接用type==new TypeToken<List<Contributor>>(){}.getType()),將會得到false
            //因為==是用於判斷兩個引用變數是否相等,但是這裡的==右邊是new的一個新的,所以肯定是“不==”的
            Log.d("測試---》",""+(type==new TypeToken<List<Contributor>>(){}.getType()));
            if (type.equals(new TypeToken<List<Contributor>>(){}.getType())) {
                return CustomConverter.INSTANCE;
            }
            //其它型別我們不處理,返回null就行
            return null;
        }
    }

2、接著是實現自定義的CallAdapter,這裡是模仿實現RxJavaCallAdapter的功能,即在Demo中將Call<List<Contributor>>轉換為Observable<List<Contributor>>。主要程式碼如下:

public static class CustomCallAdapter implements CallAdapter<List<Contributor>,Observable<List<Contributor>>> {
        private final Type responseType;

        CustomCallAdapter(Type type) {
            responseType=type;
        }

        @Override
        public Type responseType() {
            return responseType;
        }

        @Override
        public Observable<List<Contributor>> adapt(Call<List<Contributor>> call) {
            Log.d("測試-----5","responseType="+responseType);
            try {
                List<Contributor> contributorList=call.execute().body();
                return Observable.just(contributorList);
            } catch (IOException e) {
                Log.e("異常",e.getMessage());
            }
            return null;
        }
    }

    public static class CustomCallAdapterFactory extends CallAdapter.Factory {
        public static final CustomCallAdapterFactory INSTANCE=new CustomCallAdapterFactory();

        /**
         * returnType為需要轉換的目標型別(原始型別),比如在本例中,需要轉換為Observable<List<Contributor>>,所以returnType就為其原始型別,即Observable.class對應的型別
         */
        @Override
        public CallAdapter<?,?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
            Class<?> rawType=getRawType(returnType);//提取returnType的原始類型別,例如,表示List <?擴充套件Runnable>返回List.class
            //因此在對比的時候我們只要rawType==Observable.class,而不是與new TypeToken<Observable<List<Contributor>>>(){}.getType()對比
            if (rawType==Observable.class&&returnType instanceof ParameterizedType) {
                Type callReturnType=getParameterUpperBound(0,(ParameterizedType)returnType);
                return new CustomCallAdapter(callReturnType);
            }
            return null;
        }
    }

由於本人能力有限,不能模仿得像原本的那麼厲害,且迫於時間緊張,無心去分析原始碼,所以這裡只是簡易的實現功能。且需要注意執行contributors3()方法時需要在子執行緒中,因為在CustomCallAdapteradapt()方法中有執行call.execute(),這會用於網路請求,如果執行contributors3()方法時需要不在子執行緒中就會出現android.os.NetworkOnMainThreadException

相關文章