Android中搭建自己的項目網絡框架

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) {
      //獲取請求數據
 }
發佈了79 篇原創文章 · 獲贊 62 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章