Android中网络框架

面试中经常会遇到面试管问你网络框架的原理这个问题

今天我们来讲一讲这个遇到这个问题怎么回答。

主讲咱们现在最主流的OkHttp。

首先这个题不局限于OkHttp,适用任何网络框架。

http://square.github.io/okhttp/

https://github.com/square/okhttp

OkHttp官方中文文档

http://blog.csdn.net/jackingzheng/article/details/51778793

这个很重要可以去看一看具体那些方法,怎么设置的。

分析

这个问题的考点,面试管想考你什么?

1.你对安卓中网络请求的了解

2.你平时工作中对开源项目源码的了解

3.你工作中对三方框架的封装

你对网络请求的了解

安卓原生支持2中请求HttpURLConnection和HttpClient

HttpClient

HttpClient是Apache基金会的一个开源网络库, 功能十分强大, API数量众多, 但是正是由于庞大的API数量使得我们很难在不破坏兼容性的情况下对它进行升级和扩展, 所以Android团队在提升和优化HttpClient方面的工作态度并不积极.

HttpURLConnection

HttpURLConnection是一种多用途, 轻量极的HTTP客户端, 提供的API比较简单, 可以容易地去使用和扩展. 不过在Android 2.2版本之前, HttpURLConnection一直存在着一些令人厌烦的bug. 比如说对一个可读的InputStream调用close()方法时,就有可能会导致连接池失效了。那么我们通常的解决办法就是直接禁用掉连接池的功能:

private void disableConnectionReuseIfNecessary() {    
    // 这是一个2.2版本之前的bug    
    if (Integer.parseInt(Build.VERSION.SDK) < Build.VERSION_CODES.FROYO) {    
        System.setProperty("http.keepAlive", "false");    
    }    
}

因此, 一般的推荐是在2.2之前, 使用HttpClient, 因为其bug较少. 在2.2之后, 推荐使用HttpURLConnection, 因为API简单, 体积小, 并且有压缩和缓存机制, 并且Android团队后续会继续优化HttpURLConnection.

OkHttp的特点

  • 支持 SPDY ,共享同一个Socket来处理同一个服务器的所有请求
  • 如果SPDY不可用,则通过连接池来减少请求延时
  • 无缝的支持GZIP来减少数据流量
  • 缓存响应数据来减少重复的网络请求

使用 OkHttp 无需重写您程序中的网络代码。OkHttp实现了几乎和java.net.HttpURLConnection一样的API。如果你用了 Apache HttpClient,则OkHttp也提供了一个对应的okhttp-apache 模块。

这么强大的网络请求,所以Google从Android 4.4起, 其HttpURLConnection的内部实现已经变为OkHttp。

OkHttp的重要方法

以下是一个基本的网络请求操作过程

private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
    Request request = new Request.Builder()
        .url("https://api.github.com/repos/square/okhttp/issues")
        .header("User-Agent", "OkHttp Headers.java")
        .addHeader("Accept", "application/json; q=0.5")
        .addHeader("Accept", "application/vnd.github.v3+json")
        .build();
    Response response = client.newCall(request).execute();
    if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
    System.out.println("MyServer: " + response.header("Server"));
    System.out.println("MyDate: " + response.header("Date"));
    System.out.println("MyVary: " + response.headers("Vary"));
}

在这个过程中主要是通过Diapatcher不断从RequestQueue中取出请求(Call),根据是否已缓存调用Cache或 Network这两类数据获取接口之一,从内存缓存或是服务器取得请求的数据。该引擎有同步和异步请求,同步请求通过Call.execute()直接返 回当前的Response,而异步请求会把当前的请求Call.enqueue添加(AsyncCall)到请求队列中,并通过回调(Callback) 的方式来获取最后结果。

OkHttp的总体设计

            Request.Builder

               Dispatcher

    HttpEngine          Cache

ConnnectionPool         Connnection

     Route              Platform

     Data               Server(Socket)

1.Route.java 简单说就是对地址封装的类

连接用于到达抽象原点服务器的具体路由。

创建连接时客户端有许多选项:

    - HTTP proxy: a proxy server may be explicitly configured for the client. Otherwise the {@linkplain java.net.ProxySelector proxy selector} is used. It may return multiple proxies to attempt.
    - IP address: whether connecting directly to an origin server or a proxy, opening a socket requires an IP address. The DNS server may return multiple IP addresses to attempt.
    - TLS configuration: which cipher suites and TLS versions to attempt with the HTTPS connection.

Each route is a specific selection of these options.

2.Platform.java 这个类主要是做平台适应性,针对Android2.3到5.0后的网络请求的适配支持。

访问平台特定功能。

- Server name indication (SNI): Supported on Android 2.3+.
- Session Tickets: Supported on Android 2.3+.
- Android Traffic Stats (Socket Tagging): Supported on Android 4.0+.
- ALPN (Application Layer Protocol Negotiation): Supported on Android 5.0+. The APIs were present in Android 4.4, but that implementation was unstable.

3.Connnection.java

这个类的实例通常由HTTP客户端自动创建、连接和执行。应用程序可以使用这个类来监视HTTP连接作为一个连接池的成员。

- Server Name Indication (SNI) enables one IP address to negotiate secure connections for multiple domain names.
- Application Layer Protocol Negotiation (ALPN) enables the HTTPS port (443) to be used for different HTTP and SPDY protocols.

4.ConnnectionPool.java 连接池

管理减少网络延迟的HTTP和SPDY连接复用。共享相同地址的http请求可以共享连接。

- http.keepAlive true if HTTP and SPDY connections should be pooled at all. Default is true.
- http.maxConnections maximum number of idle connections to each to keep in the pool. Default is 5.
- http.keepAliveDuration Time in milliseconds to keep the connection alive in the pool before closing it. Default is 5 minutes. This property isn’t used by HttpURLConnection.

5.Request.java HTTP请求

。这个类的实例是不可变的如果他们的身体是空的或本身不变(Builder模式)。

6.Response.java HTTP响应。
这个类的实例不是一成不变的:响应体是一一次的值,可能只消耗一次。所有其他属性都是不可变的。

7.Call.java

Call是一个已经准备好执行的请求。呼叫可以取消。由于该对象表示单个请求/响应对(流),因此不能执行两次。

8.Dispatcher.java

异步请求执行的类。

9.HttpEngine.java

HTTP处理引擎类

- It is created.
- The HTTP request message is sent with sendRequest(). Once the request is sent it is an error to modify the request headers. After sendRequest() has been called the request body can be written to if it exists.
- The HTTP response message is read with readResponse(). After the response has been read the response headers and body can be read. All responses have a response body input stream, though in some instances this stream is empty.

10.Cache.java 缓存类

缓存HTTP和HTTPS响应文件系统,以便它们可以被重用,节省时间和带宽。

- Request Count: the number of HTTP requests issued since this cache was created.
- Network Count: the number of those requests that required network use.
- Hit Count: the number of those requests whose responses were served by the cache.

强制不缓存

connection.addRequestProperty("Cache-Control", "no-cache")

强制缓存响应

try {
    connection.addRequestProperty("Cache-Control", "only-if-cached");
    InputStream cached = connection.getInputStream();
    // the resource was cached! show it
    } catch (FileNotFoundException e) {
    // the resource was not cached
}

缓存大小设置

int maxStale = 60 * 60 * 24 * 28; // tolerate 4-weeks stale
connection.addRequestProperty("Cache-Control", "max-stale=" + maxStale);

11.OkHttpClient.java 请求实体类

配置和创建http连接。大多数应用程序可以使用一个单一的okhttpclient他们所有的HTTP请求-受益于一个共享的响应缓存、线程池、连接复用,等。

同步与异步的实现

- 同步    Dispatcher会在同步执行任务队列中记录当前被执行过得任务Call,同时在当前线程中去执行Call的getResponseWithInterceptorChain()方法,直接获取当前的返回数据Response;
- 异步    首先来说一下Dispatcher,Dispatcher内部实现了懒加载无边界限制的线程池方式,同时该线程池采用了 SynchronousQueue这种阻塞队列。SynchronousQueue每个插入操作必须等待另一个线程的移除操作,同样任何一个移除操作都等 待另一个线程的插入操作。因此此队列内部其 实没有任何一个元素,或者说容量是0,严格说并不是一种容器。由于队列没有容量,因此不能调用peek操作,因为只有移除元素时才有元素。显然这是一种快 速传递元素的方式,也就是说在这种情况下元素总是以最快的方式从插入者(生产者)传递给移除者(消费者),这在多任务队列中是最快处理任务的方式。对于高 频繁请求的场景,无疑是最适合的。
- 异步执行是通过Call.enqueue(Callback responseCallback)来执行,在Dispatcher中添加一个封装了Callback的Call的匿名内部类Runnable来执行当前 的Call。这里一定要注意的地方这个AsyncCall是Call的匿名内部类。AsyncCall的execute方法仍然会回调到Call的 getResponseWithInterceptorChain方法来完成请求,同时将返回数据或者状态通过Callback来完成。

框架的二次封装

public class OkHttpHelper {

        private static OkHttpHelper mInstance = new OkHttpHelper();
        private OkHttpClient client = null;
        private Handler handler = new Handler();
        //禁止外界new对象
        private OkHttpHelper(){
            //1.创建OkHttpClient对象
            if(client==null){
                client = new OkHttpClient.Builder()
                        .writeTimeout(10, TimeUnit.SECONDS)
                        .readTimeout(10, TimeUnit.SECONDS)
                        .build();
            }
        }

        public void init(OkHttpClient client){
            this.client =client;
        }


        public static OkHttpHelper create(){
            return mInstance;
        }
        /**
         * 执行get请求
         */
        public void get(String url, final HttpCallback cb){
            //2.创建请求对象Request
            Request request = new Request.Builder()
                    .url(url)
                    .get()
                    .build();

            //3.执行请求
            Call call = client.newCall(request);
            call.enqueue(new Callback() {
                @Override
                public void onFailure(Call call, final IOException e) {
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            cb.onFail(e);
                        }
                    });
                }
                @Override
                public void onResponse(Call call, Response response) throws IOException {
                   final String data = response.body().string();

                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            cb.onSuccess(data);
                        }
                    });
                }
            });

        }

        public interface HttpCallback{
            void onFail(Exception e);
            void onSuccess(String data);
        }

    }

okio

Okio,使用起来很简单,暴露给用户的就:Okio,BufferSink,BufferSource,Buffer这几个类

Okio对文件读写操作,使用起来是很简单的,减少了很多io操作的基本代码,并且对内存和cpu使用做了优化。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值