Android戰(zhàn)紀之網(wǎng)絡請求框架封裝(Retrofit的封裝)

網(wǎng)絡請求框架封裝(OkHttp3+Retrofit+loading的封裝)

  • 本文主要將Retrofit網(wǎng)絡請求和loading進行封裝,之后只需很少的代碼就能實現(xiàn)網(wǎng)絡請求he


  • 封裝后進行post請求的效果展示(在任意需要網(wǎng)絡請求的地方)
RestClient.builder()
        .url("/sign_in")
        .loader(getContext())
        .params("account", mEmail.getText().toString())
        .params("password", mPassword.getText().toString())
        .success(new ISuccess(){
            @Override
            public void onSuccess(){
                //請求成功的處理邏輯
            }
        })
        .error(new IError(){
            @Override
            public void onError(){
                //請求錯誤的處理邏輯
            }
        })
        .failure(new IFailure(){
            @override
            public void onFailure(){
                //請求失敗的處理邏輯
            }
        }
        .build()
        .post();

  • 引入依賴
  //網(wǎng)絡請求依賴
  api 'com.squareup.okio:okio:1.13.0'
  api 'com.squareup.okhttp3:okhttp:3.8.1'
  api 'com.squareup.retrofit2:retrofit:2.3.0'
  api 'com.squareup.retrofit2:converter-scalars:2.3.0'
  // loader依賴
  api 'com.wang.avi:library:2.1.3'
  • 網(wǎng)絡框架結構

    網(wǎng)絡請求框架結構

  • loading封裝結構

    loading

  • Loader的封裝

  • 1.新建LoaderStyle枚舉類即定義loading展示的樣式查坪,可以在github上拿到,這里只拉了一部分蹬叭。

public enum LoaderStyle{
    BallPulseIndicator,
    BallGridPulseIndicator,
    BallClipRotateIndicator,
    BallClipRotatePulseIndicator,
    SquareSpinIndicator,
    BallClipRotateMultipleIndicator,
    BallPulseRiseIndicator,
    BallRotateIndicator,
    CubeTransitionIndicator,
    BallZigZagIndicator
}
  • 2.新建LoaderCreator類,通過映射,拿到需要的樣式圖標青瀑。
public final class LoaderCreator{
    // 優(yōu)化,新建一個map集合,存儲已經(jīng)映射過的Loading
    private static final WeakHashMap<String, Indicator> LOADING_MAP = new WeakHashMap<>();

    static AVLoadingIndicatorView create(String type, Context context){
        final AVLoadingIndicatorView avLoadingIndicatorView = new AVLoadingIndicatorView(context);
        if (LOADING_MAP.get(type) == null){
            final Indicator indicator = getIndicator(type);
            LOADING_MAP.put(type, indicator);
        }

        avLoadingIndicatorView.setIndicator(LOADING_MAP.get(type));
        return avLoadingIndicatorView;
    }
    
    // 得到該type類型的Indicator
    private static Indicator getIndicator(String name){
        if (name == null||name.isEmpty()){
            return null;
        }
        final StringBuilder drawableClassName = new StringBuilder();
        if (!name.contains(".")){
            final String defaultPackageName = AVLoadingIndicatorView.class.getPackage().getName();
            drawableClassName.append(defaultPackageName)
                    .append(".indicators")
                    .append(".");
        }
        drawableClassName.append(name);
        try {
            final Class<?> drawableClass = Class.forName(drawableClassName.toString());
            return (Indicator) drawableClass.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}
  • 3.新建MyLoader,通過映射得到的圖標斥难,顯示到屏幕上枝嘶。
public class MyLoader{
    private static final int LOADER_SIZE_SCALE=8;

    private static final int LOADER_OFFSET_SCALE=10;

    private static final ArrayList<AppCompatDialog> LOADERS=new ArrayList<>();

    private static final String DEFAULT_LOADER=LoaderStyle.BallSpinFadeLoaderIndicator.name();

    public static void showLoading(Context context,Enum<LoaderStyle> styleEnum){
        showLoading(context,styleEnum.name());
    }

    public static void showLoading(Context context,String type){
        final AppCompatDialog dialog=new AppCompatDialog(context, R.style.dialog);

        final AVLoadingIndicatorView avLoadingIndicatorView=LoaderCreator.create(type,context);
        dialog.setContentView(avLoadingIndicatorView);

        int deviceWidth= DimenUtil.getScreenWidth();
        int deviceHeight=DimenUtil.getScreenHeight();

        final Window dialogWindow=dialog.getWindow();

        if (dialogWindow!=null){
            WindowManager.LayoutParams lp=dialogWindow.getAttributes();
            lp.width=deviceWidth/LOADER_SIZE_SCALE;
            lp.height=deviceHeight/LOADER_SIZE_SCALE;
            lp.height=lp.height+deviceHeight/LOADER_OFFSET_SCALE;
            lp.gravity= Gravity.CENTER;
        }
        LOADERS.add(dialog);
        dialog.show();
    }

    public static void showLoading(Context context){
        showLoading(context,DEFAULT_LOADER);
    }

    public static void stopLoading(){
        for (AppCompatDialog dialog:LOADERS){
            if (dialog!=null){
                if (dialog!=null){
                    dialog.cancel();
                }
            }
        }
    }
}
  • RestClient封裝

  • 1.先建立Retrofit請求必須要的接口文件RestService(泛式封裝)

public interface RestService{
    @GET
    Call<String> get(@Url String url, @QueryMap Map<String, Object> params);

    @FormUrlEncoded
    @POST
    Call<String> post(@Url String url, @FieldMap Map<String, Object> params);

    @POST
    Call<String> postRaw(@Url String url, @Body RequestBody body);

    @FormUrlEncoded
    @PUT
    Call<String> put(@Url String url, @FieldMap Map<String, Object> params);

    @PUT
    Call<String> putRaw(@Url String url, @Body RequestBody body);

    @DELETE
    Call<String> delete(@Url String url, @QueryMap Map<String, Object> params);

    @Streaming
    @GET
    Call<ResponseBody> download(@Url String url, @QueryMap Map<String, Object> params);

    @Multipart
    @POST
    Call<String> upload(@Url String url, @Part MultipartBody.Part file);
}
  • 2.新建HttpMethod的枚舉類
public enum HttpMethod{
    GET,
    POST,
    POST_RAW,
    PUT,
    PUT_RAW,
    DELETE,
    UPLOAD
}
  • 3.新建RestCreator類,將RetrofitService的接口實例化蘸炸,然后用來進行網(wǎng)絡請求躬络。(靜態(tài)內部類實現(xiàn)線程安全的單例模式)
public class RestCreator{
    // 參數(shù)的單例模式
    private static final class ParamsHolder{
        private static final WeakHashMap<String, Object> PARAMS = new WeakHashMap<>();
    }
    
    public static WeakHashMap<String, Object> getParams(){
        return ParamsHolder.PARAMS;
    }
    
    // 對外釋放RestService的實例
    public static RestService getRestService(){
        return RestServiceHolder.REST_SRVICE;
    }
    
    private static final class RetrofitHolder{
        private static final String BASE_URL = "http://www.baidu.com/"
        private static final Retrofit RETROFIT_CLIENT = new Retrofit.Builder()
                                                                    .baseUrl(BASE_URL)
                                                                    .client(OKHttpHolder.OK_HTTP_CLIENT)
                                                                    .addConverterFactory(ScalarsConverterFactory.create())
                                                                    .build();
    }
    
    private static final class OKHttpHolder {
        private static final int TIME_OUT = 60;
        private static final OkHttpClient OK_HTTP_CLIENT = new OkHttpClient.Builder()
                .connectTimeout(TIME_OUT, TimeUnit.SECONDS)
                .build();
    }

    private static final class RestServiceHolder{
        private static final RestService REST_SERVICE = RetrofitHolder.RETROFIT_HOLDER.create(RestService.class);
    }
}
  • 4.根據(jù)獲取到的參數(shù)數(shù)據(jù)尖奔,組裝之后進行網(wǎng)絡請求(使用建造者模式進行數(shù)據(jù)的組裝)先建立callback的回調接口
public interface ISuccess {
    void onSuccess(String response);
}
public interface IError {
    void onError(int Code, String msg);
}
public interface IFailure {
    void onFailure();
}
public interface IRequest {
    void onRequestStart();
    void onRequestEnd();
}
  • 5.新建RequestCallbacks實現(xiàn)Callback<String>的接口搭儒,即處理網(wǎng)絡請求的回調
public class RequestCallbacks implements Callback<String>{
    private final IRequest REQUEST;
    private final ISuccess SUCCESS;
    private final IFailure FAILURE;
    private final IError ERROR;
    private final LoaderStyle LOADER_STYLE;

    public RequestCallbacks(IRequest request, ISuccess success, IFailure failure, IError error, LoaderStyle loaderStyle){
        this.REQUEST = request;
        this.SUCCESS = success;
        this.FAILURE = failure;
        this.ERROR = error;
        this.LOADER_STYLE = loaderStyle;
    }
    
    @Override
    public void onResponse(Call<String> call, Response<String> response) {
        if (response.isSuccessful()) {
            if (call.isExecuted()) {
                if (SUCCESS != null) {
                    SUCCESS.onSuccess(response.body());
                }
            }
        } else {
            if (ERROR != null) {
                ERROR.onError(response.code(), response.message());
            }
        }
        stopLoader();
    }
    
    @Override
    public void onFailure(Call<String> call, Throwable t) {
        if (FAILURE != null) {
            FAILURE.onFailure();
        }
        if (REQUEST != null) {
            REQUEST.onRequestEnd();
        }
        stopLoader();
    }
    
    private void stopLoader() {
        if (LOADER_STYLE != null) {
           LatteLoader.stopLoading();
        }
    }
}
  • 6.新建RestClient類,就是將傳入的數(shù)據(jù)進行組裝然后用之前實例化的RestService對象進行網(wǎng)絡請求提茁。
public class RestClient{
    private final String URL;
    private static final WeakHashMap<String, Object> PARAMS = RestCreator.getParams();
    private final IRequest REQUEST;
    private final String DOWNLOAD_DIR;
    private final String EXTENSION;
    private final String NAME;
    private final ISuccess SUCCESS;
    private final IFailure FAILURE;
    private final IError ERROR;
    private final RequestBody BODY;
    private final LoaderStyle LOADER_STYLE;
    private final File FILE;
    private final Context CONTEXT;

    public RestClient(String url,
                      Map<String, Object> params,
                      IRequest request,
                      String download_dir,
                      String extension,
                      String name,
                      ISuccess success,
                      IFailure failure,
                      IError error,
                      RequestBody body,
                      LoaderStyle loaderStyle,
                      File file,
                      Context context) {
        this.URL = url;
        PARAMS.putAll(params);
        this.REQUEST = request;
        this.DOWNLOAD_DIR = download_dir;
        this.EXTENSION = extension;
        this.NAME = name;
        this.SUCCESS = success;
        this.FAILURE = failure;
        this.ERROR = error;
        this.BODY = body;
        this.LOADER_STYLE = loaderStyle;
        this.FILE = file;
        this.CONTEXT = context;
    }
    
    public static RestClientBuilder builder() {
        return new RestClientBuilder();
    }

    private void request(HttpMethod method){
        final RestService service = RestCreator.getRestService();
        Call<String> call = null;

        if(REQUEST != null){
            REQUEST.onRequestStart();
        }

        if (LOADER_STYLE != null) {
            LatteLoader.showLoading(CONTEXT, LOADER_STYLE);
        }
        
        switch (method) {
            case GET:
                call = service.get(URL, PARAMS);
                break;
            case POST:
                call = service.post(URL, PARAMS);
                break;
            case POST_RAW:
                call = service.postRaw(URL, BODY);
                break;
            case PUT:
                call = service.put(URL, PARAMS);
                break;
            case PUT_RAW:
                call = service.putRaw(URL, BODY);
                break;
            case DELETE:
                call = service.delete(URL, PARAMS);
                break;
            case UPLOAD:
                final RequestBody requestBody = RequestBody.create(MediaType.parse(MultipartBody.FORM.toString()), FILE);
                final MultipartBody.Part body = MultipartBody.Part.createFormData("file", FILE.getName(), requestBody);
                call = RestCreator.getRestService().upload(URL, body);
                break;
            default:
                break;
        }
        
        if (call != null) {
            call.enqueue(getRequestCallback());
        }
        RestCreator.getParams().clear();
    }
    
    private Callback<String> getRequestCallback() {
        return new RequestCallbacks(
                REQUEST,
                SUCCESS,
                FAILURE,
                ERROR,
                LOADER_STYLE
        );
    }

    public final void get() {
        request(HttpMethod.GET);
    }

    public final void post() {
        if (BODY == null) {
            request(HttpMethod.POST);
        } else {
            if (PARAMS.isEmpty()) {
                throw new RuntimeException("params must be null");
            }
            request(HttpMethod.POST_RAW);
        }

    }

    public final void put() {
        if (BODY == null) {
            request(HttpMethod.PUT);
        } else {
            if (PARAMS.isEmpty()) {
                throw new RuntimeException("params must be null");
            }
            request(HttpMethod.PUT_RAW);
        }
    }

    public final void delete() {
        request(HttpMethod.DELETE);
    }

    public final void upload() {
        request(HttpMethod.UPLOAD);
    }
}
  • 7.新建RestClientBuilder淹禾,就是RestClient的建造者類
public class RestClientBuilder {

    private String mUrl = null;
    private static final Map<String, Object> PARAMS = RestCreator.getParams();
    private IRequest mIRequest = null;
    private String mDownloadDir = null;
    private String mExtension = null;
    private String mName = null;
    private ISuccess mISuccess = null;
    private IFailure mIFailure = null;
    private IError mIError = null;
    private RequestBody mBody = null;
    private LoaderStyle mLoaderStyle = null;
    private File mFile = null;
    private Context mContext = null;

    RestClientBuilder() {
    }

    public final RestClientBuilder url(String url) {
        this.mUrl = url;
        return this;
    }

    public final RestClientBuilder params(WeakHashMap<String, Object> params) {
        PARAMS.putAll(params);
        return this;
    }

    public final RestClientBuilder params(String key, Object value) {
        PARAMS.put(key, value);
        return this;
    }

    public final RestClientBuilder file(File file) {
        this.mFile = file;
        return this;
    }

    public final RestClientBuilder file(String file) {
        this.mFile = new File(file);
        return this;
    }

    public final RestClientBuilder raw(String raw) {
        this.mBody = RequestBody.create(MediaType.parse("application/json;charset=UTF-8"), raw);
        return this;
    }

    public final RestClientBuilder dir(String dir) {
        this.mDownloadDir = dir;
        return this;
    }

    public final RestClientBuilder extension(String extension) {
        this.mExtension = extension;
        return this;
    }

    public final RestClientBuilder name(String name) {
        this.mName = name;
        return this;
    }

    public final RestClientBuilder onRequest(IRequest iRequest) {
        this.mIRequest = iRequest;
        return this;
    }

    public final RestClientBuilder success(ISuccess iSuccess) {
        this.mISuccess = iSuccess;
        return this;
    }

    public final RestClientBuilder failure(IFailure iFailure) {
        this.mIFailure = iFailure;
        return this;
    }

    public final RestClientBuilder error(IError iError) {
        this.mIError = iError;
        return this;
    }

    public final RestClientBuilder loader(Context context, LoaderStyle style) {
        this.mContext = context;
        this.mLoaderStyle = style;
        return this;
    }

    public final RestClientBuilder loader(Context context) {
        this.mContext = context;
        this.mLoaderStyle = LoaderStyle.BallSpinFadeLoaderIndicator;
        return this;
    }

    public final RestClient build() {
        return new RestClient(mUrl, PARAMS, mIRequest, mDownloadDir, mExtension, mName, mISuccess, mIFailure, mIError, mBody, mLoaderStyle, mFile, mContext);
    }

}
  • 8.小結
    至此網(wǎng)絡框架告一段落,其中的download沒有寫全茴扁,調用方式就是開頭寫的那樣铃岔。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市峭火,隨后出現(xiàn)的幾起案子毁习,更是在濱河造成了極大的恐慌,老刑警劉巖卖丸,帶你破解...
    沈念sama閱讀 222,807評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件纺且,死亡現(xiàn)場離奇詭異,居然都是意外死亡稍浆,警方通過查閱死者的電腦和手機载碌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,284評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來衅枫,“玉大人嫁艇,你說我怎么就攤上這事∠伊茫” “怎么了步咪?”我有些...
    開封第一講書人閱讀 169,589評論 0 363
  • 文/不壞的土叔 我叫張陵,是天一觀的道長益楼。 經(jīng)常有香客問我猾漫,道長,這世上最難降的妖魔是什么偏形? 我笑而不...
    開封第一講書人閱讀 60,188評論 1 300
  • 正文 為了忘掉前任静袖,我火速辦了婚禮,結果婚禮上俊扭,老公的妹妹穿的比我還像新娘队橙。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 69,185評論 6 398
  • 文/花漫 我一把揭開白布捐康。 她就那樣靜靜地躺著仇矾,像睡著了一般。 火紅的嫁衣襯著肌膚如雪解总。 梳的紋絲不亂的頭發(fā)上贮匕,一...
    開封第一講書人閱讀 52,785評論 1 314
  • 那天,我揣著相機與錄音花枫,去河邊找鬼刻盐。 笑死,一個胖子當著我的面吹牛劳翰,可吹牛的內容都是我干的敦锌。 我是一名探鬼主播,決...
    沈念sama閱讀 41,220評論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼佳簸,長吁一口氣:“原來是場噩夢啊……” “哼乙墙!你這毒婦竟也來了?” 一聲冷哼從身側響起生均,我...
    開封第一講書人閱讀 40,167評論 0 277
  • 序言:老撾萬榮一對情侶失蹤听想,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后马胧,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體汉买,經(jīng)...
    沈念sama閱讀 46,698評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,767評論 3 343
  • 正文 我和宋清朗相戀三年漓雅,在試婚紗的時候發(fā)現(xiàn)自己被綠了录别。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,912評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡邻吞,死狀恐怖组题,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情抱冷,我是刑警寧澤崔列,帶...
    沈念sama閱讀 36,572評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站旺遮,受9級特大地震影響赵讯,放射性物質發(fā)生泄漏。R本人自食惡果不足惜耿眉,卻給世界環(huán)境...
    茶點故事閱讀 42,254評論 3 336
  • 文/蒙蒙 一边翼、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧鸣剪,春花似錦组底、人聲如沸丈积。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,746評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽江滨。三九已至,卻和暖如春厌均,著一層夾襖步出監(jiān)牢的瞬間唬滑,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,859評論 1 274
  • 我被黑心中介騙來泰國打工棺弊, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留晶密,地道東北人。 一個月前我還...
    沈念sama閱讀 49,359評論 3 379
  • 正文 我出身青樓镊屎,卻偏偏與公主長得像惹挟,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子缝驳,可洞房花燭夜當晚...
    茶點故事閱讀 45,922評論 2 361

推薦閱讀更多精彩內容