优雅设计封装基于Okhttp3的网络框架(六):HttpHeader接口设计实现 及 Response、Request封装实现

来源:互联网 发布:狄克斯特拉算法图解 编辑:程序博客网 时间:2024/05/19 01:10

到目前为止,多线程下载功能设计、编写、优化工作已经完成,但是网络框架编写工作并没有完成,此篇将完成Http核心架构,编写的新功能还是围绕在http请求上,涉及到的知识点:

  • httpHeader的接口定义和实现
  • http请求头和响应头访问编写
  • http状态码定义
  • http中的 response封装、request接口封装和实现

(建议阅读此篇文章之前,需理解前两篇文章的讲解,此系列文章是环环相扣,不可缺一,链接如下:)
优雅设计封装基于Okhttp3的网络框架(一):Http网络协议与Okhttp3解析
优雅设计封装基于Okhttp3的网络框架(二):多线程下载功能原理设计 及 简单实现
优雅设计封装基于Okhttp3的网络框架(三):多线程下载功能核心实现 及 线程池、队列机制解析
优雅设计封装基于Okhttp3的网络框架(四):多线程下载添加数据库支持(greenDao)及 进度更新
优雅设计封装基于Okhttp3的网络框架(五):多线程、单例模式优化 及 volatile、构建者模式使用解析


一. Http核心架构实现

下面将完成网络框架核心架构,考虑到程序的扩展性,首要编写的是接口,采用设计模式将相关的接口预留出来。

1. HttpHeader的接口定义和实现

(1)NameValueMap键值对接口

在定义接口之前,需要先定义一个键值对接口NameValueMap继承Map接口,提供一些相关接口访问,实现比较简单,代码如下:

public interface NameValueMap<K, V> extends Map<K, V> {    String get(String name);    void set(String name, String value);    void setAll(Map<String, String> map);}

(2)HttpHeader实现NameValueMap

HttpHeader是实现了整个Http请求的接口,该类在定义时实现NameValueMap接口后,需要实现很多方法。既然HttpHeader实现了键值对接口,所以在其内部需要维护一个private Map<String, String> mMap,此时可以根据此HashMap来完善待实现方法。

/** * @function Http请求、响应头部字段访问封装 * @author lemon Guo */public class HttpHeader implements NameValueMap<String, String> {    private Map<String, String> mMap = new HashMap<>();    /*    *   以下都是实现Map接口后需要实现的方法    * */    @Override    public String get(String name) {        return mMap.get(name);    }    @Override    public void set(String name, String value) {        mMap.put(name, value);    }    @Override    public void setAll(Map<String, String> map) {        mMap.putAll(map);    }    @Override    public int size() {        return mMap.size();    }    @Override    public boolean isEmpty() {        return mMap.isEmpty();    }    @Override    public boolean containsKey(Object o) {        return mMap.containsKey(o);    }    @Override    public boolean containsValue(Object value) {        return mMap.containsValue(value);    }    @Override    public String get(Object o) {        return mMap.get(o);    }    @Override    public String put(String key, String value) {        return mMap.put(key, value);    }    @Override    public String remove(Object key) {        return mMap.remove(key);    }    @Override    public void putAll(Map<? extends String, ? extends String> map) {        mMap.putAll(map);    }    @Override    public void clear() {        mMap.clear();    }    ......}

2. Http请求头和响应头访问编写

下面就是对Http请求头接口上的访问和包装,首先需要知道Http请求头包含的内容,但是Http请求头、响应头所包含的内容是比较多的,这里只在此封装较为常见的字段:

/** * @function Http请求、响应头部字段访问封装 * @author lemon Guo */public class HttpHeader implements NameValueMap<String, String> {    //常用的 Http字段    public final static String ACCEPT = "Accept";    public final static String PRAGMA = "Pragma";    public final static String PROXY_CONNECTION = "Proxy-Connection";    public final static String USER_AGENT = "User-Agent";    public final static String ACCEPT_ENCODING = "accept-encoding";    public final static String CACHE_CONTROL = "Cache-Control";    public final static String CONTENT_ENCODING = "Content-Encoding";    public final static String CONNECTION = "Connection";    public final static String CONTENT_LENGTH = "Content-length";    public static final String CONTENT_TYPE = "Content-Type";    private Map<String, String> mMap = new HashMap<>();    /*    *   以上Http字段的get/set方法    * */    public String getAccept() {        return get(ACCEPT);    }    public void setAccept(String value) {        set(ACCEPT, value);    }    ......    /*    *   以下都是实现Map接口后需要实现的方法    * */    ......}

以上已经封装完成HttpHeader类——Http头部相关字段的访问。接下来还需要对Http请求方式进行一个简单的封装,除了常用的GET、POST方式还有其它5种,通过一个枚举进行封装即可。代码如下:

/** * @function Http请求方式封装 * @author lemon Guo */public enum HttpMethod {    GET, POST, TRACE, PUT, DELETE, CONNECTION, OPTIONS}

3. Http状态码定义

Http的状态码非常多,分布于100~600,根据状态码也分成了几种不同的类型,这里也是封装每种类型中较为常见的,同样采用枚举方式。

  • HttpStatus类提供构造方法,参数为状态码和含义。
  • 声明状态码枚举类型。
  • 对外提供方法isSuccess,通过判断字节码返回代表请求是否成功的boolean值
  • 对外提供方法getValue,通过传入的参数状态码数字,返回状态码枚举类型。
/** * @function Http状态码封装 * @author lemon Guo */public enum HttpStatus {    CONTINUE(100, "Continue"),    SWITCHING_PROTOCOLS(101, "Switching Protocols"),    OK(200, "OK"),    CREATED(201, "Created"),    Accepted(202, "Accepted "),    NON_AUTHORITATIVE_INFORMATION(203, "Non-Authoritative Information"),    NO_CONTENT(204, "No Content"),    RESET_CONTENT(205, "Reset Content"),    MULTIPLE_CHOICES(300, "Multiple Choices"),    MOVED_PERMANENTLY(301, "Moved Permanently"),    FOUND(302, "Found"),    SEE_OTHER(303, "See Other"),    USE_PROXY(305, "Use Proxy "),    UNUSED(306, "Unused"),    TEMPORARY_REDIRECT(307, "Temporary Redirect"),    BAD_REQUEST(400, "Bad Request"),    PAYMENT_REQUIRED(402, "Payment Required"),    FORBIDDEN(403, "Forbidden"),    NOT_FOUND(404, "Not_Found"),    METHOD_NOT_ALLOWED(405, "Method Not Allowed "),    NOT_ACCEPTABLE(406, "Not Acceptable"),    REQUEST_TIMEOUT(408, "Request Timeout"),    CONFLICT(409, "Conflict"),    GONE(410, "Gone"),    LENGTH_REQUIRED(411, "Length Required"),    PAYLOAD_TOO_LARGE(413, "Payload Too Large"),    URI_TOO_LONG(414, "URI Too Long"),    UNSUPPORTED_MEDIA_TYPE(415, "Unsupported Media Type  Server Error"),    FAILED(417, "Failed Server Error"),    UPGRADE_REQUIRED(426, "Upgrade Required"),    INTERNAL_SERVER_ERROR(500, "Internal Server Error"),    NOT_IMPLEMENTED(501, "Not Implemented"),    BAD_GATEWAY(502, "Bad_Gateway"),    SERVICE_UNAVAILABLE(503, "Service Unavailable"),    GATEWAY_TIMEOUT(504, "Gateway Timeout"),    HTTP_VERSION_NOT_SUPPORTED(505, "HTTP Version Not Supported ");    private int mCode;    private String mMessage;    private HttpStatus(int code, String message) {        this.mCode = code;        this.mMessage = message;    }    public boolean isSuccess() {        int value = mCode / 100;        if (value == 2) {            return true;        }        return false;    }    public static HttpStatus getValue(int value) {        for (HttpStatus httpStatus : values()) {            if (value == httpStatus.mCode) {                return httpStatus;            }        }        return null;    }}



二. Http中Response、Request封装实现

在第一大点编码中的类与接口实现比较基础,难度不大,更像是实现Http核心框架前做的准备,所以说前期接口设计封装直接决定整个程序的扩展性,需谨慎考虑全面。而接下来将对Http中的Response响应、Request请求进行封装。

1. Response接口封装

首先思考一下Response接口中需要封装的方法,状态码和body的获取必不可少,另外可以考虑状态码信息获取、字节长度获取方法。

(1)Header

在封装Response之前还需要先封装一个接口 —– Header,它是对所有响应头、请求头的封装,而接口中只有一个getHeaders 方法,意味着响应头、请求头都会对其实现。代码如下:

/** * @function 对所有响应头、请求头的封装 * @author lemonGuo */public interface Header {    HttpHeader getHeaders();}

(2)HttpResponse接口

该接口继承于Header、Closeable接口,组成为:

  • 必须要有获取状态码getStatus()方法、获取Body输入流getBody()方法、关闭输入流close()方法。
  • 其次为了考虑全面,新增了获取状态码代表信息getStatusMsg()方法、获取字节长度getContentLength()方法
/** * @funtion Http响应接口 * @author nate */public interface HttpResponse extends Header, Closeable {    HttpStatus getStatus();    String getStatusMsg();    InputStream getBody() throws IOException;    void close();    long getContentLength();}

(3)抽象类AbstractHttpResponse

以上HttpResponse 接口定义好之后,可以定义响应类实现,可是在此之前还需要定义一个抽象类AbstractHttpResponse,由它来实现HttpResponse 接口。

抽象类的好处

抽象类可以拥有自己的成员变量和已实现的方法,比接口的功能更加丰富。在封装框架过程中,可借由抽象类来实现一些内部的方法,更易扩展。

编码实现

在此抽象类中处理响应数据时,需要多判断一点:即是否为压缩数据,若是则对数据流进行处理后再作返回。该抽象类主要是对响应数据多做了一层判断,相当于一个过滤网。

为了处理压缩这种情况,该抽象类实现了HttpResponse 接口中的getBody()close(),做了一些共性的预处理操作,同时为具体实现的子类留出了getBodyInternal()closeInternal()抽象方法。

/** * @function AbstractHttpResponse 数据响应抽象类(继承HttpResponse接口) * @author lemon guo */public abstract class AbstractHttpResponse implements HttpResponse {    private static final String GZIP = "gzip";    private InputStream mGzipInputStream;    @Override    public void close()  {        if (mGzipInputStream != null) {            try {                mGzipInputStream.close();            } catch (IOException e) {                e.printStackTrace();            }        }        closeInternal();    }    @Override    public InputStream getBody() throws IOException {        InputStream body = getBodyInternal();        if (isGzip()) {            return getBodyGzip(body);        }        return body;    }    protected abstract InputStream getBodyInternal() throws IOException;    protected abstract void closeInternal();    private InputStream getBodyGzip(InputStream body) throws IOException {        if (this.mGzipInputStream == null) {            this.mGzipInputStream = new GZIPInputStream(body);        }        return mGzipInputStream;    }    private boolean isGzip() {        String contentEncoding = getHeaders().getContentEncoding();        if (GZIP.equals(contentEncoding)) {            return true;        }        return false;    }}

(4)实现类OkHttpResponse

回顾以上,已完成的接口、抽象类都是在为Http响应实现类做准备,最后定义实现类OkHttpResponse,继承抽象类AbstractHttpResponse,实现父类的方法:

  • 实现类内部定义两个重要成员变量:响应类mResponse和Http字段访问类mHeaders 。
  • 为实现类提供构造方法,参数为响应类Response。
  • 实现类内部待实现的方法具体编码都依赖于以上两个成员变量。

代码量虽然不少,但是实现简单,查看即可理解,代码如下:

/** * @funtion: 实现类OkHttpResponse * @author lemon Guo */public class OkHttpResponse extends AbstractHttpResponse {    private Response mResponse;    private HttpHeader mHeaders;    public OkHttpResponse(Response response) {        this.mResponse = response;    }    @Override    protected InputStream getBodyInternal() {        return mResponse.body().byteStream();    }    @Override    protected void closeInternal() {        mResponse.body().close();    }    @Override    public HttpStatus getStatus() {        return HttpStatus.getValue(mResponse.code());    }    @Override    public String getStatusMsg() {        return mResponse.message();    }    @Override    public long getContentLength() {        return mResponse.body().contentLength();    }    @Override    public HttpHeader getHeaders() {        if (mHeaders == null) {            mHeaders = new HttpHeader();        }        for (String name : mResponse.headers().names()) {            mHeaders.set(name, mResponse.headers().get(name));        }        return mHeaders;    }}


2. HttpRequest接口封装和实现

接下来完成Http请求上的接口设计封装,其实在真正了解以上Response的系列接口、抽象类、实现类设计实现后,会发现两者的“套路”其实很相似。

(1)HttpRequest接口

首先来思考接口中的方法,一个请求很关键的是请求头,然后是请求方式,最后是请求中传递的参数信息。

前期考虑封装很重要,需设计全面,代码实现如下:

/** * @funtion HttpRequest接口设计 * @author nate */public interface HttpRequest extends Header {    HttpMethod getMethod();    URI getUri();    OutputStream getBody();    HttpResponse execute() throws IOException;}

(2)抽象类AbstractHttpRequest

如上,接口定义完之后,定义抽象类继承该接口,实现了HttpResponse 接口中的getBody()getHeaders()execute()做一些共性的处理操作,同时为具体实现的子类留出了executeInternal(HttpHeader mHeader)getBodyOutputStream()抽象方法。

同样为了考虑压缩情况,在实现父类的方法中需要判断当前请求过程中是否支持Zip压缩,根据判断结果来决定是否需要进一步处理输出流。

请求、响应抽象类中的压缩判断代码相同,都是为了考虑压缩情况,在接口的基础上多做了一层封装。编码实现并不难,如下:

/** * @function AbstractHttpRequest 数据响应抽象类(继承HttpRequest接口) * @author lemon guo */public abstract class AbstractHttpRequest implements HttpRequest {    private static final String GZIP = "gzip";    private HttpHeader mHeader = new HttpHeader();    private ZipOutputStream mZip;    private boolean executed;    @Override    public HttpHeader getHeaders() {        return mHeader;    }    @Override    public OutputStream getBody() {        OutputStream body = getBodyOutputStream();        if (isGzip()) {            return getGzipOutStream(body);        }        return body;    }    private OutputStream getGzipOutStream(OutputStream body) {        if (this.mZip == null) {            this.mZip = new ZipOutputStream(body);        }        return mZip;    }    private boolean isGzip() {        String contentEncoding = getHeaders().getContentEncoding();        if (GZIP.equals(contentEncoding)) {            return true;        }        return false;    }    @Override    public HttpResponse execute() throws IOException {        if (mZip != null) {            mZip.close();        }        HttpResponse response = executeInternal(mHeader);        executed = true;        return response;    }    protected abstract HttpResponse executeInternal(HttpHeader mHeader) throws IOException;    protected abstract OutputStream getBodyOutputStream();}

(3)请求流抽象处理BufferHttpRequest

到这里你会发现接下来不是应该创建实现类么?请求的封装在此之前还需要再对抽象类进行一层封装—–BufferHttpRequest,继承于AbstractHttpRequest,在其中对请求流多做一步操作:

  • 内部维护一个成员变量:输出字节流ByteArrayOutputStream
  • 在实现于父类的getBodyOutputStream方法中将成员变量输出流返回出去。
  • 在实现于父类的executeInternal(HttpHeader header)方法中将成员变量内存数据转换为字节数组类型,即请求时传递参数的信息,再定义抽象方法将HttpHeader、字节数组两个参数传出。相当于在原理基础上对输出流多做了一步处理:转换为字节数组类型。

代码实现如下:

/** * @funtion 请求流抽象处理BufferHttpRequest * @author lemon Guo */public abstract class BufferHttpRequest extends AbstractHttpRequest {    private ByteArrayOutputStream mByteArray = new ByteArrayOutputStream();    protected OutputStream getBodyOutputStream() {        return mByteArray;    }    protected HttpResponse executeInternal(HttpHeader header) throws IOException {        byte[] data = mByteArray.toByteArray();        return executeInternal(header, data);    }    protected abstract HttpResponse executeInternal(HttpHeader header, byte[] data) throws IOException;}

(4)实现类OkHttpRequest

由于请求不同于响应的特殊性,需要考虑到头部信息,在封装两次抽象类后,最后编写实现类OkHttpRequest此类继承于BufferHttpRequest ,具体实现为:

  • 定义成员变量OkHttpClient及参数HttpMethodUrl来实现Okhttp的请求过程。
  • 提供构造方法初始化以上3个成员变量。
  • 实现抽象方法getMethod()getUri()。(这两个抽象方法实现简单,只需返回成员变量即可)
  • 实现抽象方法executeInternal(HttpHeader header, byte[] data)
    • 首先需要判断请求方式是否为POST,若是则意味着需要处理RequestBody,将客户端传递的data参数封装到RequestBody其中。
    • 创建请求Request.Builder,传入URL、请求方式、RequestBody参数。
    • 接着对header进行处理,循环该参数将所有请求头封装至Request.Builder
    • 最后封装完毕,调用成员变量OkHttpClient进行请求,获取到响应数据Response
    • 创建上一点封装好的响应实现类HttpResponse,将响应数据传入其构造方法,最后将响应实现类HttpResponse返回出去即可。

此部分较为重要,一定要将逻辑整理清楚,代码实现如下:

/** * @function 实现类OkHttpRequest * @author lemon guo */public class OkHttpRequest extends BufferHttpRequest {    private OkHttpClient mClient;    private HttpMethod mMethod;    private String mUrl;    public OkHttpRequest(OkHttpClient client, HttpMethod method, String url) {        this.mClient = client;        this.mMethod = method;        this.mUrl = url;    }    @Override    protected HttpResponse executeInternal(HttpHeader header, byte[] data) throws IOException {        boolean isBody = mMethod == HttpMethod.POST;        RequestBody requestBody = null;        if (isBody) {            requestBody = RequestBody.create(MediaType.parse("application/x-www-form-urlencoded"), data);        }        Request.Builder builder = new Request.Builder().url(mUrl).method(mMethod.name(), requestBody);        for (Map.Entry<String, String> entry : header.entrySet()) {            builder.addHeader(entry.getKey(), entry.getValue());        }        Response response = mClient.newCall(builder.build()).execute();        System.out.println("fuck "+response.body().contentLength());        return new OkHttpResponse(response);    }    @Override    public HttpMethod getMethod() {        return mMethod;    }    @Override    public URI getUri() {        return URI.create(mUrl);    }}


3. 测试

在创建的module文件夹下会自动生成一个test文件夹,供开发人员测试所用,在这里可以编写一个简单的网络代码来测试以上编码工作是否正确,代码如下:

public class ExampleUnitTest {    @Test    public void addition_isCorrect() throws Exception {        assertEquals(4, 2 + 2);        OkHttpClient client = new OkHttpClient();        OkHttpRequest request = new OkHttpRequest(client, HttpMethod.GET, "http://www.baidu.com");        HttpResponse response = request.execute();        String content = null;        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(response.getBody()));        while ((content = bufferedReader.readLine()) != null){            System.out.println(content);        }        response.close();    }}

结果显示

这里写图片描述

以上代码逻辑为GET方式请求百度,打印出请求到的资源数据,成功显示,证明以上编码无误。




三. 工厂模式封装HttpReques创建

此部分将对HttpRequest对象进行封装,以上工作对于网络框架而言是底层实现,那具体的网络请求是调用OkhttpRequest来完成,但是此次封装的网络框架不仅支持Okhttp网络框架请求方式,还支持原生UrlConnection请求,所以考虑到扩展性,完成原生请求,只需继承HttpReques接口实现功能即可,但是对于上层业务调用,还是要对请求对象进行封装。

通过一种机制来封装HttpReques对象给上层调用,对于上层而言只需获取HttpReques对象即可,至于该对象是通过Okhttp还是UrlConnection获取并不关注。

1. 接口HttpRequestFactory

通过此接口的名字便知它内部采用的是工厂模式,而方法就是获取HttpReques对象:

/** * @function 接口HttpRequestFactory(获取HttpRequest对象) * @author lemon Guo */public interface HttpRequestFactory {    HttpRequest createHttpRequest(URI uri, HttpMethod method) throws IOException;}

工厂设计模式

工厂设计模式可以解决的问题:

  • 不会向上层曝露对象创建的复杂过程,只提供结果。
  • 工厂模式是典型的解耦式设计,使职责单一化。

类图

这里写图片描述

结合此类图至编写的接口:

  • HttpRequestFactory就是工厂模式中的Creator
  • 接口中返回的HttpRequest 对象就是工厂模式中的Product
  • 下面就需要创建实现类继承接口来“生产”Product,此实现类相当于工厂模式中的ConcreteCreator

2. 实现类

通过以上结合工厂模式的分析后,得知此类就是“生产”HttpRequest 对象的具体实现类,它继承于HttpRequestFactory 接口,具体实现:

  • 定义成员变量OkhttpClient
  • 为此类提供构造方法初始化成员变量
  • 实现接口中的createHttpRequest方法,即创建OkHttpRequest 对象并返回。
  • 再提供一些基本方法setConnectionTimeOut设置请求超时时间,setReadTimeOutsetWriteTimeOut设置读写时间。(若有其他需求,此处可继续增加)
/** * @function 实现类OkHttpRequestFactory(返回HttpRequest对象) * @author lemon Guo */public class OkHttpRequestFactory implements HttpRequestFactory {    private OkHttpClient mClient;    public OkHttpRequestFactory() {        this.mClient = new OkHttpClient();    }    public OkHttpRequestFactory(OkHttpClient client) {        this.mClient = client;    }    public void setReadTimeOut(int readTimeOut) {        this.mClient = mClient.newBuilder().                readTimeout(readTimeOut, TimeUnit.MILLISECONDS).                build();    }    public void setWriteTimeOut(int writeTimeOut) {        this.mClient = mClient.newBuilder().                writeTimeout(writeTimeOut, TimeUnit.MILLISECONDS).                build();    }    public void setConnectionTimeOut(int connectionTimeOut) {        this.mClient = mClient.newBuilder().                connectTimeout(connectionTimeOut, TimeUnit.MILLISECONDS).                build();    }    @Override    public HttpRequest createHttpRequest(URI uri, HttpMethod method) {        return new OkHttpRequest(mClient, method, uri.toString());    }}

3. 供上层调用HttpRequestProvider

接下来需要将OkHttpRequestFactory 的具体实现再做一次封装供上层使用,创建一个类HttpRequestProvider

  • 定义成员变量HttpRequestFactory,用于创建HttpRequest对象。
  • 提供构造方法来初始化成员变量。注意这里会判断项目中是否使用Okhttp:
    • 若是,则创建OkHttpRequestFactory
    • 若不是,意味着请求需依赖原生UrlConnction,使用原生的Factory(后续会编写)。
  • 提供方法getHttpRequest(URI uri, HttpMethod httpMethod),底层会调用HttpRequestFactory来创建HttpRequest对象。
/** * @function 封装请求HttpRequestProvider,供上层调用 * @author lemon Guo */public class HttpRequestProvider {    private static boolean OKHTTP_REQUEST = Utills.isExist("okhttp3.OkHttpClient", HttpRequestProvider.class.getClassLoader());    private HttpRequestFactory mHttpRequestFactory;    public HttpRequestProvider() {        if (OKHTTP_REQUEST) {            mHttpRequestFactory = new OkHttpRequestFactory();        } else {            mHttpRequestFactory = new OriginHttpRequestFactory();        }    }    public HttpRequest getHttpRequest(URI uri, HttpMethod httpMethod) throws IOException {        return mHttpRequestFactory.createHttpRequest(uri, httpMethod);    }    public HttpRequestFactory getHttpRequestFactory() {        return mHttpRequestFactory;    }    public void setHttpRequestFactory(HttpRequestFactory httpRequestFactory) {        mHttpRequestFactory = httpRequestFactory;    }}

最后,供给上层调用的就是HttpRequestProvider 类,它可以根据不同的条件创建不同Http请求library,这样便实现多个library类库切换的条件判断使用。




四. 总结

1. 本篇总结

这里写图片描述

以上截图显示着此篇博文完成的编码内容,看起来编码量很多,但是实现起来逻辑并不复杂。其中含有大量的接口、抽象类,这些都是在为程序拓展性做准备,在下一篇博文中将添加新的类库请求支持,你会发现在此基础上只需增加3个类即可,充分体现出了程序的扩展性。

我们编写的顺序基本是 接口、枚举 –> 抽象类 –>实现类,

  • 在第一点准备工作中完成了HttpHeader的设计实现、Http请求头和响应头访问编写、Http状态码封装,这些并不复杂,只是最基本的封装思想。
  • 在第二点中主要对Http中的RequestResponse进行设计封装,这里为了程序扩展性逻辑稍显复杂,先从接口开始定义,然后在此基础上定义抽象类实现接口,在其内部进行共性操作,再留出抽象方法。
  • 第三点在现有的请求方式上再次封装,采用工厂模式,提供最简洁方法供上层调用。

此篇文章完成的部分还是有些多,需将逻辑捋清楚,但每个类实现并不难,重要的是它们之间的封装关系,可对应以下代码理解。

对应第六篇至以前所完成的源码


2. 下篇预告

在下一篇博文中将添加新功能——原生请求的类库支持,你会发现在此基础上只需增加3个类即可,充分体现出了程序的扩展性。新增功能如下:

  • 原生HttpUrlConnction请求和响应
  • 业务层多线程分发处理
  • 移除请求
  • 请求成功类型转换包装处理


若有错误,虚心指教~

阅读全文
0 0