Anroid-async-http封装网络请求框架源码分析

Android-async-http开源项目可以是我们轻松的获取网络数据或者向服务器发送数据,使用起来非常简单, 这个网络请求库是基于Apache HttpClient库之上的一个异步网络请求处理库,网络处理均基于Android的非UI线程,通过回调方法处理请求结果.

主要特点:处理异步Http请求,并通过匿名内部类处理回调结果,Http异步请求均位于非UI线程,不会阻塞UI操作,通过线程池处理并发请求处理文件上传、下载,响应结果自动打包JSON格式.

一, Android-async-http的项目链接

       Github地址:https://github.com/loopj/android-async-http

V1.4.9的javadoc: https://loopj.com/android-async-http/doc/

在DowloadZip下载zip包解压后是Android Studio工程的目录如下:

examples:里面有简单的例子

library:里面存放的是android-async-http开源项目的源码(方法一:可以把library\src\main\Java文件下面的文件拷贝到,你应用的src下也可以直接使用)

releases:里面存放的是各个版本的jar文件,(方法二:只需把最新的jar文件拷贝到你应用的libs目录下即可.)

samples:里面存放的也是例子(可供参考)

备注:方法一和方法二只能采用其中之一,建议采用方法二

二,主要特性

1,Make asynchronous HTTP requests, handle responses in anonymous callbacks

异步http请求,匿名回调处理响应

2,HTTP requests happen outside the UI thread

在UI线程之外进行HTTP请求

3,Requests use a threadpool to cap concurrent resource usage

请求使用线程池,限制使用资源并发情况

4,GET/POST params builder (RequestParams)

使用RequestParams封装GET/POST请求参数

5,Multipart file uploads with no additional third party libraries

不使用第三方库多任务上传

6,Tiny size overhead to your application, only 60kb for everything

占用应用的控件少只需要60kb

7,Automatic smart request retries optimized for spotty mobile connections

自动智能重试请求

8,Optional built-in response parsing into JSON (JsonHttpResponseHandler)

内置响应解析成JSON,使用JsonHttpResponseHandler

9,Optional persistent cookie store, saves cookies into your app‘s SharedPreferences

有选择的持久化cookie存储,保存在app的SharedPreferences文件

三,核心类介绍

对于http请求网络的方式,无非就解决三个问题,第一,请求客户端的方法,第二,请求参数的封装,第三,请求响应的接收处理

先来看一下最基本的用法好有个大概的了解

AsyncHttpClient client = new AsyncHttpClient();
client.get("http://www.google.com", new AsyncHttpResponseHandler() {
    @Override
    public void onSuccess(String response) {
        System.out.println(response);
    }
});

1,Http客户端是谁?AsyncHttpClient

AsyncHttpClient:通过AsyncHttpClient类的实例就可以执行网络请求,包括get、put、post、head、delete。并指定一个ResponseHandlerInterface的实例接收请求结果。

核心类,使用HttpClient执行网络请求,提供了get,put,post,delete,head等请求方法,使用起来很简单,只需以url及RequestParams调用相应的方法即可,还可以选择性地传入Context,用于取消Content相关的请求,同时必须提供ResponseHandlerInterface(AsyncHttpResponseHandler继承自ResponseHandlerInterface)的实现类,一般为AsyncHttpResponseHandler的子类,AsyncHttpClient内部有一个线程池,当使用AsyncHttpClient执行网络请求时,最终都会调用sendRequest方法,在这个方法内部将请求参数封装成AsyncHttpRequest(继承自Runnable)交由内部的线程池执行

2,封装的请求对象是谁?

AsyncHttpRequest:继承自Runnabler,被submit至线程池执行网络请求并发送start,success等消息

3,请求参数和url怎么封装?

RequestParams:请求参数,可以添加普通的字符串参数,并可添加File,InputStream上传文件,内部使用Map添加Key-Value

3,Http请求怎样被执行?

AsyncHttpClient对象执行get等方法,将Context,Url,RequestParams,responseHandler等参数传入,在get()方法内部又封装成sendRequest方法,sendRequest方法内又封装请求AsyncHttpRequest,被提交到线程池的阻塞队列,等待执行,AsyncHttpRequest实现了Runnable方法,线程执行run()方法,在run方法内,responseHandler可以调用sendStartMessage(), makeRequestWithRetries(),sendFinishMessage()记录任务执行的过程日志Log,在执行makeRequestWithRetries方法中执行真正的网络执行语句HttpResponse
response = client.execute(request, context);之后响应处理者调用sendResponseMessage(response),发送响应消息,最终转到OnSuccess(int statusCode, Header[] headers, byte[] responseBody);
响应处理者子类只需要重写这个方法,对返回的响应做响应的处理

4,请求响应用什么方式处理?AsyncHttpResponseHandler, TextHttpResponseHandler, JsonHttpResponseHandler, BaseJsonHttpResponseHandler

继承图

AsyncHttpResponseHandler:

接收请求结果,一般重写onSuccess及onFailure接收请求成功或失败的消息,还有onStart,onFinish等消息

	 //这个方法是子类必须重写的方法,来处理响应的
    public abstract void onSuccess(int statusCode, Header[] headers, byte[] responseBody);

    /**
     * Fired when a request fails to complete, override to handle in your own code
     *
     * @param statusCode   return HTTP status code
     * @param headers      return headers, if any
     * @param responseBody the response body, if any
     * @param error        the underlying cause of the failure
     */
	 //这个方法是子类必须重写的方法,来处理响应的
    public abstract void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error);

BinaryHttpResponseHandler extends AsyncHttpResponseHandler :

继承AsyncHttpResponseHandler的子类,这是一个字节流返回处理的类, 该类用于处理图片,流的形式;

    @Override
    public abstract void onSuccess(int statusCode, Header[] headers, byte[] binaryData);

    @Override
    public abstract void onFailure(int statusCode, Header[] headers, byte[] binaryData, Throwable error);

TextHttpResponseHandler:

继承自AsyncHttpResponseHandler,只是重写了AsyncHttpResponseHandler的onSuccess和onFailure方法,将请求结果由byte数组转换为String

    /**
     * Called when request fails
     *
     * @param statusCode     http response status line
     * @param headers        response headers if any
     * @param responseString string response of given charset
     * @param throwable      throwable returned when processing request
     */
    public abstract void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable);

    /**
     * Called when request succeeds
     *
     * @param statusCode     http response status line
     * @param headers        response headers if any
     * @param responseString string response of given charset
     */
    public abstract void onSuccess(int statusCode, Header[] headers, String responseString);

JsonHttpResponseHandler:

继承自TextHttpResponseHandler,是一个泛型类,提供了parseResponse方法,子类需要提供实现,将请求结果解析成需要的类型,子类可以灵活地使用解析方法,可以直接原始解析,使用gson等。

 /**
     * Returns when request succeeds
     *
     * @param statusCode http response status line
     * @param headers    response headers if any
     * @param response   parsed response if any
     */
    public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
        AsyncHttpClient.log.w(LOG_TAG, "onSuccess(int, Header[], JSONObject) was not overriden, but callback was received");
    }

    /**
     * Returns when request succeeds
     *
     * @param statusCode http response status line
     * @param headers    response headers if any
     * @param response   parsed response if any
     */
    public void onSuccess(int statusCode, Header[] headers, JSONArray response) {
        AsyncHttpClient.log.w(LOG_TAG, "onSuccess(int, Header[], JSONArray) was not overriden, but callback was received");
    }

    /**
     * Returns when request failed
     *
     * @param statusCode    http response status line
     * @param headers       response headers if any
     * @param throwable     throwable describing the way request failed
     * @param errorResponse parsed response if any
     */
    public void onFailure(int statusCode, Header[] headers, Throwable throwable, JSONObject errorResponse) {
        AsyncHttpClient.log.w(LOG_TAG, "onFailure(int, Header[], Throwable, JSONObject) was not overriden, but callback was received", throwable);
    }

    /**
     * Returns when request failed
     *
     * @param statusCode    http response status line
     * @param headers       response headers if any
     * @param throwable     throwable describing the way request failed
     * @param errorResponse parsed response if any
     */
    public void onFailure(int statusCode, Header[] headers, Throwable throwable, JSONArray errorResponse) {
        AsyncHttpClient.log.w(LOG_TAG, "onFailure(int, Header[], Throwable, JSONArray) was not overriden, but callback was received", throwable);
    }

    @Override
    public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {
        AsyncHttpClient.log.w(LOG_TAG, "onFailure(int, Header[], String, Throwable) was not overriden, but callback was received", throwable);
    }

    @Override
    public void onSuccess(int statusCode, Header[] headers, String responseString) {
        AsyncHttpClient.log.w(LOG_TAG, "onSuccess(int, Header[], String) was not overriden, but callback was received");
    }
 /**
     * Returns Object of type {@link JSONObject}, {@link JSONArray}, String, Boolean, Integer, Long,
     * Double or {@link JSONObject#NULL}, see {@link org.json.JSONTokener#nextValue()}
     *
     * @param responseBody response bytes to be assembled in String and parsed as JSON
     * @return Object parsedResponse
     * @throws org.json.JSONException exception if thrown while parsing JSON
     */
    protected Object parseResponse(byte[] responseBody) throws JSONException {
        if (null == responseBody)
            return null;
        Object result = null;
        //trim the string to prevent start with blank, and test if the string is valid JSON, because the parser don't do this :(. If JSON is not valid this will return null
        String jsonString = getResponseString(responseBody, getCharset());
        if (jsonString != null) {
            jsonString = jsonString.trim();
            if (useRFC5179CompatibilityMode) {
                if (jsonString.startsWith("{") || jsonString.startsWith("[")) {
                    result = new JSONTokener(jsonString).nextValue();
                }
            } else {
                // Check if the string is an JSONObject style {} or JSONArray style []
                // If not we consider this as a string
                if ((jsonString.startsWith("{") && jsonString.endsWith("}"))
                        || jsonString.startsWith("[") && jsonString.endsWith("]")) {
                    result = new JSONTokener(jsonString).nextValue();
                }
                // Check if this is a String "my String value" and remove quote
                // Other value type (numerical, boolean) should be without quote
                else if (jsonString.startsWith("\"") && jsonString.endsWith("\"")) {
                    result = jsonString.substring(1, jsonString.length() - 1);
                }
            }
        }
        if (result == null) {
            result = jsonString;
        }
        return result;
    }

四,原理流程图

1,调用AsyncHttpClient的get或post等方法发起网络请求

2,所有的请求都走了sendRequest,在sendRequest中把请求封装为AsyncHttpRequest,并添加到线程池执行,

3,当请求被执行时(即AsyncHttpRequest的run方法),执行AsyncHttpRequest的makeRequestWithRetries方法执行实际的请求,当请求失败时可以重试。并在请求开始,结束,成功或失败时向请求时传的ResponseHandlerInterface实例发送消息

4,基本上使用的都是AsyncHttpResponseHandler的子类,调用其onStart,onSuccess等方法返回请求结果

五,核心源码解读

1,AsyncHttpClient.java

以Get方法为例分析源码:
/**
     * Perform a HTTP GET request, without any parameters.
     * 执行一个没有参数的HTTP Get请求
     * @param url             the URL to send the request to.  请求Url
     * @param responseHandler the response handler instance that should handle the response.处理响应对象
     * @return RequestHandle of future request process
     */
    public RequestHandle get(String url, ResponseHandlerInterface responseHandler) {
        return get(null, url, null, responseHandler);//转到另一个重载函数,四个参数是Context,Url,RequestParams,ResponseHandler
    }

    // [-] HTTP GET
    // [+] HTTP POST

    /**
     * Perform a HTTP GET request with parameters.
     *执行一个有参数的HTTP Get请求
     * @param url             the URL to send the request to.
     * @param params          additional GET parameters to send with the request.
     * @param responseHandler the response handler instance that should handle the response.
     * @return RequestHandle of future request process
     */
    public RequestHandle get(String url, RequestParams params, ResponseHandlerInterface responseHandler) {
        return get(null, url, params, responseHandler);//转到另一个重载函数,四个参数是Context,Url,RequestParams,ResponseHandler
    }

    /**
     * Perform a HTTP GET request without any parameters and track the Android Context which
     * initiated the request.
     *
     * @param context         the Android Context which initiated the request.
     * @param url             the URL to send the request to.
     * @param responseHandler the response handler instance that should handle the response.
     * @return RequestHandle of future request process
     */
    public RequestHandle get(Context context, String url, ResponseHandlerInterface responseHandler) {
        return get(context, url, null, responseHandler);
    }

    /**
     * Perform a HTTP GET request and track the Android Context which initiated the request.
     *执行一个Http Get请求,有Context参数,初始化request
     * @param context         the Android Context which initiated the request.   // android上下文context
     * @param url             the URL to send the request to.//请去的url
     * @param params          additional GET parameters to send with the request.//请求的参数
     * @param responseHandler the response handler instance that should handle the response.//处理响应对象
     * @return RequestHandle of future request process
     */
    public RequestHandle get(Context context, String url, RequestParams params, ResponseHandlerInterface responseHandler) {
	  /*
	   *  封装sendRequest的方法,感觉和HttpClient的方式相似,不是很懂,参数如下
	   *1,DefaultHttpClient httpClient
	   *2,HttpContext httpContext
	   *3,HttpGet httpget
	   *4,
	   *5,ResponseHandlerInterface responseHandler
	   *6,Context context
	   */
        return sendRequest(httpClient, httpContext, new HttpGet(getUrlWithQueryString(isUrlEncodingEnabled, url, params)), null, responseHandler, context);
    }

    /**
     * Perform a HTTP GET request and track the Android Context which initiated the request with
     * customized headers
     * 执行有自定义Header的请求
     * @param context         Context to execute request against
     * @param url             the URL to send the request to.
     * @param headers         set headers only for this request
     * @param params          additional GET parameters to send with the request.
     * @param responseHandler the response handler instance that should handle the response.
     * @return RequestHandle of future request process
     */
    public RequestHandle get(Context context, String url, Header[] headers, RequestParams params, ResponseHandlerInterface responseHandler) {
        HttpUriRequest request = new HttpGet(getUrlWithQueryString(isUrlEncodingEnabled, url, params));
        if (headers != null) request.setHeaders(headers);//自定义的Header加入到,HttpGet对象中
        return sendRequest(httpClient, httpContext, request, null, responseHandler,
                context);
    }

/**
     * Puts a new request in queue as a new thread in pool to be executed
     * 把一个新的请求放入线程池的队列被执行
     * @param client          HttpClient to be used for request, can differ in single requests
     * @param contentType     MIME body type, for POST and PUT requests, may be null
     * @param context         Context of Android application, to hold the reference of request
     * @param httpContext     HttpContext in which the request will be executed
     * @param responseHandler ResponseHandler or its subclass to put the response into
     * @param uriRequest      instance of HttpUriRequest, which means it must be of HttpDelete,
     *                        HttpPost, HttpGet, HttpPut, etc.
     * @return RequestHandle of future request process
     */
	   /*
	   * 封装sendRequest的方法,感觉和HttpClient的方式相似,不是很懂,参数如下
	   *1,DefaultHttpClient httpClient
	   *2,HttpContext httpContext
	   *3,HttpGet httpget
	   *4,String contentType,
	   *5,ResponseHandlerInterface responseHandler
	   *6,Context context
	   */
    protected RequestHandle sendRequest(DefaultHttpClient client, HttpContext httpContext, HttpUriRequest uriRequest, String contentType, ResponseHandlerInterface responseHandler, Context context) {
        if (uriRequest == null) {
            throw new IllegalArgumentException("HttpUriRequest must not be null");
        }

        if (responseHandler == null) {
            throw new IllegalArgumentException("ResponseHandler must not be null");
        }

        if (responseHandler.getUseSynchronousMode() && !responseHandler.getUsePoolThread()) {
            throw new IllegalArgumentException("Synchronous ResponseHandler used in AsyncHttpClient. You should create your response handler in a looper thread or use SyncHttpClient instead.");
        }

        if (contentType != null) {
            if (uriRequest instanceof HttpEntityEnclosingRequestBase && ((HttpEntityEnclosingRequestBase) uriRequest).getEntity() != null && uriRequest.containsHeader(HEADER_CONTENT_TYPE)) {
                log.w(LOG_TAG, "Passed contentType will be ignored because HttpEntity sets content type");
            } else {
                uriRequest.setHeader(HEADER_CONTENT_TYPE, contentType);
            }
        }
        //responseHandler设置请求头和请去Url
        responseHandler.setRequestHeaders(uriRequest.getAllHeaders());
        responseHandler.setRequestURI(uriRequest.getURI());
        //构造一个执行请求的AsyncHttpRequest对象,准备被发送到线程池的任务队列,等待执行AsyncHttpRequest对象中的run方法
        AsyncHttpRequest request = newAsyncHttpRequest(client, httpContext, uriRequest, contentType, responseHandler, context);
        threadPool.submit(request);//重点!!!!: 把AsyncHttpRequest对象提交到线程池等待执行
		/**
         * A Handle to an AsyncRequest which can be used to cancel a running request.
		 * 一个可以用来取消正在运行的请求的手柄或者说是操作者
         */
        RequestHandle requestHandle = new RequestHandle(request);

        if (context != null) {
            List<RequestHandle> requestList;
            // Add request to request map
            synchronized (requestMap) {
                requestList = requestMap.get(context);
                if (requestList == null) {
                    requestList = Collections.synchronizedList(new LinkedList<RequestHandle>());
                    requestMap.put(context, requestList);
                }
            }

            requestList.add(requestHandle);

            Iterator<RequestHandle> iterator = requestList.iterator();
            while (iterator.hasNext()) {
                if (iterator.next().shouldBeGarbageCollected()) {
                    iterator.remove();
                }
            }
        }

        return requestHandle;//返回手柄
    }

AsyncHttpRequest.java

/**
 * Internal class, representing the HttpRequest, done in asynchronous manner
 */
 //异步HTTP请求对象,实现的是Runnable接口,说明AsyncHttpRequest是一个供线程执行的任务类,主要关注run方法
public class AsyncHttpRequest implements Runnable {
    private final AbstractHttpClient client;//Http客户端,Httpclient
    private final HttpContext context;
    private final HttpUriRequest request;//保存HttpGet对象
    private final ResponseHandlerInterface responseHandler;//保存响应处理者对象,可以跟踪任务的执行,start,fihish等
    private final AtomicBoolean isCancelled = new AtomicBoolean();
    private int executionCount;
    private boolean cancelIsNotified;
    private volatile boolean isFinished;
    private boolean isRequestPreProcessed;

    public AsyncHttpRequest(AbstractHttpClient client, HttpContext context, HttpUriRequest request, ResponseHandlerInterface responseHandler) {
        this.client = Utils.notNull(client, "client");
        this.context = Utils.notNull(context, "context");
        this.request = Utils.notNull(request, "request");
        this.responseHandler = Utils.notNull(responseHandler, "responseHandler");
    }

    /**
     * This method is called once by the system when the request is about to be
     * processed by the system. The library makes sure that a single request
     * is pre-processed only once.
     * <p> </p>
     * Please note: pre-processing does NOT run on the main thread, and thus
     * any UI activities that you must perform should be properly dispatched to
     * the app's UI thread.
     *
     * @param request The request to pre-process
     */

    public void onPreProcessRequest(AsyncHttpRequest request) {
        // default action is to do nothing...
    }

    /**
     * This method is called once by the system when the request has been fully
     * sent, handled and finished. The library makes sure that a single request
     * is post-processed only once.
     * <p> </p>
     * Please note: post-processing does NOT run on the main thread, and thus
     * any UI activities that you must perform should be properly dispatched to
     * the app's UI thread.
     *
     * @param request The request to post-process
     */
    public void onPostProcessRequest(AsyncHttpRequest request) {
        // default action is to do nothing...
    }
    /*
	* 在线程池中执行run方法过程
	*/
    @Override
    public void run() {
        if (isCancelled()) {
            return;
        }

        // Carry out pre-processing for this request only once.
        if (!isRequestPreProcessed) {
            isRequestPreProcessed = true;
            onPreProcessRequest(this);
        }

        if (isCancelled()) {
            return;
        }
        //responseHandler发送开始消息,响应处理者设置start消息
        responseHandler.sendStartMessage();

        if (isCancelled()) {
            return;
        }

        try {
		    //重点是这个方法!!!
            makeRequestWithRetries();
        } catch (IOException e) {
            if (!isCancelled()) {
			    //任务执行失败,响应处理者设置failure消息
                responseHandler.sendFailureMessage(0, null, null, e);
            } else {
                AsyncHttpClient.log.e("AsyncHttpRequest", "makeRequestWithRetries returned error", e);
            }
        }

        if (isCancelled()) {
            return;
        }
        //任务执行完成,响应处理者设置finish消息
        responseHandler.sendFinishMessage();

        if (isCancelled()) {
            return;
        }

        // Carry out post-processing for this request.
		//任务执行完毕,调用这个方法
        onPostProcessRequest(this);

        isFinished = true;
    }
	//makeRequest
    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);
        }
        //终于看到这一句了,感觉就是我们常用的HttpClient,HttpGet,HttpResponse模式
        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.
		//猜到就是把HttpResponse对象封装到响应处理者responseHandler中,responseHandler中肯定有保存HttpResponse对象的变量
        responseHandler.sendResponseMessage(response);

        if (isCancelled()) {
            return;
        }

        // Carry out post-processing for this response.
		//返回响应之后的后处理,一个请求就这么处理完了,接下来只需要出去处理responseHandler就可以得到响应了
        responseHandler.onPostProcessResponse(responseHandler, response);
    }
   //重点是这个方法!!!做请求带有重试次数的
    private void makeRequestWithRetries() throws IOException {
        boolean retry = true;
        IOException cause = null;
        HttpRequestRetryHandler retryHandler = client.getHttpRequestRetryHandler();
        try {
            while (retry) {
                try {
				    //重点是去makerequest
                    makeRequest();
                    return;
                } catch (UnknownHostException e) {
                    // switching between WI-FI and mobile data networks can cause a retry which then results in an UnknownHostException
                    // while the WI-FI is initialising. The retry logic will be invoked here, if this is NOT the first retry
                    // (to assist in genuine cases of unknown host) which seems better than outright failure
                    cause = new IOException("UnknownHostException exception: " + e.getMessage(), e);
					//如果执行抛出异常,会重试连接,可能是这样理解的
                    retry = (executionCount > 0) && retryHandler.retryRequest(e, ++executionCount, context);
                } catch (NullPointerException e) {
                    // there's a bug in HttpClient 4.0.x that on some occasions causes
                    // DefaultRequestExecutor to throw an NPE, see
                    // https://code.google.com/p/android/issues/detail?id=5255
                    cause = new IOException("NPE in HttpClient: " + e.getMessage());
                    retry = retryHandler.retryRequest(cause, ++executionCount, context);
                } catch (IOException e) {
                    if (isCancelled()) {
                        // Eating exception, as the request was cancelled
                        return;
                    }
                    cause = e;
                    retry = retryHandler.retryRequest(cause, ++executionCount, context);
                }
                if (retry) {
                    responseHandler.sendRetryMessage(executionCount);
                }
            }
        } catch (Exception e) {
            // catch anything else to ensure failure message is propagated
            AsyncHttpClient.log.e("AsyncHttpRequest", "Unhandled exception origin cause", e);
            cause = new IOException("Unhandled exception: " + e.getMessage(), cause);
        }

        // cleaned up to throw IOException
        throw (cause);
    }

AsyncHttpResponseHandler.java

  /**
     * Fired when the request is started, override to handle in your own code
     */
	/*asyncHttpRequst的run方法执行时调用sendStartMessage发送开始消息
	* 其实就是转入这个OnStart函数,如果想跟踪任务执行的话写log就重写这个方法
	*/
    public void onStart() {
        // default log warning is not necessary, because this method is just optional notification
    }

    /**
     * Fired in all cases when the request is finished, after both success and failure, override to
     * handle in your own code
     */
	 /*asyncHttpRequst的run方法执行时调用sendFinishMessage发送开始消息
	* 其实就是转入这个onFinish函数,如果想跟踪任务执行的话写log就重写这个方法
	*/
    public void onFinish() {
        // default log warning is not necessary, because this method is just optional notification
    }
    /*
	*asyncHttpRequst的run方法执行到makeRequest方法时,执行完毕会调用一下两个函数
	*onPreProcessResponse 是指在返回响应之前的预处理
	*onPostProcessResponse 是指返回响应之后的处理
	*/
    @Override
    public void onPreProcessResponse(ResponseHandlerInterface instance, HttpResponse response) {
        // default action is to do nothing...
    }

    @Override
    public void onPostProcessResponse(ResponseHandlerInterface instance, HttpResponse response) {
        // default action is to do nothing...
    }

    /**
     * Fired when a request returns successfully, override to handle in your own code
     *
     * @param statusCode   the status code of the response 响应的响应码
     * @param headers      return headers, if any  响应的Header头信息
     * @param responseBody the body of the HTTP response from the server 响应体
     */
	 //这个方法是子类必须重写的方法,来处理响应的
    public abstract void onSuccess(int statusCode, Header[] headers, byte[] responseBody);

    /**
     * Fired when a request fails to complete, override to handle in your own code
     *
     * @param statusCode   return HTTP status code
     * @param headers      return headers, if any
     * @param responseBody the response body, if any
     * @param error        the underlying cause of the failure
     */
	 //这个方法是子类必须重写的方法,来处理响应的
    public abstract void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error);
  // Methods which emulate android's Handler and Message methods
    protected void handleMessage(Message message) {
        Object[] response;

        try {
            switch (message.what) {
                case SUCCESS_MESSAGE:
                    response = (Object[]) message.obj;
                    if (response != null && response.length >= 3) {
					   //调用onSuccess方法
                        onSuccess((Integer) response[0], (Header[]) response[1], (byte[]) response[2]);
                    } else {
                        AsyncHttpClient.log.e(LOG_TAG, "SUCCESS_MESSAGE didn't got enough params");
                    }
                    break;
                case FAILURE_MESSAGE:
                    response = (Object[]) message.obj;
                    if (response != null && response.length >= 4) {
					   //调用onFailure方法
                        onFailure((Integer) response[0], (Header[]) response[1], (byte[]) response[2], (Throwable) response[3]);
                    } else {
                        AsyncHttpClient.log.e(LOG_TAG, "FAILURE_MESSAGE didn't got enough params");
                    }
                    break;
                case START_MESSAGE:
				   //调用onStart方法
                    onStart();
                    break;
                case FINISH_MESSAGE:
				   //调用onFinish方法
                    onFinish();
                    break;
                case PROGRESS_MESSAGE:
                    response = (Object[]) message.obj;
                    if (response != null && response.length >= 2) {
                        try {
                            onProgress((Long) response[0], (Long) response[1]);
                        } catch (Throwable t) {
                            AsyncHttpClient.log.e(LOG_TAG, "custom onProgress contains an error", t);
                        }
                    } else {
                        AsyncHttpClient.log.e(LOG_TAG, "PROGRESS_MESSAGE didn't got enough params");
                    }
                    break;
                case RETRY_MESSAGE:
                    response = (Object[]) message.obj;
                    if (response != null && response.length == 1) {
                        onRetry((Integer) response[0]);
                    } else {
                        AsyncHttpClient.log.e(LOG_TAG, "RETRY_MESSAGE didn't get enough params");
                    }
                    break;
                case CANCEL_MESSAGE:
				  //调用onFinish方法
                    onCancel();
                    break;
            }
        } catch (Throwable error) {
            onUserException(error);
        }
    }
  }
   /*asyncHttpRequst的run方法执行到makeRequest方法时,获得HttpResponse后会调用如下方法sendResponseMessage
    *
    *
	**/
    @Override
    public void sendResponseMessage(HttpResponse response) throws IOException {
        // do not process if request has been cancelled
		//因为asyncHttpRequst在线程池中执行,先判断线程
        if (!Thread.currentThread().isInterrupted()) {
		   //获取状态行
            StatusLine status = response.getStatusLine();
            byte[] responseBody;
			//获取响应体的字节数组
            responseBody = getResponseData(response.getEntity());
            // additional cancellation check as getResponseData() can take non-zero time to process
            if (!Thread.currentThread().isInterrupted()) {
                if (status.getStatusCode() >= 300) {
				    //如果响应码大于等于300,则发送失败消息,失败和成功消息是判断响应码发生的,开始和结束消息是任务执行发生的
                    sendFailureMessage(status.getStatusCode(), response.getAllHeaders(), responseBody, new HttpResponseException(status.getStatusCode(), status.getReasonPhrase()));
                } else {
				   //否则发送成功消息,参数是响应码,响应头信息,响应体
                    sendSuccessMessage(status.getStatusCode(), response.getAllHeaders(), responseBody);
                }
            }
        }
    }

AsyncRequestParams.java

public class RequestParams implements Serializable {

    public final static String APPLICATION_OCTET_STREAM =
            "application/octet-stream";

    public final static String APPLICATION_JSON =
            "application/json";

    protected final static String LOG_TAG = "RequestParams";
	//d都是用的是并发HashMap,Url的参数
    protected final ConcurrentHashMap<String, String> urlParams = new ConcurrentHashMap<String, String>();
	//各种流的参数HashMap
    protected final ConcurrentHashMap<String, StreamWrapper> streamParams = new ConcurrentHashMap<String, StreamWrapper>();
	//各种文件的参数HashMap
    protected final ConcurrentHashMap<String, FileWrapper> fileParams = new ConcurrentHashMap<String, FileWrapper>();
	//多文件的参数HashMap
    protected final ConcurrentHashMap<String, List<FileWrapper>> fileArrayParams = new ConcurrentHashMap<String, List<FileWrapper>>();
	//带对象的Url的参数HashMap
    protected final ConcurrentHashMap<String, Object> urlParamsWithObjects = new ConcurrentHashMap<String, Object>();
    protected boolean isRepeatable;
    protected boolean forceMultipartEntity = false;
    protected boolean useJsonStreamer;
    protected String elapsedFieldInJsonStreamer = "_elapsed";
    protected boolean autoCloseInputStreams;
    protected String contentEncoding = HTTP.UTF_8;

    /**
     * Constructs a new empty {@code RequestParams} instance.
     */
    public RequestParams() {
        this((Map<String, String>) null);
    }

    /**
     * Constructs a new RequestParams instance containing the key/value string params from the
     * specified map.
     *
     * @param source the source key/value string map to add.
     */
    public RequestParams(Map<String, String> source) {
        if (source != null) {
            for (Map.Entry<String, String> entry : source.entrySet()) {
                put(entry.getKey(), entry.getValue());
            }
        }
    }

    /**
     * Constructs a new RequestParams instance and populate it with a single initial key/value
     * string param.
     *
     * @param key   the key name for the intial param.
     * @param value the value string for the initial param.
     */
    public RequestParams(final String key, final String value) {
        this(new HashMap<String, String>() {{
            put(key, value);
        }});
    }

    /**
     * Constructs a new RequestParams instance and populate it with multiple initial key/value
     * string param.
     *
     * @param keysAndValues a sequence of keys and values. Objects are automatically converted to
     *                      Strings (including the value {@code null}).
     * @throws IllegalArgumentException if the number of arguments isn't even.
     */
    public RequestParams(Object... keysAndValues) {
        int len = keysAndValues.length;
        if (len % 2 != 0)
            throw new IllegalArgumentException("Supplied arguments must be even");
        for (int i = 0; i < len; i += 2) {
            String key = String.valueOf(keysAndValues[i]);
            String val = String.valueOf(keysAndValues[i + 1]);
            put(key, val);
        }
    }

    /**
     * Sets content encoding for return value of {@link #getParamString()} and {@link
     * #createFormEntity()} <p> </p> Default encoding is "UTF-8"
     *
     * @param encoding String constant from {@link HTTP}
     */
    public void setContentEncoding(final String encoding) {
        if (encoding != null) {
            this.contentEncoding = encoding;
        } else {
            AsyncHttpClient.log.d(LOG_TAG, "setContentEncoding called with null attribute");
        }
    }

    /**
     * If set to true will force Content-Type header to `multipart/form-data`
     * even if there are not Files or Streams to be send
     * <p> </p>
     * Default value is false
     *
     * @param force boolean, should declare content-type multipart/form-data even without files or streams present
     */
    public void setForceMultipartEntityContentType(boolean force) {
        this.forceMultipartEntity = force;
    }

    /**
     * Adds a key/value string pair to the request.
     *
     * @param key   the key name for the new param.
     * @param value the value string for the new param.
     */
    public void put(String key, String value) {
        if (key != null && value != null) {
            urlParams.put(key, value);
        }
    }

    /**
     * Adds files array to the request.
     *
     * @param key   the key name for the new param.
     * @param files the files array to add.
     * @throws FileNotFoundException if one of passed files is not found at time of assembling the requestparams into request
     */
    public void put(String key, File files[]) throws FileNotFoundException {
        put(key, files, null, null);
    }

    /**
     * Adds files array to the request with both custom provided file content-type and files name
     *
     * @param key            the key name for the new param.
     * @param files          the files array to add.
     * @param contentType    the content type of the file, eg. application/json
     * @param customFileName file name to use instead of real file name
     * @throws FileNotFoundException throws if wrong File argument was passed
     */
    public void put(String key, File files[], String contentType, String customFileName) throws FileNotFoundException {

        if (key != null) {
            List<FileWrapper> fileWrappers = new ArrayList<FileWrapper>();
            for (File file : files) {
                if (file == null || !file.exists()) {
                    throw new FileNotFoundException();
                }
                fileWrappers.add(new FileWrapper(file, contentType, customFileName));
            }
            fileArrayParams.put(key, fileWrappers);
        }
    }

    /**
     * Adds a file to the request.
     *
     * @param key  the key name for the new param.
     * @param file the file to add.
     * @throws FileNotFoundException throws if wrong File argument was passed
     */
    public void put(String key, File file) throws FileNotFoundException {
        put(key, file, null, null);
    }

    /**
     * Adds a file to the request with custom provided file name
     *
     * @param key            the key name for the new param.
     * @param file           the file to add.
     * @param customFileName file name to use instead of real file name
     * @throws FileNotFoundException throws if wrong File argument was passed
     */
    public void put(String key, String customFileName, File file) throws FileNotFoundException {
        put(key, file, null, customFileName);
    }

    /**
     * Adds a file to the request with custom provided file content-type
     *
     * @param key         the key name for the new param.
     * @param file        the file to add.
     * @param contentType the content type of the file, eg. application/json
     * @throws FileNotFoundException throws if wrong File argument was passed
     */
    public void put(String key, File file, String contentType) throws FileNotFoundException {
        put(key, file, contentType, null);
    }

    /**
     * Adds a file to the request with both custom provided file content-type and file name
     *
     * @param key            the key name for the new param.
     * @param file           the file to add.
     * @param contentType    the content type of the file, eg. application/json
     * @param customFileName file name to use instead of real file name
     * @throws FileNotFoundException throws if wrong File argument was passed
     */
    public void put(String key, File file, String contentType, String customFileName) throws FileNotFoundException {
        if (file == null || !file.exists()) {
            throw new FileNotFoundException();
        }
        if (key != null) {
            fileParams.put(key, new FileWrapper(file, contentType, customFileName));
        }
    }

    /**
     * Adds an input stream to the request.
     *
     * @param key    the key name for the new param.
     * @param stream the input stream to add.
     */
    public void put(String key, InputStream stream) {
        put(key, stream, null);
    }

    /**
     * Adds an input stream to the request.
     *
     * @param key    the key name for the new param.
     * @param stream the input stream to add.
     * @param name   the name of the stream.
     */
    public void put(String key, InputStream stream, String name) {
        put(key, stream, name, null);
    }

    /**
     * Adds an input stream to the request.
     *
     * @param key         the key name for the new param.
     * @param stream      the input stream to add.
     * @param name        the name of the stream.
     * @param contentType the content type of the file, eg. application/json
     */
    public void put(String key, InputStream stream, String name, String contentType) {
        put(key, stream, name, contentType, autoCloseInputStreams);
    }

    /**
     * Adds an input stream to the request.
     *
     * @param key         the key name for the new param.
     * @param stream      the input stream to add.
     * @param name        the name of the stream.
     * @param contentType the content type of the file, eg. application/json
     * @param autoClose   close input stream automatically on successful upload
     */
    public void put(String key, InputStream stream, String name, String contentType, boolean autoClose) {
        if (key != null && stream != null) {
            streamParams.put(key, StreamWrapper.newInstance(stream, name, contentType, autoClose));
        }
    }

    /**
     * Adds param with non-string value (e.g. Map, List, Set).
     *
     * @param key   the key name for the new param.
     * @param value the non-string value object for the new param.
     */
    public void put(String key, Object value) {
        if (key != null && value != null) {
            urlParamsWithObjects.put(key, value);
        }
    }

    /**
     * Adds a int value to the request.
     *
     * @param key   the key name for the new param.
     * @param value the value int for the new param.
     */
    public void put(String key, int value) {
        if (key != null) {
            urlParams.put(key, String.valueOf(value));
        }
    }

    /**
     * Adds a long value to the request.
     *
     * @param key   the key name for the new param.
     * @param value the value long for the new param.
     */
    public void put(String key, long value) {
        if (key != null) {
            urlParams.put(key, String.valueOf(value));
        }
    }

    /**
     * Adds string value to param which can have more than one value.
     *
     * @param key   the key name for the param, either existing or new.
     * @param value the value string for the new param.
     */
    public void add(String key, String value) {
        if (key != null && value != null) {
            Object params = urlParamsWithObjects.get(key);
            if (params == null) {
                // Backward compatible, which will result in "k=v1&k=v2&k=v3"
                params = new HashSet<String>();
                this.put(key, params);
            }
            if (params instanceof List) {
                ((List<Object>) params).add(value);
            } else if (params instanceof Set) {
                ((Set<Object>) params).add(value);
            }
        }
    }

    /**
     * Removes a parameter from the request.
     *
     * @param key the key name for the parameter to remove.
     */
    public void remove(String key) {
        urlParams.remove(key);
        streamParams.remove(key);
        fileParams.remove(key);
        urlParamsWithObjects.remove(key);
        fileArrayParams.remove(key);
    }

    /**
     * Check if a parameter is defined.
     *
     * @param key the key name for the parameter to check existence.
     * @return Boolean
     */
    public boolean has(String key) {
        return urlParams.get(key) != null ||
                streamParams.get(key) != null ||
                fileParams.get(key) != null ||
                urlParamsWithObjects.get(key) != null ||
                fileArrayParams.get(key) != null;
    }
    //在AsyncHttpRequest执行中会调用这个方法
	//其实转化成了key1=value1&key2=value2的字符串
    @Override
    public String toString() {
        StringBuilder result = new StringBuilder();
        for (ConcurrentHashMap.Entry<String, String> entry : urlParams.entrySet()) {
            if (result.length() > 0)
                result.append("&");

            result.append(entry.getKey());
            result.append("=");
            result.append(entry.getValue());
        }

        for (ConcurrentHashMap.Entry<String, StreamWrapper> entry : streamParams.entrySet()) {
            if (result.length() > 0)
                result.append("&");

            result.append(entry.getKey());
            result.append("=");
            result.append("STREAM");
        }

        for (ConcurrentHashMap.Entry<String, FileWrapper> entry : fileParams.entrySet()) {
            if (result.length() > 0)
                result.append("&");

            result.append(entry.getKey());
            result.append("=");
            result.append("FILE");
        }

        for (ConcurrentHashMap.Entry<String, List<FileWrapper>> entry : fileArrayParams.entrySet()) {
            if (result.length() > 0)
                result.append("&");

            result.append(entry.getKey());
            result.append("=");
            result.append("FILES(SIZE=").append(entry.getValue().size()).append(")");
        }

        List<BasicNameValuePair> params = getParamsList(null, urlParamsWithObjects);
        for (BasicNameValuePair kv : params) {
            if (result.length() > 0)
                result.append("&");

            result.append(kv.getName());
            result.append("=");
            result.append(kv.getValue());
        }

        return result.toString();
    }

六,使用方法

官方建议:Recommended Usage: Make a Static Http Client

import com.loopj.android.http.*;

public class TwitterRestClient {
  private static final String BASE_URL = "https://api.twitter.com/1/";

  private static AsyncHttpClient client = new AsyncHttpClient();

  public static void get(String url, RequestParams params, AsyncHttpResponseHandler responseHandler) {
      client.get(getAbsoluteUrl(url), params, responseHandler);
  }

  public static void post(String url, RequestParams params, AsyncHttpResponseHandler responseHandler) {
      client.post(getAbsoluteUrl(url), params, responseHandler);
  }

  private static String getAbsoluteUrl(String relativeUrl) {
      return BASE_URL + relativeUrl;
  }
}

AsyncRequestParams.java‘

RequestParams params = new RequestParams();
params.put("username", "yanbober");
params.put("password", "123456");
params.put("email", "[email protected]");

/*
* Upload a File
*/
params.put("file_pic", new File("test.jpg"));
params.put("file_inputStream", inputStream);
params.put("file_bytes", new ByteArrayInputStream(bytes));

/*
* url params: "user[first_name]=jesse&user[last_name]=yan"
*/
Map<String, String> map = new HashMap<String, String>();
map.put("first_name", "jesse");
map.put("last_name", "yan");
params.put("user", map);

/*
* url params: "what=haha&like=wowo"
*/
Set<String> set = new HashSet<String>();
set.add("haha");
set.add("wowo");
params.put("what", set);

/*
* url params: "languages[]=Java&languages[]=C"
*/
List<String> list = new ArrayList<String>();
list.add("Java");
list.add("C");
params.put("languages", list);

/*
* url params: "colors[]=blue&colors[]=yellow"
*/
String[] colors = { "blue", "yellow" };
params.put("colors", colors);

/*
* url params: "users[][age]=30&users[][gender]=male&users[][age]=25&users[][gender]=female"
*/
List<Map<String, String>> listOfMaps = new ArrayList<Map<String, String>>();
Map<String, String> user1 = new HashMap<String, String>();
user1.put("age", "30");
user1.put("gender", "male");

Map<String, String> user2 = new HashMap<String, String>();
user2.put("age", "25");
user2.put("gender", "female");

listOfMaps.add(user1);
listOfMaps.add(user2);

params.put("users", listOfMaps);

/*
* 使用实例
*/
AsyncHttpClient client = new AsyncHttpClient();
client.post("http://localhost:8080/androidtest/", params, responseHandler)

JsonHttpResponseHandler带Json参数的POST:

try {
    JSONObject jsonObject = new JSONObject();
    jsonObject.put("username", "ryantang");
    StringEntity stringEntity = new StringEntity(jsonObject.toString());
    client.post(mContext, "http://api.com/login", stringEntity, "application/json", new JsonHttpResponseHandler(){
        @Override
        public void onSuccess(JSONObject jsonObject) {
            super.onSuccess(jsonObject);
        }
    });
} catch (JSONException e) {
    e.printStackTrace();
} catch (UnsupportedEncodingException e) {
    e.printStackTrace();
}

BinaryHttpResponseHandler下载文件:

client.get("http://download/file/test.java", new BinaryHttpResponseHandler() {
    @Override
    public void onSuccess(byte[] arg0) {
        super.onSuccess(arg0);
        File file = Environment.getExternalStorageDirectory();
        File file2 = new File(file, "down");
        file2.mkdir();
        file2 = new File(file2, "down_file.jpg");
        try {
            FileOutputStream oStream = new FileOutputStream(file2);
            oStream.write(arg0);
            oStream.flush();
            oStream.close();
        } catch (Exception e) {
            e.printStackTrace();
            Log.i(null, e.toString());
        }
    }
});

支持相应文件图片上传的话:

String path="http://sv1.livechano.com:8080/upload.action?&action=1.6&type=1&ext=png";
        File myFile = new File("/sdcard/test.png");
        RequestParams params = new RequestParams();
        try {

            params.put("image", myFile,"application/octet-stream");

            AsyncHttpClient client = new AsyncHttpClient();

            client.post(path, params, new AsyncHttpResponseHandler(){

                @Override
                public void onFailure(Throwable error, String content) {
                    // TODO Auto-generated method stub
                    super.onFailure(error, content);
                    Toast.makeText(MainActivity.this, "上传失败!"+content, Toast.LENGTH_LONG).show();
                }

                @Override
                public void onSuccess(int statusCode, String content) {
                    // TODO Auto-generated method stub
                    super.onSuccess(statusCode, content);
                    System.out
                            .println("content:    "+content);
                    Toast.makeText(MainActivity.this, "上传成功!"+content, Toast.LENGTH_LONG).show();
                }

            });

        } catch(FileNotFoundException e) {

        }

更多参考:

http://my.oschina.net/penngo/blog/488128

http://www.cnblogs.com/manuosex/p/3583775.html

http://blog.csdn.net/wangwei_cq/article/details/9453345

http://blog.csdn.net/yanbober/article/details/45307549

http://www.cnblogs.com/angeldevil/p/3729808.html

http://blog.csdn.net/finddreams/article/details/50887506

http://www.open-open.com/lib/view/open1438784972504.html

http://blog.csdn.net/redarmy_chen/article/details/26980613

时间: 2024-08-30 01:36:46

Anroid-async-http封装网络请求框架源码分析的相关文章

App 组件化/模块化之路——如何封装网络请求框架

App 组件化/模块化之路——如何封装网络请求框架 在 App 开发中网络请求是每个开发者必备的开发库,也出现了许多优秀开源的网络请求库.例如 okhttp retrofit android-async-http 这些网络请求库很大程度上提高程序猿的编码效率.但是随着业务的发展,App 变得越来越大,我们将这些网络请求库加入到项目中直接使用,对我们业务类的入侵是非常强的.如果要进行业务分离时,这些网络请求代码将是一个阻止我们进一步工作的绊脚石.对开发者来说是非常痛苦的. 因此我们构建的网络请求框

android 网络框架 源码分析

android 网络框架 源码分析 导语: 最近想开发一个协议分析工具,来监控android app 所有的网络操作行为, 由于android 开发分为Java层,和Native层, 对于Native层我们只要对linux下所有网络I/O接口进行拦截即可,对于java 层,笔者对android 网络框架不是很了解,所以这个工具开发之前,笔者需要对android 的网络框架进行一个简单的分析. 分析结论: 1. android 的网络框架都是基于Socket类实现的 2. java 层Socket

YII框架源码分析(百度PHP大牛创作-原版-无广告无水印)

                        YII 框架源码分析             百度联盟事业部--黄银锋   目 录 1. 引言 3 1.1.Yii 简介 3 1.2.本文内容与结构 3 2.组件化与模块化 4 2.1.框架加载和运行流程 4 2.2.YiiBase 静态类 5 2.3.组件 6 2.4.模块 9 2.5 .App 应用   10 2.6 .WebApp 应用   11 3.系统组件 13 3.1.日志路由组件  13 3.2.Url 管理组件  15 3.3.异常

iOS常用框架源码分析

SDWebImage NSCache 类似可变字典,线程安全,使用可变字典自定义实现缓存时需要考虑加锁和释放锁 在内存不足时NSCache会自动释放存储的对象,不需要手动干预 NSCache的key不会被复制,所以key不需要实现NSCopying协议 第三方框架 网络 1.PPNetworkHelper 对AFNetworking 3.x 与YYCache的二次封装 简单易用,包含了缓存机制,控制台可以直接打印json中文字符 2..YTKNetwork 猿题库研发团队基于AFNetworki

携程DynamicAPK插件化框架源码分析

携程DynamicAPK插件化框架源码分析 Author:莫川 插件核心思想 1.aapt的改造 分别对不同的插件项目分配不同的packageId,然后对各个插件的资源进行编译,生成R文件,然后与宿主项目的R文件进行id的合并. 要求:由于最终会将所有的资源文件id进行合并,因此,所有的资源名称均不能相同. 2.运行ClassLoader加载各Bundle 和MultiDex的思路是一样的,所有的插件都被加载到同一个ClassLoader当中,因此,不同插件中的Class必须保持包名和类名的唯一

CodeIgniter框架——源码分析之入口文件index.php

CodeIgniter框架的入口文件主要是配置开发环境,定义目录常量,加载CI的核心类core/CodeIgniter.php. 源码分析如下: <?php //这个文件是入口,后期所有的文件都要在这里执行. /*----------------------------------------------- * 系统环境配置常量 * 能够配置错误显示级别 * ----------------------------------------------- * 默认情况下: * developmen

介绍开源的.net通信框架NetworkComms框架 源码分析

原文网址: http://www.cnblogs.com/csdev Networkcomms 是一款C# 语言编写的TCP/UDP通信框架  作者是英国人  以前是收费的 售价249英镑 我曾经花了2千多购买过此通讯框架, 目前作者已经开源  许可是:Apache License v2 开源地址是:https://github.com/MarcFletcher/NetworkComms.Net 这个框架给我的感觉是,代码很优美,运行很稳定,我有一个项目使用此框架已经稳定运行1年多.这个框架能够

CodeIgniter框架——源码分析之CodeIgniter.php

CodeIgniter.php中加载了很多外部文件,完成CI的一次完整流程. <?php /** * 详见 http://www.phpddt.com/tag/codeIgniter/ */ //如果入口文件系统目录常量BASEPATH没定义,就挂了 if ( ! defined('BASEPATH')) exit('No direct script access allowed'); //定义常量:CI_VERSION,CI_CORE define('CI_VERSION', '2.1.4')

CodeIgniter框架——源码分析之Config.php

CI框架的配置信息被存储在$config数组中,我们可以添加自己的配置信息或配置文件到$config中: $this->config->load('filename'); //加载配置文件 $this->config->item('xxx'); //获取配置信息 当然也可以在autoload.php中设置默认加载! <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');   clas