Android下基于线程池的网络访问基础框架

Posted dreamGong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android下基于线程池的网络访问基础框架相关的知识,希望对你有一定的参考价值。

引言

  现在的android开发很多都使用Volley、OkHttp、Retrofit等框架,这些框架固然有优秀的地方(以后会写代码学习分享),但是我们今天介绍一种基于Java线程池的网络访问框架。

实现思路及实现

  APP界面上面的数据都是通过网络请求获取的,我们能不能将网络请求依次入队,然后配合着Java线程池,让线程依次处理我们的请求,最后返回结果给我们。下面我们先来看一下线程池工具类的实现:

 1 public class ThreadPoolUtils {
 2 
 3     private ThreadPoolUtils() {}
 4     //核心线程数
 5     private static int CORE_POOL_SIZE = 8;
 6     //最大线程数
 7     private static int MAX_POOL_SIZE = 64;
 8     //线程池中超过corePoolSize数目的空闲线程最大存活时间;可以allowCoreThreadTimeOut(true)使得核心线程有效时间
 9     private static int KEEP_ALIVE_TIME = 5;
10     //任务队列
11     private static BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(64);
12 
13     private static ThreadPoolExecutor threadpool;
14 
15     static {
16         threadpool = new ThreadPoolExecutor(CORE_POOL_SIZE, MAX_POOL_SIZE, KEEP_ALIVE_TIME, TimeUnit.SECONDS, workQueue);
17     }
18 
19     public static void execute(Runnable runnable) {
20         threadpool.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 
 6     private Handler hand;
 7     private String strURL;
 8     private String method;
 9     private List<String> params;
10     private Handler netHand;
11 
12     public HttpPostThread(Handler hand, String strURL, String method, List<String> params) {
13         this.hand = hand;
14         //实际的传值
15         this.strURL = strURL;
16         this.method = method;
17         this.params = params;
18     }
19 
20     public HttpPostThread(Handler hand, Handler netHand, String strURL, String method, List<String> params) {
21         this.hand = hand;
22         //实际的传值
23         this.strURL = strURL;
24         this.method = method;
25         this.params = params;
26         this.netHand = netHand;
27     }
28 
29     @Override
30     public void run() {
31         Message msg = hand.obtainMessage();
32         try {
33             String result;
34             if(!strURL.startsWith("https")) {
35                 RpcHttp rpcHttp = new RpcHttp();
36                 result = rpcHttp.post(strURL, method, params);
37             }
38             else {
39                 RpcHttps rpcHttps = new RpcHttps();
40                 result = rpcHttps.post(strURL, method, params);
41             }
42             /**
43              * 根据访问http来设置标识位
44              * 然后发送msg到handlerMessage进行处理(此处配合Handler进行使用)
45              */
46             if (result.equals("noNet")) {
47                 if (netHand != null) {
48                     netHand.sendEmptyMessage(600);
49                 }
50             } else {
51                 msg.what = 200;
52                 msg.obj = result;
53             }
54         } catch(Exception e){
55             e.printStackTrace();
56         }
57         finally {
58             hand.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      */
 9     public String post(String strURL, String method, List<String> params) {
10         Log.e("开始请求","获取请求");
11         String RequestParams = "";
12         long timestamp = System.currentTimeMillis();
13         RequestParams += "{\"method\":\"" + method + "\"";
14         if (params != null && params.size() > 0) {
15             RequestParams += ",\"params\":{";
16             for (String item : params) {
17                 String first = item.substring(0, item.indexOf(":"));
18                 String second = item.substring(item.indexOf(":") + 1);
19                 RequestParams += "\"" + first + "\":\"" + second + "\",";
20             }
21 
22             RequestParams = RequestParams.substring(0, (RequestParams.length() - 1));
23             RequestParams += "}";
24         } else {
25             RequestParams += ",\"params\":{}";
26         }
27         RequestParams += ",\"id\":\"" + timestamp + "\"";
28         RequestParams += "}";
29         return this.post(strURL, RequestParams);
30     }
31 
32     private String post(String strURL, String params) {
33         try {
34             URL url = new URL(strURL);// 创建连接
35             HttpURLConnection connection = (HttpURLConnection) url.openConnection();
36 
37             connection.setDoOutput(true);
38             connection.setDoInput(true);
39             connection.setUseCaches(false);
40             connection.setInstanceFollowRedirects(true);
41             connection.setRequestMethod("POST"); // 设置请求方式
42             connection.setRequestProperty("Accept", "application/json"); // 设置接收数据的格式
43             connection.setRequestProperty("Content-Type", "application/json"); // 设置发送数据的格式
44             connection.setConnectTimeout(10000);//设置超时
45             connection.setReadTimeout(10000);//设置超时
46             Log.e("开始连接","开始连接");
47             connection.connect();
48 
49             OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream(), "UTF-8"); // utf-8编码
50             out.append(params);
51             out.flush();
52             out.close();
53 
54             String result = convertStreamToString(connection.getInputStream());
55             Log.e("responseContent",result);
56             return result;
57         } catch (Exception e) {
58             Log.e("responseException",String.valueOf(e.getStackTrace()));
59             Log.e("responseException",String.valueOf(e.getLocalizedMessage()));
60             Log.e("responseException",String.valueOf(e.getMessage()));
61             e.printStackTrace();
62         }
63         return "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下基于线程池的网络访问基础框架的主要内容,如果未能解决你的问题,请参考以下文章

android开源框架之 andbase

Android3.0以后,Asynctask在没开线程池的情况下会怎么排队执行

基于Retrofit+RxJava的Android分层网络请求框架

Binder线程池的启动流程分析

Binder线程池的启动流程分析

线程池的用法及思考