摘要:使用线程池可以带来个好处降低资源消耗通过重用已经创建的线程来降低线程创建和销毁的消耗提高响应速度任务到达时不需要等待线程创建就可以立即执行。提高线程的可管理性线程池可以统一管理分配调优和监控。
用户在调用层(Activity或Service中),发起一个网络请求,该请求肯定包含url,请求参数(requestParameter),以及我们需要给调用层提供一个请求成功或失败以后回调监听的接口dataListener(这一点与Volley类似)。
在框架层,每一次用户请求可以看做一个Http任务,这些任务我们可以用一个请求队列存储起来,框架工作时不断地从请求队列中取出任务放到处理中心中,处理中心是一个线程池ThreadPool。使用线程池可以带来3个好处:
1.降低资源消耗:通过重用已经创建的线程来降低线程创建和销毁的消耗
2.提高响应速度:任务到达时不需要等待线程创建就可以立即执行。
3.提高线程的可管理性:线程池可以统一管理、分配、调优和监控。
由于用户请求的数量是不确定的,所以请求队列的长度应该没有限制,所以这里的数据结构,我们应该使用链表。正好,java给我们提供了一个阻塞式队列LinkedBlockingQueue,它是一个单向链表实现的无界阻塞队列,先进先出,支持多线程并发操作。
再仔细考虑一下框架层的操作,用户不断发请求产生HttpTask,处理中心不断从请求队列中去任务,这和那个生产者消费者模式是不是很像?所以我们还需要考虑并发和同步问题,而LinkedBlockingQueue是线程安全的,实现了先进先出等特性,是作为生产者消费者的首选。LinkedBlockingQueue 可以指定队列的容量,也可以不指定,不指定的话,默认最大是Integer.MAX_VALUE,其中主要用到put和take方法,put方法在队列满的时候会阻塞直到有队列成员被消费,take方法在队列空的时候会阻塞,直到有队列成员被放进来。
至于处理中心的线程池,我们使用jdk里的ThreadPoolExecutor,具体用法可以自行百度,唯一需要注意的就是其中的拒绝策略。
代码编写首先,我们需要一个线程池的管理类,来管理请求队列和处理中心处理任务。由于系统中仅有一个线程池管理的类,所以该类应该设计成单例模式
ThreadPoolManager.java
import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.RejectedExecutionHandler; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; /** 1. 线程池管理类 */ public class ThreadPoolManager { //1.将请求任务放到请求队列中 //通过阻塞式队列来存储任务 private LinkedBlockingQueuequeue = new LinkedBlockingQueue<>(); //添加任务 public void execute( Runnable runnable ){ if( runnable != null ) { try { queue.put(runnable); } catch (InterruptedException e) { e.printStackTrace(); } } } //2.把队列中的任务放到线程池 private ThreadPoolExecutor threadPoolExecutor ; private ThreadPoolManager(){ threadPoolExecutor = new ThreadPoolExecutor(4,20,15, TimeUnit.SECONDS,new ArrayBlockingQueue (4),rejectedExecutionHandler); //运行线程池 threadPoolExecutor.execute(runnable); } //当线程数超过maxPoolSize或者keep-alive时间超时时执行拒绝策略 private RejectedExecutionHandler rejectedExecutionHandler = new RejectedExecutionHandler() { /** * @param runnable 超时被线程池抛弃的线程 * @param threadPoolExecutor */ @Override public void rejectedExecution(Runnable runnable, ThreadPoolExecutor threadPoolExecutor) { //将该线程重新放入请求队列中 try { queue.put(runnable); } catch (InterruptedException e) { e.printStackTrace(); } } }; //3.让他们开始工作起来 //整个的工作线程 private Runnable runnable = new Runnable() { @Override public void run() { while(true){ Runnable runnable = null ; //不断从从请求队列中取出请求 try { runnable = queue.take(); } catch (InterruptedException e) { e.printStackTrace(); } //如果不为空,放入线程池中执行 if( runnable != null ){ threadPoolExecutor.execute(runnable); } } } }; //单例模式 private static ThreadPoolManager singleInstance = new ThreadPoolManager(); public static ThreadPoolManager getSingleIntance(){ return singleInstance; } }
接下来我们需要将写两个接口将用户的网络访问操作分成两部分(参考架构图),一个是请求(IHttpRequest),一个是响应(IHttpListener),
在请求接口中,我们需要做的事有三个
IHttpRequest.java
/** * 封装请求 */ public interface IHttpRequest { void setUrl(String url); void setRequestData( byte[] requestData ); void execute(); //需要设置请求和响应两个接口之间的关系 void setHttpCallBack( IHttpListener httpListener ); }
在响应接口中,我们需要做的事也很简单
IHttpListener.java
import java.io.InputStream; /** * 封装响应 */ public interface IHttpListener { //接受上一个接口的结果 void onSuccess(InputStream inputStream); void onFailure(); }
接下来我们编写代表请求任务的类HttpTask,让它实现Runnable接口,并且维护IHttpRequest和IHttpListener两个接口的引用,在HttpTask的构造方法中,进行一些初始化操作,设置请求的url,请求参数,设置监听器等等。在将请求参数对象转换成字符串的过程中,我们使用了阿里的fastjson这个jar包。最后在run方法中,执行httpRequest的请求。另外注意这里泛型的使用。
HttpTask.java
import com.alibaba.fastjson.JSON; import java.io.UnsupportedEncodingException; public class HttpTaskimplements Runnable { private IHttpRequest httpRequest; private IHttpListener httpListener; public HttpTask( T requestInfo , String url , IHttpRequest httpRequest, IHttpListener httpListener){ this.httpRequest = httpRequest; this.httpListener = httpListener; //设置url this.httpRequest.setUrl(url); //设置响应回调 this.httpRequest.setHttpCallBack(httpListener); //设置请求参数 if( requestInfo != null ){ //将用户发送的请求参数对象转换成字符串 String requestContent = JSON.toJSONString(requestInfo); //字符串转byte数组 try { this.httpRequest.setRequestData(requestContent.getBytes("utf-8")); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } } @Override public void run() { httpRequest.execute(); } }
接下来我们编写IHttpRequest的实现类,JsonHttpRequest , 在重写的execute方法中,使用原生的HttpURLConnection执行网络请求,请求成功后,回调IHttpListener的onSuccess方法。
如果想要传送其他数据(图片,文件等),同样实现IHttpRequest该接口即可,所以这个框架的扩展性十分良好。
JsonHttpRequest.java
import java.io.BufferedOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; /** * Json版Http请求 */ public class JsonHttpRequest implements IHttpRequest{ private String url ; private byte[] requestData ; private IHttpListener httpListener; @Override public void setUrl(String url) { this.url = url ; } @Override public void setRequestData(byte[] requestData) { this.requestData = requestData; } //原生的网络操作在这里实现 @Override public void execute() { httpUrlconnPost(); } private HttpURLConnection urlConnection = null ; public void httpUrlconnPost(){ URL url = null; try{ url = new URL(this.url); //打开http连接 urlConnection = (HttpURLConnection) url.openConnection(); //设置连接的超时时间 urlConnection.setConnectTimeout(6000); //不使用缓存 urlConnection.setUseCaches(false); urlConnection.setInstanceFollowRedirects(true); //响应的超时时间 urlConnection.setReadTimeout(3000); //设置这个连接是否可以写入数据 urlConnection.setDoInput(true); //设置这个连接是否可以输出数据 urlConnection.setDoOutput(true); //设置请求的方式 urlConnection.setRequestMethod("POST"); urlConnection.setRequestProperty("Content-Type", "application/json;charset=UTF-8"); urlConnection.connect(); //使用字节流发送数据 OutputStream out = urlConnection.getOutputStream(); BufferedOutputStream bos = new BufferedOutputStream(out); if( requestData != null ){ //把字节数组的数据写入缓冲区 bos.write(requestData); } //刷新缓冲区,发送数据 bos.flush(); out.close(); bos.close(); //获得服务器响应 if( urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK){ InputStream in = urlConnection.getInputStream(); //回调监听器的listener方法 httpListener.onSuccess(in); } }catch ( Exception e){ e.printStackTrace(); } } @Override public void setHttpCallBack(IHttpListener httpListener) { this.httpListener = httpListener; } }
接下来是IHttpListener的Json版本实现类,在该类中要注意的事就是回调结果给用户时要进行线程的切换(使用Handler),并且要将返回的json字符串转换成泛型对象(该对象由用户自定义)。
JsonHttpListener.java
import android.os.Handler; import android.os.Looper; import com.alibaba.fastjson.JSON; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; /** * Json版本的httpListener */ public class JsonHttpListenerimplements IHttpListener{ Class responseClass; private IDataListener dataListener; public JsonHttpListener(Class responseClass, IDataListener dataListener) { this.responseClass = responseClass; this.dataListener = dataListener; } //用于切换线程 Handler handler = new Handler(Looper.getMainLooper()); @Override public void onSuccess(InputStream inputStream) { //获取响应结果,把byte数据转换成String数据 String content = getContent(inputStream); //将json字符串转换成对象 final M response = JSON.parseObject(content,responseClass); //把结果传送到调用层 handler.post(new Runnable() { @Override public void run() { if( dataListener != null ){ dataListener.onSuccess(response); } } }); } @Override public void onFailure() { handler.post(new Runnable() { @Override public void run() { if( dataListener != null ){ dataListener.onFailure(); } } }); } /** * 将流转换成字符串 * @param inputStream * @return */ private String getContent(InputStream inputStream){ String content = null ; BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); StringBuilder sb = new StringBuilder(); String line = null ; try{ while( (line = reader.readLine()) != null){ sb.append(line + "n"); } }catch ( IOException e ){ e.printStackTrace(); }finally { try { inputStream.close(); reader.close(); } catch (IOException e) { e.printStackTrace(); } } return sb.toString(); } }
最后两步
这样我们框架的封装性会更好。
IDataListener.java
/** * 回调调用层的接口,数据返回的统一接口 */ public interface IDataListener{ void onSuccess( M m ); void onFailure(); }
Volley.java
/** * 用户请求的统一接口 */ public class Volley { public staticvoid sendJsonRequest( T requestInfo , String url , Class response , IDataListener dataListener){ IHttpRequest httpRequest = new JsonHttpRequest(); IHttpListener httpListener = new JsonHttpListener<>(response,dataListener); HttpTask httpTask = new HttpTask (requestInfo,url,httpRequest,httpListener); ThreadPoolManager.getSingleIntance().execute(httpTask); } }
最后在MainActivity中测试
public void onClick(View view) { //Student为自己定义的javaBean Volley.sendJsonRequest(null, url, Student.class, new IDataListener() { @Override public void onSuccess(Student student) { Toast.makeText(MainActivity.this,student.getName(),Toast.LENGTH_SHORT).show(); } @Override public void onFailure() { Toast.makeText(MainActivity.this,"请求失败",Toast.LENGTH_SHORT).show(); } }); }
想要拓展更多的功能,请求更多类型的数据,我们只需要实现IHttpRequest和IHttpListener这两个接口就行了。
参考:https://www.jianshu.com/p/396ada3885cc
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/3049.html
摘要:生命周期生命周期启动方式有两种,一种是通过方式进行启动,另一种是通过方式进行启动。这种注册方式优先级较高。虚拟机运行的是字节码。一共有三种类型,分别是和。 1、Activity生命周期? onCreate() -> onStart() -> onResume() -> onPause() -> onStop() -> onDetroy() 2、Service生命周期? service ...
摘要:生命周期生命周期启动方式有两种,一种是通过方式进行启动,另一种是通过方式进行启动。这种注册方式优先级较高。虚拟机运行的是字节码。一共有三种类型,分别是和。 1、Activity生命周期? onCreate() -> onStart() -> onResume() -> onPause() -> onStop() -> onDetroy() 2、Service生命周期? service ...
摘要:下一次的计划,也许是封装的组件,也许是封装个播放器的组件,也可能是封装常用的自定义,视情况而定吧。至于为什么需要二次封装,这篇就不扯了,反正每个组件的封装肯定是来源于有这方面的需求。 本篇文章已授权微信公众号 dasu_Android(大苏)独家发布 前面已经封装了很多常用、基础的组件了:base-module, 包括了: crash 处理 常用工具类 apk 升级处理 log 组件 l...
摘要:若拦截事件返回为,表示拦截,事件不会向下层的或者传递,表示不拦截,继续分发事件。五注册反注册未成对使用引起的内存泄漏。七集合对象没有及时清理引起的内存泄漏。 原文链接:https://blog.csdn.net/wen_hah... 版权声明:本文为博主原创文章,转载请附上博文链接! 前言 金三银四到来了,找工作的好时候到了,小伙伴们是不是都在忙着找工作呢,小弟前一阵也是忙着在找工作,...
摘要:就是使用进行操作。不过设计的初衷本身也就是为频繁的数据量小的网络请求而生。是公司出品的默认基于封装的一套网络请求框架,是目前流行的一套设计的风格,并不是标准。所以这两个库相比,更有优势,在能掌握两个框架的前提下该优先使用。Xutils这个框架非常全面,可以进行网络请求,可以进行图片加载处理,可以数据储存,还可以对view进行注解,使用这个框架非常方便,但是缺点也是非常明显的,使用这个项目,会...
阅读 2755·2021-11-22 09:34
阅读 2229·2021-11-11 11:01
阅读 3021·2021-10-11 10:57
阅读 2362·2021-09-30 09:46
阅读 3557·2021-09-04 16:46
阅读 3307·2021-07-26 23:38
阅读 1417·2019-08-29 12:22
阅读 511·2019-08-29 11:28