【Android下基于线程池的网络访问基础框架】今日长缨在手,何时缚住苍龙。这篇文章主要讲述Android下基于线程池的网络访问基础框架相关的知识,希望能为你提供帮助。
引言
现在的android开发很多都使用Volley、OkHttp、Retrofit等框架,这些框架固然有优秀的地方(以后会写代码学习分享),但是我们今天介绍一种基于java线程池的网络访问框架。
实现思路及实现
APP界面上面的数据都是通过网络请求获取的,我们能不能将网络请求依次入队,然后配合着Java线程池,让线程依次处理我们的请求,最后返回结果给我们。下面我们先来看一下线程池工具类的实现:
1 public class ThreadPoolUtils { 2 3private ThreadPoolUtils() {} 4//核心线程数 5private static int CORE_POOL_SIZE = 8; 6//最大线程数 7private static int MAX_POOL_SIZE = 64; 8//线程池中超过corePoolSize数目的空闲线程最大存活时间;可以allowCoreThreadTimeOut(true)使得核心线程有效时间 9private static int KEEP_ALIVE_TIME = 5; 10//任务队列 11private static BlockingQueue< Runnable> workQueue = new ArrayBlockingQueue< > (64); 12 13private static ThreadPoolExecutor threadpool; 14 15static { 16threadpool = new ThreadPoolExecutor(CORE_POOL_SIZE, MAX_POOL_SIZE, KEEP_ALIVE_TIME, TimeUnit.SECONDS, workQueue); 17} 18 19public static void execute(Runnable runnable) { 20threadpool.execute(runnable); 21} 22 }
我们来看一下ThreadPoolExecutor的构造函数及相关参数:
参数名 | 作用 |
corePoolSize | 核心线程池大小 |
maximumPoolSize | 最大线程池大小 |
keepAliveTime | 线程池中超过corePoolSize数目的空闲线程最大存活时间;可以allowCoreThreadTimeOut(true)使得核心线程有效时间 |
TimeUnit | keepAliveTime时间单位 |
workQueue | 阻塞任务队列 |
threadFactory | 新建线程工厂 |
RejectedExecutionHandler | 当提交任务数超过maxmumPoolSize+workQueue之和时,任务会交给RejectedExecutionHandler来处理 |
其中比较容易让人误解的是:corePoolSize,maximumPoolSize,workQueue之间关系。
1.当线程池小于corePoolSize时,新提交任务将创建一个新线程执行任务,即使此时线程池中存在空闲线程。
2.当线程池达到corePoolSize时,新提交任务将被放入workQueue中,等待线程池中任务调度执行
3.当workQueue已满,且maximumPoolSize> corePoolSize时,新提交任务会创建新线程执行任务
4.当提交任务数超过maximumPoolSize时,新提交任务由RejectedExecutionHandler处理
5.当线程池中超过corePoolSize线程,空闲时间达到keepAliveTime时,关闭空闲线程
6.当设置allowCoreThreadTimeOut(true)时,线程池中corePoolSize线程空闲时间达到keepAliveTime也将关闭
网络访问的封装
通过上面的分析,我们知道ThreadPoolExecutor里面可以执行Runable对象,那么我们将网络访问逻辑封装成Runable对象,然后扔进线程池进行执行。我们来看一下封装的逻辑:
1 /** 2* post线程 3*/ 4 public class HttpPostThread implements Runnable { 5 6private Handler hand; 7private String strURL; 8private String method; 9private List< String> params; 10private Handler netHand; 11 12public HttpPostThread(Handler hand, String strURL, String method, List< String> params) { 13this.hand = hand; 14//实际的传值 15this.strURL = strURL; 16this.method = method; 17this.params = params; 18} 19 20public HttpPostThread(Handler hand, Handler netHand, String strURL, String method, List< String> params) { 21this.hand = hand; 22//实际的传值 23this.strURL = strURL; 24this.method = method; 25this.params = params; 26this.netHand = netHand; 27} 28 29@Override 30public void run() { 31Message msg = hand.obtainMessage(); 32try { 33String result; 34if(!strURL.startsWith("https")) { 35RpcHttp rpcHttp = new RpcHttp(); 36result = rpcHttp.post(strURL, method, params); 37} 38else { 39RpcHttps rpcHttps = new RpcHttps(); 40result = rpcHttps.post(strURL, method, params); 41} 42/** 43* 根据访问http来设置标识位 44* 然后发送msg到handlerMessage进行处理(此处配合Handler进行使用) 45*/ 46if (result.equals("noNet")) { 47if (netHand != null) { 48netHand.sendEmptyMessage(600); 49} 50} else { 51msg.what = 200; 52msg.obj = result; 53} 54} catch(Exception e){ 55e.printStackTrace(); 56} 57finally { 58hand.sendMessage(msg); 59} 60} 61 }
我们看到,我们封装的这个类的构造函数只需要使用者提供回调的Handler、Http访问的Url、访问的方法及参数。这样就可以将其放入线程中进行处理,然后我们只需要在客户端使用写好回调的Handler即可。我们看34-40行,这时候我们看到会使用封装的Http类去进行网络访问,我们来看一下:
1/** 2* post请求 3* 4* @param strURL 请求的地址 5* @param method 请求方法 6* @param params 请求元素 7* @return 8*/ 9public String post(String strURL, String method, List< String> params) { 10Log.e("开始请求","获取请求"); 11String RequestParams = ""; 12long timestamp = System.currentTimeMillis(); 13RequestParams += "{\"method\":\"" + method + "\""; 14if (params != null & & params.size() > 0) { 15RequestParams += ",\"params\":{"; 16for (String item : params) { 17String first = item.substring(0, item.indexOf(":")); 18String second = item.substring(item.indexOf(":") + 1); 19RequestParams += "\"" + first + "\":\"" + second + "\","; 20} 21 22RequestParams = RequestParams.substring(0, (RequestParams.length() - 1)); 23RequestParams += "}"; 24} else { 25RequestParams += ",\"params\":{}"; 26} 27RequestParams += ",\"id\":\"" + timestamp + "\""; 28RequestParams += "}"; 29return this.post(strURL, RequestParams); 30} 31 32private String post(String strURL, String params) { 33try { 34URL url = new URL(strURL); // 创建连接 35HttpURLConnection connection = (HttpURLConnection) url.openConnection(); 36 37connection.setDoOutput(true); 38connection.setDoInput(true); 39connection.setUseCaches(false); 40connection.setInstanceFollowRedirects(true); 41connection.setRequestMethod("POST"); // 设置请求方式 42connection.setRequestProperty("Accept", "application/json"); // 设置接收数据的格式 43connection.setRequestProperty("Content-Type", "application/json"); // 设置发送数据的格式 44connection.setConnectTimeout(10000); //设置超时 45connection.setReadTimeout(10000); //设置超时 46Log.e("开始连接","开始连接"); 47connection.connect(); 48 49OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream(), "UTF-8"); // utf-8编码 50out.append(params); 51out.flush(); 52out.close(); 53 54String result = convertStreamToString(connection.getInputStream()); 55Log.e("responseContent",result); 56return result; 57} catch (Exception e) { 58Log.e("responseException",String.valueOf(e.getStackTrace())); 59Log.e("responseException",String.valueOf(e.getLocalizedMessage())); 60Log.e("responseException",String.valueOf(e.getMessage())); 61e.printStackTrace(); 62} 63return "noNet"; // 自定义错误信息 64}
我们看到,我们将Http访问进行了简单的封装。在客户端使用的时候我们就只需要简单的几行代码即可:
1 List< String> params = new ArrayList< > (); 2 params.add("access_token:" + getAccessToken()); 3 //开始用户更新信息 4 ThreadPoolUtils.execute(new HttpPostThread(userhand, APIAdress.UserClass, APIAdress.GetUserInfoMethod, params));
我们看到,我们创建了一个Runable实例,然后传递了回调的Handler、Url、Method及参数。
推荐阅读
- Android的ListView弹动效果
- Android事件分发机制
- android WebView详解,常见漏洞详解和安全源码
- 计算机体系结构和计算机组织之间的差异
- 打印有趣图案的程序示例
- 使用就地排序算法对对象进行排序
- 密码学中的生日攻击详细介绍
- 亚马逊面试-SDE 1面试体验
- 使用递归从中间顺序到左右顺序遍历链表