上一篇文章重点介绍了如何分析并打造网络请求框架:一步步打造网络请求框架——初步成型(一),本篇文章重点分析如何对框架进行细节优化。
网络框架是搭建好了,测试后也可以使用,但是能不能再优化一些呢?高质量的代码从来都不是一蹴而就,而是经过不断地重构锤炼而成,重新再Review几遍代码,发现值得优化的地方还不少,下面就开始进行具体的细节优化。
从使用端入手,在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可以封装,其他的类有没有可能也封装一下呢?
在请求出现异常的时候,我们所做的处理基本就是简单的返回了一下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,经测试都没有问题,断网处理功能有了,网络请求取消功能还没有,由于取消网络请求属于功能扩展,不属于细节优化层面,所以就留到下一篇文章再做重点分析了~