引言

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

实现思路及实现

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

 public class ThreadPoolUtils {

     private ThreadPoolUtils() {}
//核心线程数
private static int CORE_POOL_SIZE = 8;
//最大线程数
private static int MAX_POOL_SIZE = 64;
//线程池中超过corePoolSize数目的空闲线程最大存活时间;可以allowCoreThreadTimeOut(true)使得核心线程有效时间
private static int KEEP_ALIVE_TIME = 5;
//任务队列
private static BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(64); private static ThreadPoolExecutor threadpool; static {
threadpool = new ThreadPoolExecutor(CORE_POOL_SIZE, MAX_POOL_SIZE, KEEP_ALIVE_TIME, TimeUnit.SECONDS, workQueue);
} public static void execute(Runnable runnable) {
threadpool.execute(runnable);
}
}

  我们来看一下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对象,然后扔进线程池进行执行。我们来看一下封装的逻辑:

 /**
* post线程
*/
public class HttpPostThread implements Runnable { private Handler hand;
private String strURL;
private String method;
private List<String> params;
private Handler netHand; public HttpPostThread(Handler hand, String strURL, String method, List<String> params) {
this.hand = hand;
//实际的传值
this.strURL = strURL;
this.method = method;
this.params = params;
} public HttpPostThread(Handler hand, Handler netHand, String strURL, String method, List<String> params) {
this.hand = hand;
//实际的传值
this.strURL = strURL;
this.method = method;
this.params = params;
this.netHand = netHand;
} @Override
public void run() {
Message msg = hand.obtainMessage();
try {
String result;
if(!strURL.startsWith("https")) {
RpcHttp rpcHttp = new RpcHttp();
result = rpcHttp.post(strURL, method, params);
}
else {
RpcHttps rpcHttps = new RpcHttps();
result = rpcHttps.post(strURL, method, params);
}
/**
* 根据访问http来设置标识位
* 然后发送msg到handlerMessage进行处理(此处配合Handler进行使用)
*/
if (result.equals("noNet")) {
if (netHand != null) {
netHand.sendEmptyMessage(600);
}
} else {
msg.what = 200;
msg.obj = result;
}
} catch(Exception e){
e.printStackTrace();
}
finally {
hand.sendMessage(msg);
}
}
}

  我们看到,我们封装的这个类的构造函数只需要使用者提供回调的Handler、Http访问的Url、访问的方法及参数。这样就可以将其放入线程中进行处理,然后我们只需要在客户端使用写好回调的Handler即可。我们看34-40行,这时候我们看到会使用封装的Http类去进行网络访问,我们来看一下:

  /**
* post请求
*
* @param strURL 请求的地址
* @param method 请求方法
* @param params 请求元素
* @return
*/
public String post(String strURL, String method, List<String> params) {
Log.e("开始请求","获取请求");
String RequestParams = "";
long timestamp = System.currentTimeMillis();
RequestParams += "{\"method\":\"" + method + "\"";
if (params != null && params.size() > 0) {
RequestParams += ",\"params\":{";
for (String item : params) {
String first = item.substring(0, item.indexOf(":"));
String second = item.substring(item.indexOf(":") + 1);
RequestParams += "\"" + first + "\":\"" + second + "\",";
} RequestParams = RequestParams.substring(0, (RequestParams.length() - 1));
RequestParams += "}";
} else {
RequestParams += ",\"params\":{}";
}
RequestParams += ",\"id\":\"" + timestamp + "\"";
RequestParams += "}";
return this.post(strURL, RequestParams);
} private String post(String strURL, String params) {
try {
URL url = new URL(strURL);// 创建连接
HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setDoOutput(true);
connection.setDoInput(true);
connection.setUseCaches(false);
connection.setInstanceFollowRedirects(true);
connection.setRequestMethod("POST"); // 设置请求方式
connection.setRequestProperty("Accept", "application/json"); // 设置接收数据的格式
connection.setRequestProperty("Content-Type", "application/json"); // 设置发送数据的格式
connection.setConnectTimeout(10000);//设置超时
connection.setReadTimeout(10000);//设置超时
Log.e("开始连接","开始连接");
connection.connect(); OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream(), "UTF-8"); // utf-8编码
out.append(params);
out.flush();
out.close(); String result = convertStreamToString(connection.getInputStream());
Log.e("responseContent",result);
return result;
} catch (Exception e) {
Log.e("responseException",String.valueOf(e.getStackTrace()));
Log.e("responseException",String.valueOf(e.getLocalizedMessage()));
Log.e("responseException",String.valueOf(e.getMessage()));
e.printStackTrace();
}
return "noNet"; // 自定义错误信息
}

  我们看到,我们将Http访问进行了简单的封装。在客户端使用的时候我们就只需要简单的几行代码即可:

 List<String> params = new ArrayList<>();
params.add("access_token:" + getAccessToken());
//开始用户更新信息
ThreadPoolUtils.execute(new HttpPostThread(userhand, APIAdress.UserClass, APIAdress.GetUserInfoMethod, params));

  我们看到,我们创建了一个Runable实例,然后传递了回调的Handler、Url、Method及参数。

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

  1. Python网络爬虫之cookie处理、验证码识别、代理ip、基于线程池的数据爬去

    本文概要 session处理cookie proxies参数设置请求代理ip 基于线程池的数据爬取 引入 有些时候,我们在使用爬虫程序去爬取一些用户相关信息的数据(爬取张三“人人网”个人主页数据)时, ...

  2. Android开发之线程池使用总结

    线程池算是Android开发中非常常用的一个东西了,只要涉及到线程的地方,大多数情况下都会涉及到线程池.Android开发中线程池的使用和Java中线程池的使用基本一致.那么今天我想来总结一下Andr ...

  3. requests模块session处理cookie 与基于线程池的数据爬取

    引入 有些时候,我们在使用爬虫程序去爬取一些用户相关信息的数据(爬取张三“人人网”个人主页数据)时,如果使用之前requests模块常规操作时,往往达不到我们想要的目的,例如: #!/usr/bin/ ...

  4. Android中的线程池概述

    线程池 Android里面,耗时的网络操作,都会开子线程,在程序里面直接开过多的线程会消耗过多的资源,在众多的开源框架中也总能看到线程池的踪影,所以线程池是必须要会把握的一个知识点; 线程运行机制 开 ...

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

    了解线程池 在http://blog.csdn.net/ns_code/article/details/14105457(读书笔记一:TCP Socket)这篇博文中,服务器端采用的实现方式是:一个客 ...

  6. android中的线程池学习笔记

    阅读书籍: Android开发艺术探索 Android开发进阶从小工到专家 对线程池原理的简单理解: 创建多个线程并且进行管理,提交的任务会被线程池指派给其中的线程进行执行,通过线程池的统一调度和管理 ...

  7. 设计模式:基于线程池的并发Visitor模式

    1.前言 第二篇设计模式的文章我们谈谈Visitor模式. 当然,不是简单的列个的demo,我们以电商网站中的购物车功能为背景,使用线程池实现并发的Visitor模式,并聊聊其中的几个关键点. 一,基 ...

  8. 基于线程池的多线程售票demo2.0(原创)

    继上回基于线程池的多线程售票demo,具体链接: http://www.cnblogs.com/xifenglou/p/8807323.html以上算是单机版的实现,特别使用了redis 实现分布式锁 ...

  9. Android下基于PCM的音频渲染

    环境准备 请按照我之前的文章-Android下基于SDL的位图渲染,安装必要的开发环境. 实践篇 这里主要参考Beginning SDL 2.0(6) 音频渲染及wav播放,只不过将源从WAV文件改成 ...

随机推荐

  1. OGG日常运维监控的自动化脚本模板

    #!/usr/bin/ksh export ORACLE_BASE=/oracle/ export ORACLE_SID=epmln1 export ORACLE_HOSTNAME=pmlnpdb1 ...

  2. sencha touch 在安卓中横屏、竖屏切换 应用崩溃问题

    答案来至于 Sencha Touch 交流 @周旭 这是由于横竖屏转换导致activity重跑onCreate方法导致的,有两种解决方案:1.横竖屏转换的时候不要重新跑onCreate方法,这个可以在 ...

  3. 安装Windows Server 2012 R2提示"unable to create a new system partition or locate an existing system partition"解决方法

    重新安装Windows Server 2012 R2,把原来SSD分区全部格式化重建,用U盘启动安装时提示如下: "Setup was unable to create a new syst ...

  4. 为Docker容器中运行的gitlab添加ssh的一些问题记录

    最近做的一个东西,是将gitlab10.x的汉化版本,从源码编译(在源码中自己定制一些东西),然后制作成Docker镜像,作为Docker容器来运行 在启用容器中的gitlab的ssh的时候,遇到了一 ...

  5. tomcat如何配置context的docBase

    docbase是web应用和本地路径,path是tomcat访问这个应用的URL路径.Tomcat的项目部署方式有以下三种:1.直接把项目复制到Tomcat安装目录的webapps目录中,这是最简单的 ...

  6. python偏函数的运用

    摘要:python的设计核心原则就是简洁——在这种原则的指导下,诞生了lambda表达式和偏函数:二者都让函数调用变得简洁.本文主要为你介绍偏函数的应用. 1.为什么要使用偏函数 如果我们定义了一个函 ...

  7. Spark2 Dataset持久化存储级别StorageLevel

    import org.apache.spark.storage.StorageLevel // 数据持久缓存到内存中//data.cache()data.persist() // 设置缓存级别data ...

  8. win10中强制vs2015使用管理员启动

    文章转自: win10中强制vs2015使用管理员启动   首先,和网上流传的版本一样,需要做这下面这两步: 1. 打开VS快捷方式的属性对话框.   2.勾选“用管理员身份运行”   现在,你双击V ...

  9. (转载)准确率(accuracy),精确率(Precision),召回率(Recall)和综合评价指标(F1-Measure )-绝对让你完全搞懂这些概念

    自然语言处理(ML),机器学习(NLP),信息检索(IR)等领域,评估(evaluation)是一个必要的工作,而其评价指标往往有如下几点:准确率(accuracy),精确率(Precision),召 ...

  10. iOS多线程编程之创建线程(转载)

    一.创建和启动线程简单说明 一个NSThread对象就代表一条线程 (1)创建.启动线程 NSThread *thread = [[NSThread alloc] initWithTarget:sel ...