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及参数。

时间: 2024-10-11 16:52:14

Android下基于线程池的网络访问基础框架的相关文章

使用Android新式LruCache缓存图片,基于线程池异步加载图片

import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import a

Android开发之线程池使用总结

线程池算是Android开发中非常常用的一个东西了,只要涉及到线程的地方,大多数情况下都会涉及到线程池.Android开发中线程池的使用和Java中线程池的使用基本一致.那么今天我想来总结一下Android开发中线程池的使用. OK,假如说我想做一个新闻应用,ListView上有一个item,每个item上都有一张图片需要从网络上加载,如果不使用线程池,你可能通过下面的方式来开启一个新线程: new Thread(new Runnable() { @Override public void ru

【Java TCP/IP Socket】基于线程池的TCP服务器(含代码)

了解线程池 在http://blog.csdn.net/ns_code/article/details/14105457(读书笔记一:TCP Socket)这篇博文中,服务器端采用的实现方式是:一个客户端对应一个线程.但是,每个新线程都会消耗系统资源:创建一个线程会占用CPU周期,而且每个线程都会建立自己的数据结构(如,栈),也要消耗系统内存,另外,当一个线程阻塞时,JVM将保存其状态,选择另外一个线程运行,并在上下文转换(context switch)时恢复阻塞线程的状态.随着线程数的增加,线

基于线程池的线程调度管控系统

本文将详细描述"基于线程池的线程调度管控系统"的实现原理,以梳理当时的编程思路. 简单叙述一下此线程池的开发背景:客户端是批量运行的,虽然客户端均运行在服务器上,但是大量客户端运行时它们对机器资源是抢占式的,所以客户端在大规模运行时与单次运行时的运行效果是不一样的,因为相同客户端在单次运行与大规模运行时所占有的资源量是不同的,理论上说大规模运行时客户端的数量越多,每个客户端所占有的资源量就越少,于是我们认为解决问题的关键应该是不管是单次运行还是大规模运行,相同客户端所获取的资源量就应该

linux下的线程池

什么时候需要创建线程池呢?简单的说,如果一个应用需要频繁的创建和销毁线程,而任务执行的时间又非常短,这样线程创建和销毁的带来的开销就不容忽视,这时也是线程池该出场的机会了.如果线程创建和销毁时间相比任务执行时间可以忽略不计,则没有必要使用线程池了. 下面是Linux系统下用C语言创建的一个线程池.线程池会维护一个任务链表(每个CThread_worker结构就是一个任务).   pool_init()函数预先创建好max_thread_num个线程,每个线程执thread_routine ()函

基于线程池、消息队列和epoll模型实现Client-Server并发架构

引言 并发是什么?企业在进行产品开发过程中为什么需要考虑这个问题?想象一下天猫的双11和京东的618活动,一秒的点击量就有几十万甚至上百万,这么多请求一下子涌入到服务器,服务器需要对这么多的请求逐个进行消化掉,假如服务器一秒的处理能力就几万,那么剩下的不能及时得到处理的这些请求作何处理?总不能让用户界面一直等着,因此消息队列应运而生,所有的请求都统一放入消息队列,工作线程从消息队列不断的消费,消息队列相当于一个缓冲区,可达到解藕.异步和削峰的目的. Kafka.ActiveMQ.RabbitMQ

一个Linux下C线程池的实现

在传统服务器结构中, 常是 有一个总的 监听线程监听有没有新的用户连接服务器, 每当有一个新的 用户进入, 服务器就开启一个新的线程用户处理这 个用户的数据包.这个线程只服务于这个用户 , 当 用户与服务器端关闭连接以后, 服务器端销毁这个线程.然而频繁地开辟与销毁线程极大地占用了系统的资源.而且在大量用户的情况下, 系统为了开辟和销毁线程将浪费大量的时间和资源.线程池提供了一个解决外部大量用户与服务器有限资源的矛盾, 线程池和传统的一个用户对应一个线程的处理方法不同, 它的基本思想就是在程序

Linux下简单线程池的实现

线程池的技术背景 在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源.在Java中更是如此,虚拟机将试图跟踪每一个对象,以便能够在对象销毁后进行垃圾回收.所以提高服务程序效率的一个手段就是尽可能减少创建和销毁对象的次数,特别是一些很耗资源的对象创建和销毁.如何利用已有对象来服务(不止一个不同的任务)就是一个需要解决的关键问题,其实这就是一些"池化资源"技术产生的原因.比如大家所熟悉的数据库连接池正是遵循这一思想而产生的,本文将介绍的线程池技术同

Android AsyncTask内部线程池异步执行任务机制简要分析

如下分析针对的API 25的AsyncTask的源码: 使用AsyncTask如果是调用execute方法则是同步执行任务,想要异步执行任务可以直接调用executeOnExecutor方法,多数情况下我们会使用AsyncTask内部静态的线程池, THREAD_POOL_EXECUTOR,这里并不是要分析AsyncTask内部的流程,而是简单介绍下线程池的工作流程.可以看到THREAD_POOL_EXECUTOR的配置如下: new ThreadPoolExecutor( CORE_POOL_