一个好用的网络底层框架可以很大的程度上方便自己的项目,我们下面要做的就是一个趁手的网络框架。

做一个网络框架我们首先要确定这个网络框架除了能够从网络上获取数据还需要哪些功能:

  • 首先抛弃AsyncTask,自定义一套网络底层的封装框架。
  • 设计一套适合自己App的缓存策略
  • 设计一套假数据返回的机制,在网络请求API没有返回的时候,可以假装获取到了网络返回的数据。
  • 封装用户cookie的逻辑。

其他的还好,可能有人对于第一步的那个抛弃AsyncTask有些疑问,就是为什么要抛弃啊,这个类这个好用,内部封装了那么多的方法。但是我们不能只看到这个的优点,这个类有个致命的缺点:不能灵活的控制内部的线程池。

我们都知道的是,线程池里面的每个线程都是API的调用请求,而AsyncTask中有没有暴漏出取消这些请求的方法,这个时候,如果我们从A界面调到B界面,那么在A界面调用的API请求,如果还没有返回,并不会被取消,对于一个频繁调用API请求的APP应用应用来说,一个界面调用的API可能超过十个,在网络不好的情况下,如果这个时候跳转到了其他界面,这个时候其他界面也会调用API,这个时候造成的情况就是这个界面的请求并不会显示数据,因为首页的请求还在排队,要等首页的请求完成之后你才可以调用,这个就是所谓的AsyncTask堵塞。

我刚工作的时候遇到一个情况就是,根据公司的情况写了一个统计用户交互数据的SDK,开始的使用时候就是这个AsyncTask类,结构我发现在APP中某一个界面的吊起特别的慢,数据加载也非常的慢,发现的原因是我写的这个SDK中的API请求调用超时,并且在超时的时候重复调用三次这个API。

网络请求的格式

网络请求两个方法POST和GET,我们一般把GET方法为请求数据,POST为修改数据。请求的方法格式也是相对有讲究的。

Request

所有的MobileApi都可以写作:http://www.xxx.com/aaaa.api的形式。

  • GET:对于GET方法我们可以将请求API写作http://www.xxx.com/aaaa.api K1=va1&K2=va2,形式,也就是说,把key-value这样的键值对存放在URL上,这样做的话会方便我们后面对数据进行缓存,另外要精良是GET的参数都是String,int这样的类型,方便缓存,解析。
  • POST:我们都知道看不见POST的请求数据,一般key-value这样的键值对存放在Form表单中,最后进行提交请求。POST经常会提交大量数据,所以有些键值对要定义成集合或复杂的自定义实例,这个时候我们就需要把这样的值转换为JSON字符串进行提交,有APP传递到API后,在将JSON字符串转换为对于的实体。

Response

服务器现在用的最多的是使用JSON作为api返回的结果,这里也是使用JSON。

一般情况下返回的json数据中要有以下数据:

  • 首先一个是否调用api成功的参数,
  • 另外一个错误类型的参数(这个参数可以是Int格式的参数,成功为0)
  • 错误具体信息的参数,成功为“”
  • 具体API返回的结果,失败为“”

所以我们定义一个Response实体类,作为JSON实体的最外层。

package com.infrastructure.net;

/**
 * Created by binbin.ma on 2016/6/25.
 */
public class Response {
    private boolean error ;
    private int errorType ;
    private String errorMessage ;
    private String result ;

    public boolean hasError() {
        return error;
    }

    public void setError(boolean hasError) {
        this.error = hasError;
    }

    public int getErrorType() {
        return errorType;
    }

    public void setErrorType(int errorType) {
        this.errorType = errorType;
    }

    public String getErrorMessage() {
        return errorMessage;
    }

    public void setErrorMessage(String errorMessage) {
        this.errorMessage = errorMessage;
    }

    public String getResult() {
        return result;
    }

    public void setResult(String result) {
        this.result = result;
    }
}

如果成功返回了数据,数据会存放在result字符按中,映射为Response实体的result属性。

如果上面返回的result是一种实体的集合,那么就要把result解析为相应的实体集合。

我们在前面看到我们把AsyncTask抛弃重新写一个扩展性强的,可以随时取消API请求网络底层,那么我们的这个网络底层的线程池使用的是什么:使用原生的ThreadPoolExecutor + Runnable + Handler

首先我们要把App所调用的所有的API接口放到一个类或者xml文件中去,我们这里放在xml文件里面去,当然要写出读取xml的类和函数:

<?xml version="1.0" encoding="UTF-8"?>
<url>

    <Node Key="sendException"
        Expires="0"
        NetType="get"
        Url="http://192.168.9.59:8080/userInfo/app_exception_service"/>
</url>

package com.infrastructure.net;

import android.app.Activity;
import android.content.res.XmlResourceParser;

import com.infrastructure.R;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 
 */
public class UrlConfigManager {

    private static ArrayList<URLData> urlList ;


    private static void fetchUrlDataFromXml(final Activity activity) {
        urlList = new ArrayList<URLData>();

        final XmlResourceParser xmlParser = activity.getApplication()
                .getResources().getXml(R.xml.url);

        int eventCode;
        try {
            eventCode = xmlParser.getEventType();
            while (eventCode != XmlPullParser.END_DOCUMENT) {
                switch (eventCode) {
                    case XmlPullParser.START_DOCUMENT:
                        break;
                    case XmlPullParser.START_TAG:
                        if ("Node".equals(xmlParser.getName())) {
                            final String key = xmlParser.getAttributeValue(null,
                                    "Key");
                            final URLData urlData = new URLData();
                            urlData.setKey(key);
                            urlData.setExpires(Long.parseLong(xmlParser
                                    .getAttributeValue(null, "Expires")));
                            urlData.setNetType(xmlParser.getAttributeValue(null,
                                    "NetType"));
                            urlData.setMockClass(xmlParser.getAttributeValue(null,
                                    "MockClass"));
                            urlData.setUrl(xmlParser.getAttributeValue(null, "Url"));
                            urlList.add(urlData);
                        }
                        break;
                    case XmlPullParser.END_TAG:
                        break;
                    default:
                        break;
                }
                eventCode = xmlParser.next();
            }
        } catch (final XmlPullParserException e) {
            e.printStackTrace();
        } catch (final IOException e) {
            e.printStackTrace();
        } finally {
            xmlParser.close();
        }
    }
    public static URLData findURL(final Activity activity,
                                  final String findKey) {
        // 如果urlList还没有数据(第一次),或者被回收了,那么(重新)加载xml
        if (urlList == null || urlList.isEmpty())
            fetchUrlDataFromXml(activity);

        for (URLData data : urlList) {
            if (findKey.equals(data.getKey())) {
                return data;
            }
        }
        return null;
    }
}

package com.infrastructure.net;

/**

 */
public class URLData {
    private String key ;
    private long expires ;
    private String netType ;
    private String url ;
    private String mockClass ;

    public URLData(
    ) {
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public long getExpires() {
        return expires;
    }

    public void setExpires(long expires) {
        this.expires = expires;
    }

    public String getNetType() {
        return netType;
    }

    public void setNetType(String netType) {
        this.netType = netType;
    }

    public String getMockClass() {
        return mockClass;
    }

    public void setMockClass(String mockClass) {
        this.mockClass = mockClass;
    }
}

其中key和url的值符合key-value键值,expires代表数据缓存的时间单位为毫秒,netType代表请求方式(POST和GET) ,mockClass代表的是返回假数据的类。

RemoteService和RequestCallback和RequestParameter

这三个类表示的是请求的服务,请求返回,请求参数,三个给APP调用的类。

package com.infrastructure.net;

/**

 */
public interface RequestCallback {
    public void onSuccess(String content) ;
    public void onFail(String errorMessage) ;
    public void onCookieExpired();
}

package com.infrastructure.net;

import java.io.Serializable;
import java.util.Comparator;
import java.util.Objects;

/**

 */
public class RequestParameter  implements Serializable,Comparator<Object>{

    private String name ;
    private String value ;

    public RequestParameter(String name, String value) {
        this.name = name;
        this.value = value;
    }

    public boolean equals(final Object o){
        if (null == o){
            return  false;
        }
        if (this == o){
            return true ;
        }
        if (o instanceof RequestParameter){
            final RequestParameter parameter = (RequestParameter) o;
            return name.equals(parameter.name) && value.equals(parameter.value) ;
        }
        return false ;
    }

    @Override
    public int compare(Object lhs, Object rhs) {
        int compared ;
        final RequestParameter parameter = (RequestParameter) rhs;
        compared = name.compareTo(parameter.value) ;
        if (compared == 0){
            compared = value.compareTo(parameter.value) ;
        }
        return compared;
    }


    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

package com.youngheart.engine;

import android.util.Log;

import java.util.List;

import com.alibaba.fastjson.JSON;
import com.infrastructure.activity.BaseActivity;
import com.infrastructure.net.DefaultThreadPool;
import com.infrastructure.net.HttpRequest;
import com.infrastructure.net.RequestCallback;
import com.infrastructure.net.RequestManager;
import com.infrastructure.net.RequestParameter;
import com.infrastructure.net.Response;
import com.infrastructure.net.URLData;
import com.infrastructure.net.UrlConfigManager;
import com.youngheart.mockdata.MockService;

public class RemoteService {
    private static RemoteService service = null;

    private static final String TAG = "RemoteService" ;

    private RemoteService() {

    }

    public static synchronized RemoteService getInstance() {
        if (RemoteService.service == null) {
            RemoteService.service = new RemoteService();
        }
        return RemoteService.service;
    }


    public void invoke(final BaseActivity activity,
                       final String apiKey,
                       final List<RequestParameter> params,
                       final RequestCallback callBack,final boolean forceUpdate) {

        final URLData urlData = UrlConfigManager.findURL(activity, apiKey);
        if (forceUpdate){
            urlData.setExpires(0);
        }
        if (null == urlData.getMockClass()) {
            HttpRequest request = activity.getRequestManager().createRequest(
                    urlData, params, callBack);
            DefaultThreadPool.getInstance().execute(request);
        }else
        {
            try {
                MockService mockService = (MockService) Class.forName(urlData.getMockClass()).newInstance();
                String strResponse = mockService.getJSONData();

                final Response responseInJSON = JSON.parseObject(strResponse,Response.class) ;
                Log.d(TAG, "invoke: "+responseInJSON);
                if (callBack != null){
                    if (responseInJSON.hasError()){
                        callBack.onFail(responseInJSON.getErrorMessage());
                    }else
                    {
                        callBack.onSuccess(responseInJSON.getResult());
                    }
                }

            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    }
}

用户调用时只需要调用RemoteService中的invoke方法即可。

RemoteService.getInstance().invoke(Context context,String key,RequestParameters requestParameters,RequestCallback callback,boolean forceUpdate);

其他的两个类在方法中调用:

  • context:表示上下文
  • key:即xml文件中的key
  • RequestParameter:请求携带的参数
  • callback:请求回调
  • forceUpdate:是否强制更新数据,忽略缓存

RequestMannager类是一个集合类,用于取消请求的。每次发起请求时,都会把为此创建的Request添加到RequestManager中,即RequestManager中保存了全部的request。

package com.infrastructure.net;

import java.util.ArrayList;
import java.util.List;

import com.infrastructure.activity.BaseActivity;

public class RequestManager {
	ArrayList<HttpRequest> requestList = null;

	public RequestManager(final BaseActivity activity) {
		// 异步请求列表
		requestList = new ArrayList<HttpRequest>();
	}

	/**
	 * 添加Request到列表
	 */
	public void addRequest(final HttpRequest request) {
		requestList.add(request);
	}

	/**
	 * 取消网络请求
	 */
	public void cancelRequest() {
		if ((requestList != null) && (requestList.size() > 0)) {
			for (final HttpRequest request : requestList) {
				if (request.getRequest() != null) {
					try {
						request.getRequest().abort();
						requestList.remove(request.getRequest());
					} catch (final UnsupportedOperationException e) {
						e.printStackTrace();
					}
				}
			}
		}
	}

	/**
	 * 无参数调用
	 */
	public HttpRequest createRequest(final URLData urlData,
			final RequestCallback requestCallback) {
		return createRequest(urlData, null, requestCallback);
	}

	/**
	 * 有参数调用
	 */
	public HttpRequest createRequest(final URLData urlData,
			final List<RequestParameter> params,
			final RequestCallback requestCallback) {
		final HttpRequest request = new HttpRequest(urlData, params,
				requestCallback);

		addRequest(request);
		return request;
	}
}

我们只需要在所有的Activity的onPouse和onDestroy周期中调用取消支付就好了

if (requestManager != null){
            requestManager.cancelRequest();
        }

而这个网络请求底层框架的线程池使用的是ThreadPoolExecutor创建的类是DefaultThreadPool:

package com.infrastructure.net;

import java.util.concurrent.AbstractExecutorService;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 线程池 、缓冲队列
 * 
 */
public class DefaultThreadPool {
	// 阻塞队列最大任务数量
	static final int BLOCKING_QUEUE_SIZE = 20;
	static final int THREAD_POOL_MAX_SIZE = 10;

	static final int THREAD_POOL_SIZE = 6;
	/**
	 * 缓冲BaseRequest任务队列
	 */
	static ArrayBlockingQueue<Runnable> blockingQueue = new ArrayBlockingQueue<Runnable>(
			DefaultThreadPool.BLOCKING_QUEUE_SIZE);

	private static DefaultThreadPool instance = null;
	/**
	 * 线程池,目前是十个线程,
	 */
	static AbstractExecutorService pool = new ThreadPoolExecutor(
			DefaultThreadPool.THREAD_POOL_SIZE,
			DefaultThreadPool.THREAD_POOL_MAX_SIZE, 15L, TimeUnit.SECONDS,
			DefaultThreadPool.blockingQueue,
			new ThreadPoolExecutor.DiscardOldestPolicy());

	public static synchronized DefaultThreadPool getInstance() {
		if (DefaultThreadPool.instance == null) {
			DefaultThreadPool.instance = new DefaultThreadPool();
		}
		return DefaultThreadPool.instance;
	}

	public static void removeAllTask() {
		DefaultThreadPool.blockingQueue.clear();
	}

	public static void removeTaskFromQueue(final Object obj) {
		DefaultThreadPool.blockingQueue.remove(obj);
	}

	/**
	 * 关闭,并等待任务执行完成,不接受新任务
	 */
	public static void shutdown() {
		if (DefaultThreadPool.pool != null) {
			DefaultThreadPool.pool.shutdown();
		}
	}

	/**
	 * 关闭,立即关闭,并挂起所有正在执行的线程,不接受新任务
	 */
	public static void shutdownRightnow() {
		if (DefaultThreadPool.pool != null) {
			DefaultThreadPool.pool.shutdownNow();
			try {
				// 设置超时极短,强制关闭所有任务
				DefaultThreadPool.pool.awaitTermination(1,
						TimeUnit.MICROSECONDS);
			} catch (final InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 执行任务
	 * 
	 * @param r
	 */
	public void execute(final Runnable r) {
		if (r != null) {
			try {
				DefaultThreadPool.pool.execute(r);
			} catch (final Exception e) {
				e.printStackTrace();
			}
		}
	}
}

他是对ThreadPoolExecutor和ArrayBlockingQueue的简单封装,是一个线程池,每发起一次请求,这个线程池就会分配一个新的线程来执行该请求。

HttpRequest类,发起HTTP请求的地方,他事先了Runable,从而让DefaultThreadPool可以分配新的线程,所以所有的请求逻辑都在Runnable接口方法里:

package com.infrastructure.net;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;
import java.util.zip.GZIPInputStream;

import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;

import android.os.Handler;
import android.preference.PreferenceActivity;
import android.util.Log;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.infrastructure.cache.CacheManager;
import com.infrastructure.utils.BaseUtils;
import com.infrastructure.utils.FrameConstants;

public class HttpRequest implements Runnable {

    private static final String TAG = "HttpRequest" ;
    // 区分get还是post的枚举
    public static final String REQUEST_GET = "get";
    public static final String REQUEST_POST = "post";

    private final static String cookiePath = "/data/data/com.youngheart/cache/cookie";

    private HttpUriRequest request = null;
    private URLData urlData = null;
    private RequestCallback requestCallback = null;
    private List<RequestParameter> parameter = null;
    private String url = null; // 原始url
    private String newUrl = null; // 拼接key-value后的url
    private HttpResponse response = null;
    private DefaultHttpClient httpClient;

    // 切换回UI线程
    protected Handler handler;

    protected boolean cacheRequestData = true;

    HashMap<String,String> headers ;

    static long deltaBetweenServerAndClientTime; // 服务器时间和客户端时间的差值

    public HttpRequest(final URLData data, final List<RequestParameter> params,
                       final RequestCallback callBack) {
        urlData = data;

        url = urlData.getUrl();
        this.parameter = params;
        requestCallback = callBack;

        if (httpClient == null) {
            httpClient = new DefaultHttpClient();
        }

        handler = new Handler();
        headers = new HashMap<>() ;
    }

    /**
     * 获取HttpUriRequest请求
     *
     * @return
     */
    public HttpUriRequest getRequest() {
        return request;
    }

    @Override
    public void run() {
        try {
            if (urlData.getNetType().equals(REQUEST_GET)) {
                // 添加参数
                final StringBuffer paramBuffer = new StringBuffer();
                if ((parameter != null) && (parameter.size() > 0)) {

                    // 这里要对key进行排序
                    sortKeys();

                    for (final RequestParameter p : parameter) {
                        if (paramBuffer.length() == 0) {
                            paramBuffer.append(p.getName() + "="
                                    + BaseUtils.UrlEncodeUnicode(p.getValue()));
                        } else {
                            paramBuffer.append("&" + p.getName() + "="
                                    + BaseUtils.UrlEncodeUnicode(p.getValue()));
                        }
                    }

                    newUrl = url + "?" + paramBuffer.toString();
                } else {
                    newUrl = url;
                }

                // 如果这个get的API有缓存时间(大于0)
                if (urlData.getExpires() > 0) {
                    final String content = CacheManager.getInstance()
                            .getFileCache(newUrl);
                    if (content != null) {
                        Log.d(TAG,"handle.post") ;
                         handler.post(new Runnable() {
                            @Override
                            public void run() {
                                requestCallback.onSuccess(content);
                            }

                        });
                        return;
                    }
                }

                request = new HttpGet(newUrl);

            } else if (urlData.getNetType().equals(REQUEST_POST)) {
                request = new HttpPost(url);
                // 添加参数
                if ((parameter != null) && (parameter.size() > 0)) {
                    final List<BasicNameValuePair> list = new ArrayList<BasicNameValuePair>();
                    for (final RequestParameter p : parameter) {
                        list.add(new BasicNameValuePair(p.getName(), p
                                .getValue()));
                    }

                    ((HttpPost) request).setEntity(new UrlEncodedFormEntity(
                            list, HTTP.UTF_8));
                }
            } else {
                return;
            }

            request.getParams().setParameter(
                    CoreConnectionPNames.CONNECTION_TIMEOUT, 30000);
            request.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT,
                    30000);
            /**
             * 添加必要的头信息
             */
            setHttpHeaders(request) ;
            // 添加Cookie到请求头中
            addCookie();
            // 发送请求
            response = httpClient.execute(request);
            // 获取状态
            final int statusCode = response.getStatusLine().getStatusCode();
            // 设置回调函数,但如果requestCallback,说明不需要回调,不需要知道返回结果
             if ((requestCallback != null)) {
                if (statusCode == HttpStatus.SC_OK) {

                    updateDeltaBetweenServerAndClientTime();

                    final ByteArrayOutputStream content = new ByteArrayOutputStream();
                    String strResponse = "" ;
                    if ((response.getEntity().getContentEncoding() != null)&&(response.getEntity().getContentEncoding().getValue() != null)){
                        if (response.getEntity().getContentEncoding().getValue().contains("gzip")){
                            final InputStream in = response.getEntity().getContent();
                            final InputStream is = new GZIPInputStream(in) ;
                            strResponse = HttpRequest.inputStreamToString(is) ;
                            is.close();
                        }else{
                            response.getEntity().writeTo(content);
                            strResponse = new String(content.toByteArray()).trim();
                        }

                    }else{
                        response.getEntity().writeTo(content);
                        strResponse = new String(content.toByteArray()).trim();
                    }
                    Log.d(TAG, "run: ----------------------------->"+strResponse);

                    final Response responseInJson = new Response();
                    if (strResponse == null) {
                        responseInJson.setError(true);
                        responseInJson.setErrorMessage("网络异常");
                    } else {
                        responseInJson.setError(false);
                        responseInJson.setResult(strResponse);
                    }
                    if (responseInJson.hasError()) {
                       if (responseInJson.getErrorType() == 1){
                            handler.post(new Runnable() {
                                @Override
                                public void run() {
                                    requestCallback.onCookieExpired();
                                }
                            }) ;
                       }else{
                           handleNetworkError(responseInJson.getErrorMessage());
                       }
                    } else {
                        // 把成功获取到的数据记录到缓存
                        if (urlData.getNetType().equals(REQUEST_GET)
                                && urlData.getExpires() > 0) {
                            CacheManager.getInstance().putFileCache(newUrl,
                                    responseInJson.getResult(),
                                    urlData.getExpires());
                        }
                        Log.d(TAG, "run: handler.post");
                        handler.post(new Runnable() {

                            @Override
                            public void run() {
                                requestCallback.onSuccess(responseInJson
                                        .getResult());
                            }

                        });
                        saveCookie();
                    }
                } else {
                    handleNetworkError("网络异常");
                }
            } else {
                handleNetworkError("网络异常");
            }
        } catch (final java.lang.IllegalArgumentException e) {
            handleNetworkError("网络异常");
        } catch (final UnsupportedEncodingException e) {
            handleNetworkError("网络异常");
        } catch (final IOException e) {
            handleNetworkError("网络异常");
        }
    }

    public void handleNetworkError(final String errorMsg) {
        if (requestCallback != null) {
            handler.post(new Runnable() {
                @Override
                public void run() {
                    requestCallback.onFail(errorMsg);
                }
            });
        }
    }

    /**
     * cookie列表保存到本地
     *
     * @return
     */
    public synchronized void saveCookie() {
        // 获取本次访问的cookie
        final List<Cookie> cookies = httpClient.getCookieStore().getCookies();
        // 将普通cookie转换为可序列化的cookie
        List<SerializableCookie> serializableCookies = null;

        if ((cookies != null) && (cookies.size() > 0)) {
            serializableCookies = new ArrayList<SerializableCookie>();

            for (final Cookie c : cookies) {
                serializableCookies.add(new SerializableCookie(c));
            }
        }

        BaseUtils.saveObject(cookiePath, serializableCookies);
    }

    void setHttpHeaders(final HttpUriRequest httpMessage){
        headers.clear();
        headers.put(FrameConstants.ACCEPT_CHARSET,"UTF-8") ;
        headers.put(FrameConstants.USER_AGENT,"Young Heart Android App ") ;
        headers.put(FrameConstants.ACCEPT_ENCODING,"gzip") ;
        if ((httpMessage != null)&&(headers != null)){
            for (final Map.Entry<String,String> entry:headers.entrySet()){
                if (entry.getKey() != null){
                    httpMessage.addHeader(entry.getKey(),entry.getValue());
                }
            }
        }
    }

    static String inputStreamToString(final InputStream is) throws IOException {
        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
        int i = -1;
        while ((i = is.read()) != -1) {
            baos.write(i);
        }
        return baos.toString();
    }

    void sortKeys() {
        for (int i = 1; i < parameter.size(); i++) {
            for (int j = i; j > 0; j--) {
                RequestParameter p1 = parameter.get(j - 1);
                RequestParameter p2 = parameter.get(j);
                if (compare(p1.getName(), p2.getName())) {
                    // 交互p1和p2这两个对象,写的超级恶心
                    String name = p1.getName();
                    String value = p1.getValue();

                    p1.setName(p2.getName());
                    p1.setValue(p2.getValue());

                    p2.setName(name);
                    p2.setValue(value);
                }
            }
        }
    }

    // 返回true说明str1大,返回false说明str2大
    boolean compare(String str1, String str2) {
        String uppStr1 = str1.toUpperCase();
        String uppStr2 = str2.toUpperCase();

        boolean str1IsLonger = true;
        int minLen = 0;

        if (str1.length() < str2.length()) {
            minLen = str1.length();
            str1IsLonger = false;
        } else {
            minLen = str2.length();
            str1IsLonger = true;
        }

        for (int index = 0; index < minLen; index++) {
            char ch1 = uppStr1.charAt(index);
            char ch2 = uppStr2.charAt(index);
            if (ch1 != ch2) {
                if (ch1 > ch2) {
                    return true; // str1大
                } else {
                    return false; // str2大
                }
            }
        }

        return str1IsLonger;
    }

    @SuppressWarnings("unchecked")
    public void addCookie(){
        List<SerializableCookie> cookieList = null ;
        Object cookieObject = BaseUtils.restoreObject(cookiePath);
        if (cookieObject != null){
            cookieList = (List<SerializableCookie>) cookieObject;
        }
        if ((cookieList!=null)&&(cookieList.size()>0)){
            final BasicCookieStore cs = new BasicCookieStore();
            cs.addCookies(cookieList.toArray(new Cookie[] {}));
            httpClient.setCookieStore(cs);
        }else
        {
            httpClient.setCookieStore(null);
        }
    }

    /**
     * 更新服务器时间和本地时间的差值
     */
    void updateDeltaBetweenServerAndClientTime(){
        if (response != null){
            final Header header = response.getLastHeader("Date") ;
            if (header != null){
                final String strServerDate = header.getValue();
                try{
                 if ((strServerDate != null)&& strServerDate.equals("")){
                     final SimpleDateFormat sdf = new SimpleDateFormat("EEE,d MMM yyyy HH:mm:ss z", Locale.ENGLISH) ;
                     TimeZone.setDefault(TimeZone.getTimeZone("GMT+8"));
                     Date serverDateUAT = sdf.parse(strServerDate) ;
                     deltaBetweenServerAndClientTime = serverDateUAT.getTime() + 8 * 60 * 60 * 1000 - System.currentTimeMillis();
                 }
                } catch (ParseException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static Date getServerTime(){
        return new Date(System.currentTimeMillis()+deltaBetweenServerAndClientTime) ;
    }
}


在这个类中对于get请求接口,他会把传递来的数据,处理为相应的格式:http://www.xxx.com/aaaa.api K1=va1&K2=va2。对于Post格式的请求接口,他会把传递过来的数据转换为BasicNameValuePair的形式,并放在表单中提交。

需要注意的是,因为我们把每个HttpRequest都放在了子线程中执行,所以RequestCallback的回调不能直接操作UI线程的控件,所以这个时候Handler就可以用到了。使用这个就可以保证RequestCallback的回调在UI线程上,不会报错。