仿电商App:笔记(四):网络请求框架设计

本文详细介绍使用Retrofit进行网络请求的封装过程,包括接口创建、注解使用、Restful请求处理、Loading框架集成、文件下载及OKHttp拦截器功能实现。通过动态代理和建造者模式,实现网络请求的灵活配置与高效执行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

1、网络请求接口创建--retrofit的使用

1.1 使用注解描述网络请求

1.2 网络请求接口的实例创建

2、Restful请求的处理--同接口,使用不同方法,可以产生不同的作用

3、Loading框架集成和完善--在dialog中显示

3.1 LoaderView的创建

3.2 LoaderView的显示

4、文件下载功能的实现--AsyncTask、线程池并发的实现

5、拦截器功能的实现--OKHttp中拦截器的改写

5.1 拦截器初始化

5.2 拦截器功能实现

使用retrofit进行网络请求封装

1、网络请求接口创建--retrofit的使用

1.1 使用注解描述网络请求

位于latte-core模块下的RestService,接口,内部含有网络请求的get、post、download等方法。

主要作用:通过动态代理方式,将注解生成网络请求的request。

@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);

1.2 网络请求接口的实例创建

位于latte-core模块下的RestCreator,内部含有OKHttp和Retrofit的创建。

主要作用:创建RestService的实例,单例,确保全局唯一性。

    /**
     * 构建全局Retrofit客户端
     */
    private static final class RetrofitHolder{
        private static final String BASE_URL = Latte.getConfiguration(ConfigKeys.API_HOST) ;
        private static final Retrofit RETROFIT_CLIENT = new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .client(OKHttpHolder.OK_HTTP_CLIENT)
                .addConverterFactory(ScalarsConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build();
    }

    private static final class OKHttpHolder{//对okhttpclient处理,okhttp惰性初始化
        private static final int TIME_OUT = 60;
        private static final OkHttpClient.Builder BUILDER = new OkHttpClient.Builder();
        private static final ArrayList<Interceptor> INTERCEPTORS = Latte.getConfiguration(ConfigKeys.INTERCEPTOR);

        private static OkHttpClient.Builder addInterceptor(){
            if (INTERCEPTORS != null && !INTERCEPTORS.isEmpty()){
                for (Interceptor interceptor: INTERCEPTORS) {
                    BUILDER.addInterceptor(interceptor);
                }
            }
            return BUILDER;
        }
        private static final OkHttpClient OK_HTTP_CLIENT = addInterceptor()
                .connectTimeout(TIME_OUT, TimeUnit.SECONDS)
                .build();
    }

    /**
     * Service接口
     */
    private static final class RestServiceHolder{
        private static final RestService REST_SERVICE = RetrofitHolder.RETROFIT_CLIENT.create(RestService.class);
    }

    public static RestService getRestService(){
        return RestServiceHolder.REST_SERVICE;
    }

2、Restful请求的处理--同接口,使用不同方法,可以产生不同的作用

使用建造者模式进行传参,链式调用,将使用和构建相分离,确保初始化唯一。

位于latte-core模块下的RestClient,内部含有call方法的请求,根据调用的方法不同,发起不同的call请求。

主要作用:创建RestService的实例,单例,确保全局唯一性。

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

        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);//根据文件和MediaType.parse(MultipartBody.FORM.toString()):相当于请求头---形成请求体
                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());
        }
    }

位于latte-core模块下的RestClientBuilder,内部含有方法接受网络请求需要的参数。

主要作用:将传入的参数通过build()方法传回RestClient类中,为后续call请求做准备。

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

    public final RestClientBuilder loader(Context context){//使用默认style
        this.mContext = context;
        this.mLoaderStyle = LoaderStyle.BallClipRotatePulseIndicator;
        return this;
    }

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

位于latte-core模块下的RequestCallbacks,继承自Callback,内部含有call方法请求后的回调。

主要作用:根据call方法的请求请求结果回调不同的接口:ISuccess、IError等接口,实现不同的结果处理

    @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());
            }
        }

        stopLoading();
    }

    @Override
    public void onFailure(Call<String> call, Throwable t) {
        if(FAILURE != null){
            FAILURE.onFailure();
        }
        if(REQUEST != null){
            REQUEST.onRequestEnd();
        }
        stopLoading();
    }

位于latte-core模块下的ISuccess、IError等接口,内部含有call方法请求后的结果方法。

主要作用:使用在call后结果处理,根据结果选择回调不同方法。----具体的实现在链式调用中体现。

public interface ISuccess {
    void onSuccess(String response);
}

public interface IError {
    void onError(int code, String msg);
}

3、Loading框架集成和完善--在dialog中显示

考虑网络较差情况下的网络加载,这时候会在UI上出现一个Loader;

在retrofit的回调中进行loader的删除。

3.1 LoaderView的创建

位于latte-core模块下的LoaderCreator,内部通过反射获取View,官方每次请求都反射一次,这里使用WeakHashmap进行缓存。

主要作用:创建出Loader的View。

    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;
    }

    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);//生成具体View
        try {
            final Class<?> drawableClass = Class.forName(drawableClassName.toString());
            return (Indicator) drawableClass.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

3.2 LoaderView的显示

位于latte-core模块下的LatteLoader,内部与dialog绑定。

主要作用:显示View。

    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){
            final 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();

    }

4、文件下载功能的实现--AsyncTask、线程池并发的实现

使用AsyncTask进行异步下载

位于latte-core模块下的DownloadHandler,内部进行了异步下载处理。

主要作用:调用download请求方法。

    public final void handleDownload(){
        if (REQUEST != null){
            REQUEST.onRequestStart();//请求开始的回调
        }

        RestCreator.getRestService().download(URL,PARAMS)
                .enqueue(new Callback<ResponseBody>() {
                    @Override
                    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                        if (response.isSuccessful()){
                            final ResponseBody responseBody = response.body();
                            final SaveFileTask task = new SaveFileTask(REQUEST, SUCCESS);
//使用线程池方法进行下载,内部默认的线程池:核心1,最大20,时间3分                  
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,DOWNLOAD_DIR,EXTENSION,responseBody,NAME);

                            //这里一定要注意判断,否则文件下载不全
                            if (task.isCancelled()){//下载结束
                                if (REQUEST != null){
                                    REQUEST.onRequestEnd();
                                }
                            }
                        }else {
                            if (ERROR != null){
                                ERROR.onError(response.code(), response.message());
                            }
                        }
                        RestCreator.getParams().clear();
                    }

                    @Override
                    public void onFailure(Call<ResponseBody> call, Throwable t) {
                        if (FAILURE != null){
                            FAILURE.onFailure();
                            RestCreator.getParams().clear();
                        }
                    }
                });
    }

位于latte-core模块下的SaveFileTask,继承自AsyncTask。

主要作用:进行下载的处理,写入文件(使用IO流)。

    @Override
    protected File doInBackground(Object... objects) {
        String downloadDir = (String) objects[0];
        String extension = (String) objects[1];
        final ResponseBody body = (ResponseBody) objects[2];
        final String name = (String) objects[3];
        final InputStream is = body.byteStream();
        if (downloadDir == null || downloadDir.equals("")){
            downloadDir = "down_loads";
        }
        if (extension == null || extension.equals("")){
            extension = "";
        }
        if (name == null){
            return FileUtil.writeToDisk(is,downloadDir,extension.toUpperCase(),extension);
        }else {
            return FileUtil.writeToDisk(is, downloadDir, name);
        }
    }

5、拦截器功能的实现--OKHttp中拦截器的改写

如果请求的url中包含参数,进行拦截,改写Response。

5.1 拦截器初始化

位于latte-core模块下的Configurator。

主要作用:传入拦截器,进行初始化。

    public final Configurator withInterceptor(Interceptor interceptor) {
        INTERCEPTORS.add(interceptor);
        LATTE_CONFIGS.put(ConfigKeys.INTERCEPTOR, INTERCEPTORS);
        return this;
    }

    public final Configurator withInterceptors(ArrayList<Interceptor> interceptors) {
        INTERCEPTORS.addAll(interceptors);
        LATTE_CONFIGS.put(ConfigKeys.INTERCEPTOR, INTERCEPTORS);
        return this;
    }

5.2 拦截器功能实现

位于latte-core模块下的DebugInterceptor,继承自BaseInterceptor,继承自Interceptor。

主要作用:根据传入参数,如果请求的url中包含参数,进行拦截,更改返回体。

    public DebugInterceptor(String debugUrl, int rawId) {
        DEBUG_URL = debugUrl;
        DEBUG_RAW_ID = rawId;
    }

    private Response getResponse(Chain chain, String json){
        return new Response.Builder()//更改返回体
                .code(200)
                .addHeader("Content-Type","application/json")
                .body(ResponseBody.create(MediaType.parse("application/json"),json))
                .message("OK")
                .request(chain.request())
                .protocol(Protocol.HTTP_1_1)
                .build();
    }

    private Response debugResponse(Chain chain, @RawRes int rawId){
        final String json = FileUtil.getRawFile(rawId);//将要返回的内容转为json格式
        return getResponse(chain, json);
    }

    @Override
    public Response intercept(Chain chain) throws IOException {
        final String url = chain.request().url().toString();
        if (url.contains(DEBUG_URL)){//请求的url中包含参数
            return debugResponse(chain, DEBUG_RAW_ID);
        }
        return chain.proceed(chain.request());
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值