Android發展至今,先後出現了許多流行的網絡框架,比如Xutils、OkHttp、Volley、Retrofit等框架,但是作爲開發者,我們也應有自己的搭建網絡框架的能裏,以自己的項目“量體裁衣”,另一方面,不是每一個網絡框架都是沒有缺點的比如
Xutils 網絡請求框架的弊端:
- 1、請求方式、地址、參數都拆開了,應該封裝到一個對象裏面
- 2、請求之前應該判斷網絡
- 3、每次請求都new了一個RequestCallBack對象
- 4、請求得到的響應不知道是那次請求發出的
- 5、json的解析封裝是耗時的操作不應該放到主線程
- 6、gson解析用流比字符串效率高很多
- 7、httpUtils基於HttpClient , HttpUrlConnection 擴展性很差,如果項目要用OkHttp之類的 NoHttp
- 8、錯誤的處理不應該讓子類來處理
- 9、請求的響應應該分爲三種:成功、其他的情況、錯誤
現在我們開始搭建網絡框架,下面是我們網絡搭建的時序圖:
添加依賴 okhttp、Gson
implementation ‘com.squareup.okhttp3:okhttp:3.10.0’ compile
compile ‘com.google.code.gson:gson:2.8.2’
添加權限:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
/**
* Created by MG_ZXC on 2018/3/22.
* 封裝:請求方式, 請求地址, 請求參數
*/
public abstract class BaseRequest {
public enum HttpMethod{
GET,POST;
}
public abstract HttpMethod getMethod();
public abstract String getUrl();
public abstract Map<String, String> getParams();
}
BaseResponse類封裝響應:
/**
* Created by MG_ZXC on 2018/3/22.
* 響應json數據的封裝
*/
public abstract class BaseResponse <T> {
//響應碼
public int code;
public T data;
public boolean success() {
return code >= 200 && code < 300;
}
}
聲明接口 Callback結果回調:
/**
* Created by MG_ZXC on 2018/3/22.
* 請求結果回調
* 爲了回調的時候告知當前的響應是哪次請求發出的,響應的方法把請求的BaseRequest傳入
*/
public interface Callback <Res extends BaseResponse> {
void onError(BaseRequest request, Exception e);
void onOther(BaseRequest request, Res response);
void onSuccess(BaseRequest request, Res response);
}
通過NetUtil發送網絡請求:
public class NetUtil {
private static ConnectivityManager connectivityManager;
public static void init(Context context) {
connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
}
private static boolean checkNet() {
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
return activeNetworkInfo != null && activeNetworkInfo.isAvailable();
}
/**
* 通過NetUtil發送網絡請求
*
* @param request 請求的參數
* @param responseClass 相應的自字節碼
* @param callback 請求的回調結果
* @param <Res>
*/
public static <Res extends BaseResponse> void sendRequest(BaseRequest request, Class<Res> responseClass, Callback callback) {
//請求之前檢查網絡
if (checkNet()) {
new NetTask().execute(new NetBean(request, responseClass, callback));
} else {
callback.onError(request, new IllegalStateException("請檢查網絡"));
}
}
//需要的對象:BaseRequest, Callback
private static class NetTask extends AsyncTask<NetBean, Void, NetBean> {
@Override
protected NetBean doInBackground(NetBean[] params) {
NetBean netBean = params[0];
try {
Reader readerResponse = HttpWrapper.getInstance().getReaderResponse(netBean.request);
BaseResponse response = new Gson().fromJson(readerResponse, netBean.responseClass);
netBean.response = response;
} catch (IOException e) {
e.printStackTrace();
netBean.exception = e;
} catch (JsonParseException e) {
e.printStackTrace();
netBean.exception = e;
} catch (Exception e) {
e.printStackTrace();
netBean.exception = e;
}
return netBean;
}
@Override
protected void onPostExecute(NetBean netBean) {
//出現了異常
if (netBean.exception != null) {
netBean.callback.onError(netBean.request, netBean.exception);
} else {
if (netBean.response.success()) {
netBean.callback.onSuccess(netBean.request, netBean.response);
} else {
netBean.callback.onOther(netBean.request, netBean.response);
}
}
}
}
private static class NetBean {
public NetBean(BaseRequest request, Class<? extends BaseResponse> responseClass, Callback callback) {
this.request = request;
this.callback = callback;
this.responseClass = responseClass;
}
BaseRequest request;
Callback callback;
Class<? extends BaseResponse> responseClass;
//json解析封裝的結果對象BaseResponse response
BaseResponse response;
Exception exception;
}
}
聲明 HttpWrapper 對Http封裝 :
/**
* Created by MG_ZXC on 2018/3/22.
* Http的封裝,真正執行網絡請求: OkHttp封裝
*/
public class HttpWrapper {
private volatile static HttpWrapper singleton;
private final OkHttpClient okHttpClient;
private HttpWrapper() {
okHttpClient = new OkHttpClient();
}
public static HttpWrapper getInstance() {
if (singleton == null) {
synchronized (HttpWrapper.class) {
if (singleton == null) {
singleton = new HttpWrapper();
}
}
}
return singleton;
}
//執行請求 get請求 :請求參數url?username=zxc&password=123
//post 在請求體
public Reader getReaderResponse(BaseRequest request) throws IOException {
return getResponseBody(request).charStream();
}
public String getStringResponse(BaseRequest request) throws IOException {
return getResponseBody(request).string();
}
public byte[] getBytesResponse(BaseRequest request) throws IOException {
return getResponseBody(request).bytes();
}
public InputStream getInputStreamResponse(BaseRequest request) throws IOException {
return getResponseBody(request).byteStream();
}
private ResponseBody getResponseBody(BaseRequest request) throws IOException {
Request.Builder builder = new Request.Builder();
if (request.getMethod() == BaseRequest.HttpMethod.GET) {
StringBuilder stringBuilder = new StringBuilder(request.getUrl());
Map<String, String> params = request.getParams();
if (params != null && params.size() > 0) {
stringBuilder.append("?");
Set<String> keySet = params.keySet();
for (String key : keySet) {
stringBuilder.append(key).append("=").append(URLEncoder.encode(params.get(key), "UTF-8")).append("&");
}
stringBuilder.deleteCharAt(stringBuilder.length() - 1);
}
builder.url(stringBuilder.toString()).get();
} else if (request.getMethod() == BaseRequest.HttpMethod.POST) {
//添加請求參數到請求體
FormBody.Builder formBody = new FormBody.Builder();
Map<String, String> params = request.getParams();
if (params != null && params.size() > 0) {
Set<String> keySet = params.keySet();
for (String key : keySet) {
formBody.addEncoded(key, params.get(key));
}
}
builder.url(request.getUrl()).post(formBody.build());
}
ResponseBody body = okHttpClient.newCall(builder.build()).execute().body();
return body;
}
}
使用方式:
1,在 Application 中初始化 :
NetUtil.init(getApplicationContext());
2,使用
NetUtil.sendRequest(new TestRequest(), TestResponse.class, new Callback<TestResponse>() {
@Override
public void onError(BaseRequest request, Exception e) {
Toast.makeText(mContext, e.getMessage(), Toast.LENGTH_SHORT).show();
}
@Override
public void onOther(BaseRequest request, TestResponse response) {
Toast.makeText(mContext, "其他錯誤", Toast.LENGTH_SHORT).show();
}
@Override
public void onSuccess(BaseRequest request, TestResponse response) {
TestData data = response.data;
content.setText(data.toString());
showSuccesStateView();
}
});
public class TestData {
/**
* name : sz
* score : 100
* sex : true
*/
private String name;
private int score;
private boolean sex;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
public boolean isSex() {
return sex;
}
public void setSex(boolean sex) {
this.sex = sex;
}
@Override
public String toString() {
return "TestData{" +
"name='" + name + '\'' +
", score=" + score +
", sex=" + sex +
'}';
}
}
public class TestResponse extends BaseResponse<TestData> {
}
public class TestRequest implements BaseRequest {
@Override
public HttpMethod getMethod() {
return HttpMethod.POST;
}
@Override
public String getUrl() {
return Constant.format("TestServlet");
}
@Override
public Map<String, String> getParams() {
HashMap<String, String> map = new HashMap<>();
map.put("username", "itcast");
map.put("password", "123&heima");
return map;
}
}
以上是網絡框架的基本用法。實際上在開發中還可以優化形式出現比如(在基類中進行除數據請求成功的頁面設置,在子類中進行,發送數據請求和處理數據請求正確的情況的):
在基類BaseFragment:
private OnSuccessCallback mOnSuccessCallback;
//由父類發出請求在通知子類,錯誤,空數據由父類處理
public void sendRequest(BaseRequest request, Class<? extends BaseResponse> responseClass, OnSuccessCallback onSuccessCallback) {
mOnSuccessCallback = onSuccessCallback;
NetUtil.sendRequest(request, responseClass, this);
}
@Override
public void onError(BaseRequest request, Exception e) {
//在基類中統一進行錯誤處理,比如錯誤頁面的展示
}
@Override
public void onOther(BaseRequest request, BaseResponse response) {
Toast.makeText(mContext, "其他錯誤", Toast.LENGTH_SHORT).show();
}
//請求通知子類
@Override
public void onSuccess(BaseRequest request, BaseResponse response) {
if (response == null || response.data == null) {
// 數據爲空的情況
} else {
//展示成功頁面由子類處理
mOnSuccessCallback.onSuccess(request, response);
}
}
聲明數據請求成功的情況的接口
public interface OnSuccessCallback<Res extends BaseResponse> {
public void onSuccess(BaseRequest request, Res response);
}
在子類中進行處理成功數據請求情況:
//調用父類sendRequest
sendRequest(new TestRequest(), TestResponse.class, new OnSuccessCallback<TestResponse>() {
@Override
public void onSuccess(BaseRequest request, TestResponse response) {
//獲取請求數據
}