一步步打造网络请求框架——细节优化(二)

本文档详细介绍了如何对网络请求框架进行细节优化,包括封装CommonRequest类以统一参数管理,实现更简洁的调用方式;新增HttpException类以分类处理请求异常,增强错误定位能力;引入线程池提升性能并处理断网情况。通过这些优化,代码更加整洁且易于维护。

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

上一篇文章重点介绍了如何分析并打造网络请求框架:一步步打造网络请求框架——初步成型(一),本篇文章重点分析如何对框架进行细节优化。

网络框架是搭建好了,测试后也可以使用,但是能不能再优化一些呢?高质量的代码从来都不是一蹴而就,而是经过不断地重构锤炼而成,重新再Review几遍代码,发现值得优化的地方还不少,下面就开始进行具体的细节优化。
 

Request优化

 

从使用端入手,在Activity中使用的时候向里面传递了大量的参数,这里就会带来一个问题,有的请求是get类型,不带请求参数,有的请求是post类型,带请求参数,还有的可能会带有headers请求头等参数,这样每创建一个网络请求就会根据不同情况传入不同参数,造成参数的不匹配,就比如第一个请求的第二个参数明明不需要,还硬要写一个null进去,非常不合理,而且之后有可能还会有业务扩展再添加新的参数,context等等......

是时候给所有参数进行一下封装了,来一个CommonRequest类,把所有用到的参数全部封装进去:

public class CommonRequest {
    private String mUrl;
    private Map<String,String> mParams;
    private Map<String,String> mHeaders;
    private HttpMethod mHttpMethod;
    private JsonCallback mJsonCallback;
    private Context mContext;

    public CommonRequest(Builder builder) {
        this.mUrl = builder.mUrl;
        this.mParams = builder.mParams;
        this.mHeaders = builder.mHeaders;
        this.mHttpMethod = builder.mHttpMethod;
        this.mJsonCallback = builder.mJsonCallback;
        this.mContext = builder.mContext;
    }

    public Context getContext() {
        return mContext;
    }

    public String getUrl() {
        return mUrl;
    }

    public Map<String, String> getParams() {
        return mParams;
    }

    public Map<String, String> getHeaders() {
        return mHeaders;
    }

    public HttpMethod getHttpMethod() {
        return mHttpMethod;
    }

    public JsonCallback getJsonCallback() {
        return mJsonCallback;
    }

    public static class Builder{
        private String mUrl;
        private Map<String,String> mParams;
        private Map<String,String> mHeaders;
        private HttpMethod mHttpMethod;
        private JsonCallback mJsonCallback;
        private Context mContext;

        public Builder setContext(Context context) {
            mContext = context;
            return this;
        }

        public Builder setUrl(String url) {
            mUrl = url;
            return this;
        }

        public Builder setParams(Map<String, String> params) {
            mParams = params;
            return this;
        }

        public Builder setHeaders(Map<String, String> headers) {
            mHeaders = headers;
            return this;
        }

        public Builder setHttpMethod(HttpMethod httpMethod) {
            mHttpMethod = httpMethod;
            return this;
        }

        public Builder setJsonCallback(JsonCallback jsonCallback) {
            mJsonCallback = jsonCallback;
            return this;
        }
        public CommonRequest build(){
            return new CommonRequest(this);
        }
    }
}

具体使用就变成了这样:

public class MainActivity extends AppCompatActivity {
    private static final String TAG = MainActivity.class.getSimpleName();
    private String getUrl        = "http://39.100.224.84:6100/api/system/open/module/selectCCGet";
    private String postUrl       = "http://39.100.224.84:6100/api/system/open/module/selectCCPost";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.btn_test_get).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                CommonRequest request = new CommonRequest.Builder()
                        .setContext(MainActivity.this)
                        .setHttpMethod(HttpMethod.GET)
                        .setUrl(getUrl)
                        .setJsonCallback(new JsonCallback<User>() {
                            @Override
                            public void onSuccess(User result) {
                                LogUtils.i(TAG,"get: " + result.toString());
                            }

                            @Override
                            public void onFailure(int code, String msg) {
                                LogUtils.i(TAG,"get: " +"code = " + code + "  msg = " + msg);
                            }
                        })
                        .build();
                RequestManager.getRequestManager().performRequest(request);
            }
        });
        findViewById(R.id.btn_test_post).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Map<String,String> params = new HashMap<>();
                params.put("userId","123");
                CommonRequest request = new CommonRequest.Builder()
                        .setContext(MainActivity.this)
                        .setHttpMethod(HttpMethod.POST)
                        .setParams(params)
                        .setUrl(postUrl)
                        .setJsonCallback(new JsonCallback<User>() {
                            @Override
                            public void onSuccess(User result) {
                                LogUtils.i(TAG,"post: " +result.toString());
                            }

                            @Override
                            public void onFailure(int code, String msg) {
                                LogUtils.i(TAG,"post: " +"code = " + code + "  msg = " + msg);
                            }
                        })
                        .build();
                RequestManager.getRequestManager().performRequest(request);
            }
        });
    }
}

 

再把其他类中与此相关联的地方修改一下,其他地方就不贴图了。这么一看,是比刚才要舒服多了,代码也看着更干净利落一些。

无独有偶,既然Request可以封装,其他的类有没有可能也封装一下呢?

Exception优化

在请求出现异常的时候,我们所做的处理基本就是简单的返回了一下code和message,如果能更清晰的返回异常的类型,比如网络请求取消了(cancel),服务端出现错误了(Server),json数据出现问题了(Json),连接超时了(TimeOut),断网了(IO),将异常进行分类,有助于我们更好地定位bug。说到这,突然发现,好像没有断网处理这个功能诶......,也没有取消网络请求这个功能.....太好了,需要优化的地方一个接一个的来了。

写一个HttpException类,用于封装请求异常参数

public class HttpException extends Exception {
    public int    mStatusCode;
    public String mResponseMessage;
    public enum ErrorType{
        CANCEL,
        TIMEOUT,
        SERVER,
        JSON,
        IO,
    }
    public ErrorType mErrorType;
    public HttpException(int code, String message){
        this.mErrorType = ErrorType.SERVER;
        this.mStatusCode = code;
        this.mResponseMessage = message;
    }
    public HttpException(ErrorType type, String message){
        this.mErrorType = type;
        this.mResponseMessage = message;
    }
    public HttpException(ErrorType type, int code, String message){
        this.mErrorType = type;
        this.mStatusCode = code;
        this.mResponseMessage = message;
    }
}

把相关用到的地方修改一下,再加入一个断网处理功能

public class NetWorkUtil {
    public static boolean isConnect(Context context){
        ConnectivityManager connectivityManager=(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo netInfo=connectivityManager.getActiveNetworkInfo();
        return netInfo != null && netInfo.isConnected();
    }

    public static boolean isWifiConnect(Context context){
        ConnectivityManager connectivityManager=(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo wifiInfo=connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
        return wifiInfo != null && wifiInfo.isConnected();
    }

    public static boolean isMobileConnect(Context context){
        ConnectivityManager connectivityManager=(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo mobileNetInfo=connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
        return mobileNetInfo != null && mobileNetInfo.isConnected();
    }
}

NetWorkUtil类用于判断网络是否连接,需要加入权限:

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

在一顿修改之后发现,有一个地方看着特别不顺眼,就是这里:

线程池优化

 

由于我们HttpUtil里面封装了Okhttp的同步请求的方式,而没有用异步请求的方式,所以子线程都是由我们自己管理,每次启动一个RequestTask,就会new一个Thread,什么?new Thread?连个线程池都没有吗?

public class CoreExecutorService {
    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    private static final int CORE_POOL_SIZE = CPU_COUNT * 2 + 1;
    private static final int MAXIMUM_POOL_SIZE = 50;
    private static final long KEEP_ALIVE_TIME = CPU_COUNT;

    private static BlockingQueue<Runnable> sPoolWorkQueue = new LinkedBlockingQueue<>(128);

    private static ThreadFactory sThreadFactory = new ThreadFactory() {
        private final AtomicInteger mCount = new AtomicInteger(1);
        @Override
        public Thread newThread(Runnable r) {
            return new Thread(r,"CoreExecutorService --" + mCount.getAndIncrement());
        }
    };

    private static final ExecutorService THREAD_POOL_EXECUTOR =
            new ThreadPoolExecutor(CORE_POOL_SIZE,MAXIMUM_POOL_SIZE,KEEP_ALIVE_TIME
            , TimeUnit.SECONDS,sPoolWorkQueue,sThreadFactory);

    public static ExecutorService getExecutorService(){
        return THREAD_POOL_EXECUTOR;
    }

    public static void cancel(Runnable task){
        sPoolWorkQueue.remove(task);
    }
}

有,这不,线程池来了,CoreExecutorService中基本使用到的都是常规配置,不懂的可以百度一下,网上关于线程池装逼的代码一箩筐。。。。。。
有了线程池,再修改一下RequestTask里面相关的代码,就基本差不多了,优化的结果就是如下所示

public class RequestTask implements Runnable {
    private static final String             TAG        = RequestTask.class.getSimpleName();
    private              String             url;
    private              Map<String,String> params;
    private              Map<String,String> headers;
    private              HttpMethod         httpMethod;
    private              JsonCallback       mJsonCallback;
    private              Context            mContext;
    private static       InternalHandler    sHandler;
    public RequestTask(CommonRequest request) {
        this.url = request.getUrl();
        this.params = request.getParams();
        this.headers = request.getHeaders();
        this.httpMethod = request.getHttpMethod();
        this.mJsonCallback = request.getJsonCallback();
        this.mContext = request.getContext();
    }

    public void execute() {
        CoreExecutorService.getExecutorService().submit(this);
    }

    @Override
    public void run() {
        if (!NetWorkUtil.isConnect(mContext)) {
            //断网处理
            onFailure(new HttpException(HttpException.ErrorType.IO, "请检查网络连接是否正常"));
            return;
        }
        Response response;
        String json;
        if (httpMethod == HttpMethod.GET) {
            if (headers != null && headers.size() > 0) {
                response = HttpUtil.get(url, headers);
            } else {
                response = HttpUtil.get(url);
            }
        } else if (httpMethod == HttpMethod.POST) {
            response = HttpUtil.post(url, params, headers);
        } else if (httpMethod == HttpMethod.PUT) {
            response = HttpUtil.put(url, params);
        } else {
            response = HttpUtil.delete(url, params);
        }
        try {
            if (response != null) {
                if (response.body() != null) {
                    json = response.body().string();
                    if (!TextUtils.isEmpty(json)) {
                        LogUtils.i(TAG, json);
                        JSONObject jsonObject = new JSONObject(json);
                        if (jsonObject.has("code")) {
                            int code = jsonObject.optInt("code");
                            String message = jsonObject.optString("msg");
                            String type = jsonObject.optString("type");
                            String data = jsonObject.optString("data");
                            LogUtils.i(TAG, "需要解析的数据 :" + data);
                            if (code == 1) {
                                Object o = mJsonCallback.bindData(data);
                                onSuccess(o);
                            } else {
                                onFailure(new HttpException(code, message));
                            }
                        } else {
                            onFailure(new HttpException(HttpException.ErrorType.JSON, "json error"));
                        }
                    } else {
                        //Json为空
                        onFailure(new HttpException(HttpException.ErrorType.SERVER, "json empty"));
                        return;
                    }
                }
            }
        } catch(Exception e){
            LogUtils.e(TAG, "error---" + e.toString());
            e.printStackTrace();
            onFailure(e);
        }

    }



    private void onFailure(final Exception e) {
        getHandler().post(new Runnable() {
            @Override
            public void run() {
                mJsonCallback.onFailure(e);
            }
        });
    }

    private void onSuccess(final Object o) {
        getHandler().post(new Runnable() {
            @Override
            public void run() {
                mJsonCallback.onSuccess(o);
            }
        });
    }

    private static class InternalHandler extends Handler {
        InternalHandler() {
            super(Looper.getMainLooper());
        }
    }

    private static InternalHandler getHandler() {
        if (sHandler == null) {
            synchronized (RequestTask.class) {
                if (sHandler == null) {
                    sHandler = new InternalHandler();
                }
            }
        }
        return sHandler;
    }
}

还得把IResponseCallback里面的onFailure改一下
 

public interface IResponseCallback<T> {
    /**
     * 请求成功回调
     * @param result
     */
    void onSuccess(T result);

    /**
     * 请求失败回调
     * @param e
     */
    void onFailure(Exception e);
}

Activity中也要跟着修改

public class MainActivity extends AppCompatActivity {
    private static final String TAG = MainActivity.class.getSimpleName();
    private String getUrl        = "http://39.100.224.84:6100/api/system/open/module/selectCCGet";
    private String postUrl       = "http://39.100.224.84:6100/api/system/open/module/selectCCPost";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.btn_test_get).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                CommonRequest request = new CommonRequest.Builder()
                        .setContext(MainActivity.this)
                        .setHttpMethod(HttpMethod.GET)
                        .setUrl(getUrl)
                        .setJsonCallback(new JsonCallback<User>() {
                            @Override
                            public void onSuccess(User result) {
                                LogUtils.i(TAG,"get: " + result.toString());
                            }

                            @Override
                            public void onFailure(Exception e) {
                                if(e instanceof HttpException){
                                    HttpException exception = (HttpException) e;
                                    LogUtils.i(TAG,"get: " +"code = " + exception.mStatusCode +
                                            "  msg = " + exception.mResponseMessage + "  errorType = " + exception.mErrorType);
                                }

                            }
                        })
                        .build();
                RequestManager.getRequestManager().performRequest(request);
            }
        });
        findViewById(R.id.btn_test_post).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Map<String,String> params = new HashMap<>();
                params.put("userId","123");
                CommonRequest request = new CommonRequest.Builder()
                        .setContext(MainActivity.this)
                        .setHttpMethod(HttpMethod.POST)
                        .setParams(params)
                        .setUrl(postUrl)
                        .setJsonCallback(new JsonCallback<User>() {
                            @Override
                            public void onSuccess(User result) {
                                LogUtils.i(TAG,"post: " +result.toString());
                            }

                            @Override
                            public void onFailure(Exception e) {
                                if(e instanceof HttpException){
                                    HttpException exception = (HttpException) e;
                                    LogUtils.i(TAG,"post: " +"code = " + exception.mStatusCode +
                                            "  msg = " + exception.mResponseMessage + "  errorType = " + exception.mErrorType);
                                }
                            }
                        })
                        .build();
                RequestManager.getRequestManager().performRequest(request);
            }
        });
    }
}

来吧,运行一下

2021-02-20 17:26:29.063 19886-19886/com.wzw.baseframwork I/MainActivity: get: User{name='ly', id='1', sex='男'}
2021-02-20 17:26:30.027 19886-19886/com.wzw.baseframwork I/MainActivity: post: User{name='ly', id='1', sex='男'}

网络正常的时候没什么问题,关掉wifi再运行一下

2021-02-20 17:27:48.094 20342-20342/com.wzw.baseframwork I/MainActivity: get: code = 0  msg = 请检查网络连接是否正常  errorType = IO
2021-02-20 17:27:48.682 20342-20342/com.wzw.baseframwork I/MainActivity: post: code = 0  msg = 请检查网络连接是否正常  errorType = IO

OK,经测试都没有问题,断网处理功能有了,网络请求取消功能还没有,由于取消网络请求属于功能扩展,不属于细节优化层面,所以就留到下一篇文章再做重点分析了~

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值