1. 程式人生 > >Retrofit網路請求,工具類的封裝

Retrofit網路請求,工具類的封裝

對於Retrofit的使用我就不介紹了,使用也不難,隨便去搜兩篇文章看看。
我主要介紹的就是如何封裝,簡便使用。

一、Retrofit工具類的封裝(核心類)

 /**
 * Retrofit工具類
 */
public class RetrofitUtils {
    public static final String BASE_URL = "http://XXX";
    /**
     * 超時時間
     */
    public static final int TIMEOUT = 60;
    private static volatile RetrofitUtils mInstance;
    private Retrofit mRetrofit;

    public static RetrofitUtils getInstance() {
        if (mInstance == null) {
            synchronized (RetrofitUtils.class) {
                if (mInstance == null) {
                    mInstance = new RetrofitUtils();
                }
            }
        }
        return mInstance;
    }

    private RetrofitUtils() {
        initRetrofit();
    }

    /**
     * 初始化Retrofit
     */
    private void initRetrofit() {
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        // 設定超時
        builder.connectTimeout(TIMEOUT, TimeUnit.SECONDS);
        builder.readTimeout(TIMEOUT, TimeUnit.SECONDS);
        builder.writeTimeout(TIMEOUT, TimeUnit.SECONDS);
        OkHttpClient client = builder.build();
        mRetrofit = new Retrofit.Builder()
                // 設定請求的域名
                .baseUrl(BASE_URL)
                // 設定解析轉換工廠,用自己定義的
                .addConverterFactory(ResponseConvert.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .client(client)
                .build();
    }

    /**
     * 建立API
     */
    public <T> T create(Class<T> clazz) {
        return mRetrofit.create(clazz);
    }
}

程式碼很簡單,建立後臺請求介面,呼叫create即可。

二、Converter.Factory的封裝

自己採用Gson封裝解析。
/**
 * 自定義Gson解析轉換
 */

public class ResponseConvert extends Converter.Factory {
    public static ResponseConvert create() {
        return new ResponseConvert();
    }

    /**
     * 轉換的方法
     */
    @Override
    public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
        return new BodyConverter<>(type);
    }

    private class BodyConverter<T> implements Converter<ResponseBody, T> {
        private Gson gson;
        private Type type;

        public BodyConverter(Type type) {
            this.type = type;
            gson = new GsonBuilder()
                    .registerTypeHierarchyAdapter(List.class, new ListTypeAdapter())
                    .create();
        }

        @Override
        public T convert(ResponseBody value) throws IOException {
            String json = value.string();
            return gson.fromJson(json, type);
        }
    }

    /**
     * 空列表的轉換
     */
    private static class ListTypeAdapter implements JsonDeserializer<List<?>> {
        @Override
        public List<?> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
            if (json != null && json.isJsonArray()) {
                JsonArray array = json.getAsJsonArray();
                Type itemType = ((ParameterizedType) typeOfT).getActualTypeArguments()[0];
                java.util.List list = new ArrayList<>();
                for (int i = 0; i < array.size(); i++) {
                    JsonElement element = array.get(i);
                    Object item = context.deserialize(element, itemType);
                    list.add(item);
                }
                return list;
            } else {
                //和介面型別不符,返回空List
                return Collections.EMPTY_LIST;
            }
        }
    }
}

三、Retrofit網路請求基類的封裝

/**
 * 後臺統一介面API
 */

public interface ServerApi {
    // 聯絡人編輯
    @POST(URLS.LOGIN)
    Observable<ResponseBean<LoginBean>> login(@Body RequestBody requestBody);
}

/**
 * 請求網路業務的基類,AppPresenterr 的封裝
 */

public class AppPresenter {
    protected ServerApi mApi = RetrofitUtils.getInstance().create(ServerApi.class);
    private static final Gson gson = new Gson();

    /**
     * 1. 轉換
     * 統一處理一些動作
     */
    public static <T> void convert(Observable<ResponseBean<T>> observable, Observer<T> observer) {
        observable
                .map(new Function<ResponseBean<T>, T>() {
                    @Override
                    public T apply(ResponseBean<T> httpResult) throws Exception {
                        // 列印響應的物件
                        LogUtils.object(httpResult);
                        // TODO 實際開發的時候統一處理一些東西
                        if (httpResult == null || httpResult.head == null) {
                            throw new RuntimeException("請求資料異常");
                        } else if (!"1".equals(httpResult.head.bcode)) {
                            throw new RuntimeException(httpResult.head.bmessage);
                        }
                        return httpResult.data;
                    }
                })
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(observer);
    }

    /**
     *  2. 執行的方法
     */
    public static <T> void execute(Observable<ResponseBean<T>> observable, Observer<ResponseBean<T>> observer) {
        observable.subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(observer);
    }

    /**
     * 3.請求資料是Json,Json轉成RequestBody
     */
    public static RequestBody createRequestBody(Object obj) {
        RequestBean bean = new RequestBean<>(obj);
        String json = gson.toJson(bean);
        // 列印請求的Json
        LogUtils.json(json);
        RequestBody body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), json);
        return body;
    }

}
有三個通用的方法:
  1.convert方法,轉換、統一處理網路請求,將公共處理部分放在這方法裡面。
  2.execute方法,只執行,不做任何處理操作,適用於一些不能統一處理的介面。
  3.createRequestBody方法,就是統一建立請求的RequestBody。

四、具體網路請求業務類

/**
 * 登入的業務類
 */

public class LoginPresenter extends AppPresenter {
    /**
     * 登入的介面
     */
    public void login(LoginData data, Observer<LoginBean> observer) {
        Observable<ResponseBean<LoginBean>> login = mApi.login(createRequestBody(data));
        // 轉換
        convert(login, observer);
    }
}

五、測試和使用

/**
 * 呼叫登入介面
 */
public void open(View view) {
    LoginData loginData = new LoginData("135****5219", "12***56");
    presenter.login(loginData, new DialogObserver<LoginBean>(getAppActivity()) {
        @Override
        public void onNext(LoginBean data) {
            // TODO 做登入的成功的操作
            Toast.makeText(getAppActivity(), "" + data.userInfo.nickName, Toast.LENGTH_SHORT).show();
        }
    });
}

六、補充,對於Observer<T>需要再次封裝。

1.如呼叫登入要顯示Dialog
2.如Activity銷燬要取消請求。
3.結合載入資料各種狀態頁面,如:載入中、載入失敗、網路異常、資料為空等等
  這些都是可以統一封裝在Observer<T>裡面。

原文博主