简介:我们发现目前android网络开发框架越来越多,其实任何一个网络框架都能满足我们的应用开发需求,但是到底哪一个更好,接下来我们从源码角度来分析,到底哪一个更适合我们。


比较:首先我们通过以下几个方面的比较来分析一下(connect实现,线程池管理,可扩展性等)


第一方面:首先是connect的实现

volley

okhttp

Retrofit

AsyncHttp

XUtils

HttpURLConnectionImpl

HttpsURLConnectionImpl

HttpURLConnectionImpl

HttpsURLConnectionImpl

HttpURLConnectionImpl

HttpsURLConnectionImpl

DefaultHttpClient(httpclient)

HttpURLConnectionImpl

HttpsURLConnectionImpl


可以看到除了AsyncHttp以外,其他几种框架的connect实现都是相同的,而且可以确切的说用的都是okhttp的实现,

android框架与LINUX框架 android 网络框架对比_android框架与LINUX框架

到这里也许有人会提出疑问,命名各个框架都是有自己的connect,为什么都用的是volley的呢?

下面从源码角度来分析一下。

以volley为例分析,其他都是相同的,

/**
     * Create an {@link HttpURLConnection} for the specified {@code url}.
     */
    protected HttpURLConnection createConnection(URL url) throws IOException {
        return (HttpURLConnection) url.openConnection();
    }

可以看到都是通过URL的openConnection打开的连接,

到URL.java中看一下:

public URLConnection openConnection(Proxy proxy) throws IOException {
        if (proxy == null) {
            throw new IllegalArgumentException("proxy == null");
        }
        return streamHandler.openConnection(this, proxy);
    }



下面只要知道streamHandler是谁可以了,

void setupStreamHandler() {
        .... //忽略掉无用代码

        // Fall back to a built-in stream handler if the user didn't supply one
        if (protocol.equals("file")) {
            streamHandler = new FileHandler();
        } else if (protocol.equals("ftp")) {
            streamHandler = new FtpHandler();
        } else if (protocol.equals("http")) {
            try {
                String name = "com.android.okhttp.HttpHandler";     //可以看到这里就会实例化okhttp内部的类,接下来就是按照okhttp内部的实现
                streamHandler = (URLStreamHandler) Class.forName(name).newInstance();
            } catch (Exception e) {
                throw new AssertionError(e);
            }
        } else if (protocol.equals("https")) {
            try {
                String name = "com.android.okhttp.HttpsHandler";
                streamHandler = (URLStreamHandler) Class.forName(name).newInstance();
            } catch (Exception e) {
                throw new AssertionError(e);
            }
        } else if (protocol.equals("jar")) {
            streamHandler = new JarHandler();
        }
        if (streamHandler != null) {
            streamHandlers.put(protocol, streamHandler);
        }
    }

从上面可以看出来,无论任何框架,只要调用了Url.connect(),在系统源码中自动会使用okhttp的connection去处理

这里面需要特殊提出来Retrofix,他与其他的有所不同,是完全使用okhttp实现的,

/**
   * The factory used to create {@linkplain okhttp3.Call OkHttp calls} for sending a HTTP requests.
   * Typically an instance of {@link OkHttpClient}.
   */
  public okhttp3.Call.Factory callFactory() {
    return callFactory;
  }



下面说一下特殊的AnysnHttp,一款老大哥级的网络框架,也是我使用的第一个网络框架,他的底层实现以来httpclient,这个不知道具体什么原因,已经被android废弃了,所以我也不再过多介绍了,简单的列一下代码

AsyncHttpRequest.java

private void makeRequest() throws IOException {
        if (isCancelled()) {
            return;
        }

        // Fixes #115
        if (request.getURI().getScheme() == null) {
            // subclass of IOException so processed in the caller
            throw new MalformedURLException("No valid URI scheme was provided");
        }

        if (responseHandler instanceof RangeFileAsyncHttpResponseHandler) {
            ((RangeFileAsyncHttpResponseHandler) responseHandler).updateRequestHeaders(request);
        }

        HttpResponse response = client.execute(request, context);

        if (isCancelled()) {
            return;
        }

        // Carry out pre-processing for this response.
        responseHandler.onPreProcessResponse(responseHandler, response);

        if (isCancelled()) {
            return;
        }

        // The response is ready, handle it.
        responseHandler.sendResponseMessage(response);

        if (isCancelled()) {
            return;
        }

        // Carry out post-processing for this response.
        responseHandler.onPostProcessResponse(responseHandler, response);
    }




通过上面的比较,真正连接工作的地方实际上是相同的,所以性能相差是不大的,但是由于其他调用的是okhttp的类,而且是反射等方式,所以okhttp理论上应该是优势最大的,但经过笔者测试,几乎没有差别。


第二方面 :下面比较各个内部连接池的实现。

首先OkHttp

/external/okhttp/okhttp/src/main/java/com/squareup/okhttp/Dispatcher.java


public synchronized ExecutorService getExecutorService() { if (executorService == null) { executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false)); } return executorService; }

可以看到是一个无限大的core_size=0的线程池来管理所有的网络请求


再看volley


RequestQueue.java




mDispatchers = new NetworkDispatcher[threadPoolSize];
	public class NetworkDispatcher extends Thread


可以看到volley简单粗暴的就是new出来几个线程,




再来看xutils


HttpTask.java


private static final PriorityExecutor HTTP_EXECUTOR = new PriorityExecutor(5, true);


public PriorityExecutor(int poolSize, boolean fifo) {
        BlockingQueue<Runnable> mPoolWorkQueue =
                new PriorityBlockingQueue<Runnable>(MAXIMUM_POOL_SIZE, fifo ? FIFO_CMP : FILO_CMP);
        mThreadPoolExecutor = new ThreadPoolExecutor(
                poolSize,
                MAXIMUM_POOL_SIZE,
                KEEP_ALIVE,
                TimeUnit.SECONDS,
                mPoolWorkQueue,
                sThreadFactory);
    }




可以看到仍然使用的是线程池,只是core_max是5,就是说会始终维持线程,

再来看AnysnHttp

在AsyncHttpClient.java 中





protected ExecutorService getDefaultThreadPool() {
        return Executors.newCachedThreadPool();
    }

可以看到使用的是cache的线程池,来进行管理的。可以理解为与okhttp线程池管理方式相同,


最后retrofit,因为retrofit底层完全用的是okhttp,所以他和okhttp使用的线程管理方式也是一样的,不再介绍。

最后总结一下上面所说的三种线程池管理方式。

其实很难说哪个好哪个不好,但是volley的方式过于暴力,

1.网络请求频率比较低,仍然有多个线程占用,这是一种浪费,

2.当大量的网络请求到来时,线程也没有办法增加,造成请求阻塞,但是他有个好处就是不会因为大量网络请求到来的时候,引起oom


对于使用线程池的okhttp和xutils,各有各自的优势,而且都是允许用户自定义线程池的,所以总体来说各有优势。


今天先从整体架构角度来分析一下,

稍后会对各个细节做进一步的比较。