您的位置:首页 > 理论基础 > 计算机网络

自己动手写HTTP框架:ThreadPool+Runnable+handler篇

2016-06-30 22:23 393 查看
  既然异步任务有诸多问题,那么我们可以尝试使用ThreadPoolExecutor+Runnable+Handler来对网络底层进行封装。

类图



具体流程:首先构造一个请求Request,然后通过这个请求RequestManager可以构造一个NetWorkExecutor,然后从DefaultThreadPool中选择一个线程来执行这个NetWorkExecutor。把结果回调到RequestCallback中去。

运行流程(时序图)



核心模块分析

RequestCallback

RequestCallback是回调,目前拥有onSuccess和onFail两种.

public interface RequestCallback<T> {
public void onSuccess(T response);

public void onFail(String errorMessage);
}


RequestParameter

  是用来传递MobileAPI接口所需参数的键值对的。我们原本可以使用HashMap

Request

为了支持多种请求格式的扩展,这里Request设置为抽象类。

public abstract class Request<T> {
public enum RequestMethod {
GET, POST, DELETE, PUT
}

private RequestMethod method;
private String url;
private RequestCallback mCallback;
private List<RequestParameter> mParams;

public Request(String url, RequestMethod method, RequestCallback callback, List<RequestParameter> params) {
this.url = url;
this.method = method;
this.mCallback = callback;
this.mParams = params;
}

/**
* 从原生的网络请求中解析结果
*
* @param response
* @return
*/
public abstract T parseResponse(Response response);

/**
* 处理Response,该方法运行在UI线程.
*
* @param response
*/
public final void deliveryResponse(Response response) {
T result = parseResponse(response);
if (mCallback != null) {
int stCode = response != null ? response.getStatusCode() : -1;
String msg = response != null ? response.getMessage() : "unkown error";
Log.e("", "### 执行回调 : stCode = " + stCode + ", result : " + result + ", err : " + msg);
mCallback.onSuccess(result);
}
}

public String getUrl() {
return url;
}

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

public RequestMethod getMethod() {
return method;
}

public void setMethod(RequestMethod method) {
this.method = method;
}

public RequestCallback getCallback() {
return mCallback;
}

public void setCallback(RequestCallback callback) {
mCallback = callback;
}

public List<RequestParameter> getParams() {
return mParams;
}

public void setParams(List<RequestParameter> params) {
mParams = params;
}
}


RequestManager

   一个单例,你可以调用它来创建一个request,然后构造一个NetworkExecutor,然后放到DefaultThreadPool的一个线程池中去执行这个request。

public class RequestManager {
private static RequestManager instance = new RequestManager();

private RequestManager() {
}

public static RequestManager getInstance() {
if (instance == null) {
instance = new RequestManager();
}
return instance;
}

/**
* 取消网络请求
*/
// 应该是是直接调用DefaultThreadPool里的方法吧,removeTaskFromQueue
public void cancelRequest() {
DefaultThreadPool.getInstance().removeAllTask();
}

/**
* 有参数调用
*/
public void executeRequest(Request request) {
final NetworkExecutor executor = new NetworkExecutor(request);
DefaultThreadPool.getInstance().execute(executor);
}
}


NetworkExecutor

  NetworkExecutor是发起网络请求的地方,它实现了Runnable,从而让DefaultThreadPool

可以分配新的线程来执行它,所以,所有的请求逻辑都在run方法中

对于get形式的mobileAPI接口,它会把上层传递进来的ArrayList,解析为url?k1=v1&k2=v2这样的形式。

对于post格式的mobileAPI接口,它会把从上层传递进来的ArrayList转化为BasicNameValuePair的形式,放到表单中进行提交。

  因为我们把每个请求都放到了子线程中去执行,所以回调RequestCallback的onSuccess方法时,不能直接操作UI线程中的控件,所以我们在NetworkExecutor中使用了Handler。

// 设置回调函数
if ((requestCallback != null)) {
final Response responseInJson = JSON.parseObject(
strResponse, Response.class);
if (responseInJson.hasError()) {
handleNetworkError(responseInJson.getErrorMessage());
} else {
handler.post(new Runnable() {

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

});


这样保证了RequestCallback的onSuccess方法是在UI线程上的。

DefaultThreadPool

  DefaultThreadPool仅仅是对ThreadPoolExecutor和ArrayBlockingQueue的简单封装。

  我们可以认为它是一个线程池,每发起一次请求(runnable),就由线程池分配一个新的线程来执行该请求。

/**
* 线程池 、缓冲队列
* DefaultThreadPool仅仅是对ThreadPoolExecutor和ArrayBlockingQueue的简单封装。
* 我们可以认为它是一个线程池,每发起一次请求(runnable),就由线程池分配一个新的线程来执行该请求。
*/
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 void removeAllTask() {
DefaultThreadPool.blockingQueue.clear();
}

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

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

/**
* 关闭,立即关闭,并挂起所有正在执行的线程,不接受新任务
*/
public 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();
}
}
}
}


源码地址:

https://github.com/zhujainxipan/FYForAndroidTest
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: