自己动手写HTTP框架:ThreadPool+Runnable+handler篇
2016-06-30 22:23
393 查看
既然异步任务有诸多问题,那么我们可以尝试使用ThreadPoolExecutor+Runnable+Handler来对网络底层进行封装。
具体流程:首先构造一个请求Request,然后通过这个请求RequestManager可以构造一个NetWorkExecutor,然后从DefaultThreadPool中选择一个线程来执行这个NetWorkExecutor。把结果回调到RequestCallback中去。
可以分配新的线程来执行它,所以,所有的请求逻辑都在run方法中
对于get形式的mobileAPI接口,它会把上层传递进来的ArrayList,解析为url?k1=v1&k2=v2这样的形式。
对于post格式的mobileAPI接口,它会把从上层传递进来的ArrayList转化为BasicNameValuePair的形式,放到表单中进行提交。
因为我们把每个请求都放到了子线程中去执行,所以回调RequestCallback的onSuccess方法时,不能直接操作UI线程中的控件,所以我们在NetworkExecutor中使用了Handler。
这样保证了RequestCallback的onSuccess方法是在UI线程上的。
我们可以认为它是一个线程池,每发起一次请求(runnable),就由线程池分配一个新的线程来执行该请求。
类图
具体流程:首先构造一个请求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接口所需参数的键值对的。我们原本可以使用HashMapRequest
为了支持多种请求格式的扩展,这里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相关文章推荐
- http://www.tuicool.com/articles/B3qeUrB
- 波尔远程控制软件与网络人远程控制软件大比拼
- 波尔远程控制软件与网络人远程控制软件大比拼
- Qt---基于TCP聊天室
- 劫持网络--运营商投放广告
- ubuntu开机无网络-解决方法记录
- HTTP和HTTPS详解
- 编写C语言版本的卷积神经网络CNN之四:CNN的学习及测试结果的比较
- 伪造IP包,禁止TCP连接
- HTTP Live Streaming直播(iOS直播)技术分析与实现
- 网络流
- labview之tcp通信
- iOS判断当前是否有网络
- 安卓学习之-ConnectivityManager(判断网络连接)
- 使用httpClient请求的网络数据
- ios调用unix 网络编程的socket 接口实行UDP通信, 锁屏后解屏会闪退的解决方法
- httputils用法
- 《HTTP权威指南》——集成点:网关、隧道、中继
- 通过httpUtils请求网络xml数据进行解析
- Android 获取视频(本地和网络)缩略图的解决方案