Android开源框架Afinal第二篇——庖丁解牛,深入调查

---恢复内容开始---

还是继续FinalHttp,这个类涉及到的东西还是挺多的。

一:线程池

首先我们看到FinalHttp类里面有两个跟线程池相关的两个静态类

private static final ThreadFactory  sThreadFactory = new ThreadFactory() {
        private final AtomicInteger mCount = new AtomicInteger(1);
        public Thread newThread(Runnable r) {
            Thread tread = new Thread(r, "FinalHttp #" + mCount.getAndIncrement());
            tread.setPriority(Thread.NORM_PRIORITY - 1);
            return tread;
        }
    };
    
    private static final Executor executor =Executors.newFixedThreadPool(httpThreadCount, sThreadFactory);

ThreadFactory是一个工厂模式,下面是一个线程池Executor。线程池里new出来的线程都是这个ThreadFactory孵化出来的线程,赋予了原始信息线程名字都是FinalHttp #n,(这里还有一个AtomicInteger,这是一个原子操作类,主要用于在高并发环境下的高效程序处理。使用非阻塞算法来实现并发控制。)并且设置线程优先级。

看到这个类里面很多方法都有传递这个Executor线程池,没到执行一个线程我想都是executor 加入线程池去执行的,这样的线程管理是比较高效和出色的。

二:构造方法

这个构造方法有超多默认配置,蛋疼了米有?

 public FinalHttp() {
        BasicHttpParams httpParams = new BasicHttpParams();

        ConnManagerParams.setTimeout(httpParams, socketTimeout);
        ConnManagerParams.setMaxConnectionsPerRoute(httpParams, new ConnPerRouteBean(maxConnections));
        ConnManagerParams.setMaxTotalConnections(httpParams, 10);

        HttpConnectionParams.setSoTimeout(httpParams, socketTimeout);
        HttpConnectionParams.setConnectionTimeout(httpParams, socketTimeout);
        HttpConnectionParams.setTcpNoDelay(httpParams, true);
        HttpConnectionParams.setSocketBufferSize(httpParams, DEFAULT_SOCKET_BUFFER_SIZE);

        HttpProtocolParams.setVersion(httpParams, HttpVersion.HTTP_1_1);

        SchemeRegistry schemeRegistry = new SchemeRegistry();
        schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
        schemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
        ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager(httpParams, schemeRegistry);

        httpContext = new SyncBasicHttpContext(new BasicHttpContext());
        httpClient = new DefaultHttpClient(cm, httpParams);
        httpClient.addRequestInterceptor(new HttpRequestInterceptor() {
            public void process(HttpRequest request, HttpContext context) {
                if (!request.containsHeader(HEADER_ACCEPT_ENCODING)) {
                    request.addHeader(HEADER_ACCEPT_ENCODING, ENCODING_GZIP);
                }
                for (String header : clientHeaderMap.keySet()) {
                    request.addHeader(header, clientHeaderMap.get(header));
                }
            }
        });

        httpClient.addResponseInterceptor(new HttpResponseInterceptor() {
            public void process(HttpResponse response, HttpContext context) {
                final HttpEntity entity = response.getEntity();
                if (entity == null) {
                    return;
                }
                final Header encoding = entity.getContentEncoding();
                if (encoding != null) {
                    for (HeaderElement element : encoding.getElements()) {
                        if (element.getName().equalsIgnoreCase(ENCODING_GZIP)) {
                            response.setEntity(new InflatingEntity(response.getEntity()));
                            break;
                        }
                    }
                }
            }
        });

        httpClient.setHttpRequestRetryHandler(new RetryHandler(maxRetries));

        clientHeaderMap = new HashMap<String, String>();
        
    }

 httpParams是一个网络链接配置类,比如设置最大连接数,路由最大连接数,读取超时时间,连接超时时间,套接字缓冲大小。这里连接数都是10次,超市时间都是10秒,其实这样本来就是一种网络请求任务的拖慢。再下面还有个重复次数,竟然是5次,如果网络不好的话有可能要重试5次,这样严重影响了上层的UI交互。不过有个亮点就是g-zip,Gzip开启以后会将输出的数据进行压缩的处理,这样就会减小通过网络传输的数据量,提高读取的速度。

 

三:AfinalHttp里的方法

1.配置方法:

public void configCharset(String charSet){
        if(charSet!=null && charSet.trim().length()!=0)
            this.charset = charSet;
    }

    public void configCookieStore(CookieStore cookieStore) {
        httpContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
    }


    public void configUserAgent(String userAgent) {
        HttpProtocolParams.setUserAgent(this.httpClient.getParams(), userAgent);
    }
    

    /**
     * 设置网络连接超时时间,默认为10秒钟
     * @param timeout
     */
    public void configTimeout(int timeout){
        final HttpParams httpParams = this.httpClient.getParams();
        ConnManagerParams.setTimeout(httpParams, timeout);
        HttpConnectionParams.setSoTimeout(httpParams, timeout);
        HttpConnectionParams.setConnectionTimeout(httpParams, timeout);
    }

    /**
     * 设置https请求时  的 SSLSocketFactory
     * @param sslSocketFactory
     */
    public void configSSLSocketFactory(SSLSocketFactory sslSocketFactory) {
        Scheme scheme = new Scheme("https", sslSocketFactory, 443);
        this.httpClient.getConnectionManager().getSchemeRegistry().register(scheme);
    }
    
    /**
     * 配置错误重试次数
     * @param retry
     */
    public void configRequestExecutionRetryCount(int count){
        this.httpClient.setHttpRequestRetryHandler(new RetryHandler(count));
    }

这些配置应该都在发起请求之前执行,不过设置超时这个方法太狗血了,竟然三种超时都是10s,那是不是意味着有可能3种超时加起来就要30s,半分钟啊!

2.请求方法入口,有常用的get()方法,post()方法,download()文件下载方法得各种重载。

那些重载方法这就不贴了,都是调用的HttpHandler类去处理的。

这里我们看到有几个东西:

AjaxParams,这是一个设置url参数的类。

笔者在实际使用过程中发现,有两个缺陷。

一个是里头用到的是ConcurrentHashMap,我们看一看java中几种常用集合的对比。

Map

HashMap 无序

HashTable:线程安全

LinkedHashMap 有序

ConcurrentHashMap 无序 线程安全

TreeMap:重新排序

 ConcurrentHashMap 是线程安全的,但却是无序的。适用于高并发情景,但是无序在此就不太恰当。比如有个www.bvin.com/login.jsp?name=bvin&pw=888888,如果用这个Ajax去Put进去的话,有可能会出现像这样的情况:www.bvin.com/login.jsp?pw=888888&name=bvin,明显这样是错误的。

还有一点就是,这个类竟然没有clean()或者removeAll()方法。如果要再次用到这个类的话,就必须重新new一个。其实写这么个方法就举手投足的事,AjaxParams里面其实就是两个ConcurrentHashMap实例。只要把下面这两个清空就行了。

protected ConcurrentHashMap<String, String> urlParams;
protected ConcurrentHashMap<String, FileWrapper> fileParams;

AjaxCallBack,这是一个泛型抽象类,起回调作用。

   public void onStart(){};
    public void onLoading(long count,long current){};
    public void onSuccess(T t){};
    public void onFailure(Throwable t,String strMsg){};

3.发送请求方法

 protected <T> void sendRequest(DefaultHttpClient client, HttpContext httpContext, HttpUriRequest uriRequest, String contentType, AjaxCallBack<T> ajaxCallBack) {
        if(contentType != null) {
            uriRequest.addHeader("Content-Type", contentType);
        }

        new HttpHandler<T>(client, httpContext, ajaxCallBack,charset)
        .executeOnExecutor(executor, uriRequest);

    }
    
    protected Object sendSyncRequest(DefaultHttpClient client, HttpContext httpContext, HttpUriRequest uriRequest, String contentType) {
        if(contentType != null) {
            uriRequest.addHeader("Content-Type", contentType);
        }
        return new SyncRequestHandler(client, httpContext,charset).sendRequest(uriRequest);
    }

 

这里涉及到HttpHandler和SyncRequestHandler两各类,下回分解了。。。

 

posted @ 2013-06-02 14:15  bvin  阅读(2751)  评论(1编辑  收藏  举报