andriod如何搭建自己的轮询框架
很多时候android应用需要每间隔一段时间向服务器请求数据,如果服务器数据有更新则通知界面变化。android中最常用的红点一般采用的就是轮询,红点是为了在数据有更新时及时的提醒用户,比如朋友圈更新,当用户的朋友圈更新时就会显示红点,就是通过移动端不断的向服务器查询朋友圈的更新状态。
相关知识点
在实现轮询框架时会主要会要到下面两个类,会结合轮询框架对这三个类进行讲解,在应用中分析会理解更加深刻。
1、intentservice intentservice是一种特殊的service,继承了service并且是一个抽象类,必须创建它的子类才能用。intentservice可以用于执行后台耗时的任务,当任务执行后会自动停止,intentservice的优先级比一般的线程高,比较适合执行一些优先级高的后台任务。
2、pendingintent pendingintent是延迟的intent,主要用来在某个事件完成后执行特定的action。pendingintent包含了intent及context,所以就算intent所属程序结束,pendingintent依然有效,可以在其他程序中使用。pendingintent一般作为参数传给某个实例,在该实例完成某个操作后自动执行pendingintent上的action,也可以通过pendingintent的send函数手动执行,并可以在send函数中设置onfinished表示send成功后执行的动作。
轮询框架实现
要实现轮询,可以借鉴handler中的looper机制,如下图,维护一个消息队列,循环的从消息队列中取出消息来执行,轮询框架可以定时的向消息队列中加入消息,然后循环中消息队列中取出消息执行。
可以自己实现一个looper,但是intentservice中已经包含了一个looper和一个handlerthread。因此轮询框架中使用intentservice作为循环框架。继承intentservice接口来实现处理消息访问服务器。
pollingservice 用于每次轮询时向请求服务器接口数据。
public class pollingservice extends intentservice { public static final string action_check_circle_update="action_check_circle_update"; public static final long default_min_polling_interval = 60000;//最短轮询间隔1分钟 public pollingservice() { super("pollingservice"); } @override protected void onhandleintent(intent intent) { if (intent == null) return; final string action = intent.getaction(); if (action_check_circle_update.equals(action)) { checkcircleoffriendsupdate();//这个是访问服务器获取朋友圈是否更新 } } }
pollingservice 用来处理接到轮询的消息之后在 onhandleintent(intent intent)
中根据intent所带有的action不同来进行访问服务器不同的接口获取数据。
pollingutil 用于控制轮询服务的开始和结束 使用pollingutil中的startpollingservice来根据action和context生成一个pendingintent,并将pendingintent交给pollingscheduler来处理。pollingscheduler是一个线程池控制类。
public class pollingutil { /** * 开始轮询服务 */ public static void startpollingservice(final context context, string action) { //包装需要执行service的intent intent intent = new intent(context, pollingservice.class); intent.setaction(action); pendingintent pendingintent = pendingintent.getservice(context, 0, intent, pendingintent.flag_update_current); pollingscheduler.getinstance().addscheduletask(pendingintent, 0, pollingservice.default_min_polling_interval); } } /** * 停止轮询服务 * * @param context */ public static void stoppollingservices(context context, string action) { pollingscheduler.getinstance().clearscheduletasks(); } }
pollingscheduler实现定时向intentservice的looper中加入消息 pollingscheduler中生成一个单线程池,addscheduletask中定时的执行pendingintent.send(),其中pendingintent是由 pendingintent pendingintent = pendingintent.getservice(context, 0,intent, pendingintent.flag_update_current);
生成的,pendingintent.send()函数会调用service.startservice()来开启一个服务。
public class pollingscheduler { private static pollingscheduler sinstance; private scheduledexecutorservice mscheduler; private pollingscheduler() { mscheduler = executors.newsinglethreadscheduledexecutor(); } public static synchronized pollingscheduler getinstance() { if (sinstance == null) { sinstance = new pollingscheduler(); } if (sinstance.mscheduler.isshutdown()) { sinstance.mscheduler = executors.newsinglethreadscheduledexecutor(); } return sinstance; } public void addscheduletask(final pendingintent pendingintent, long initialdelay, long period) { runnable command = new runnable() { @override public void run() { try { pendingintent.send(); } catch (pendingintent.canceledexception e) { e.printstacktrace(); } } }; mscheduler.scheduleatfixedrate(command, initialdelay, period, timeunit.milliseconds); } public void clearscheduletasks() { mscheduler.shutdownnow(); } }
代码分析
先给出类图之间的关系如下:
pollingservice继承了intentservice,并且在pollingutil的startpollingservice方法中通过 intent intent = new intent(context, pollingservice.class);
和将pendingintent 与pollingservice关联起来,并将pendingintent加入到定时执行的线程池中,在pollingscheduler 中使用 pendingintent.send();
由于pendingintent与pollingservice关联,所以执行pendingintent.send()的时候会调用pollingintentservide中的onstart()方法。onstart()方法是intentservice中的方法,代码如下:
@override public void onstart(@nullable intent intent, int startid) { message msg = mservicehandler.obtainmessage(); msg.arg1 = startid; msg.obj = intent; mservicehandler.sendmessage(msg); }
在onstart()中有一个 mservicehandler.sendmessage(msg);
,找到mservicehandler的生成位置:
@override public void oncreate() { super.oncreate(); handlerthread thread = new handlerthread("intentservice[" + mname + "]"); thread.start(); mservicelooper = thread.getlooper(); mservicehandler = new servicehandler(mservicelooper); }
在intentservice的oncreate方法中生成了一个handlerthread,一个mservicelooper,一个mservicehandler,其中mservicehandler.sendmessage(msg)中的msg都会放到mservicelooper,执行时从mservicelooper中取出执行,其中servicehandler 的代码如下
private final class servicehandler extends handler { public servicehandler(looper looper) { super(looper); } @override public void handlemessage(message msg) { onhandleintent((intent)msg.obj); stopself(msg.arg1); } }
handlemessage(message msg)中会调用onhandleintent((intent)msg.obj);方法,也就是在pollingservice中重写的onhandleintent方法。 因此我们在addscheduletask中不断的执行pending.send()方法,会不断的调用intentservice中的onstart方法中的mservicehandler.sendmessage(msg);不断的向消息队列中发消息,然后在onhandleintent处理消息。 这样一个轮询框架就完成了。
总结
本文的轮询框架利用了intentservice中的handler和looper机制来实现循环的处理消息,由于intentservice具有服务的特性因此特别适合后台轮询访问服务器数据。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
推荐阅读
-
如何获取公网ip,自己搭建公网ip服务器的方法
-
零成本免开发,企业如何快速搭建自己的移动BI轻应用
-
如何搭建一个功能复杂的前端配置化框架(一)
-
如何搭建新的WPF项目框架
-
【从零开始搭建自己的.NET Core Api框架】(三)集成轻量级ORM——SqlSugar:3.3 自动生成实体类
-
理解vue ssr原理并自己搭建简单的ssr框架
-
新手和企业如何一步步搭建自己的网站?
-
互联网商业时代,如何免费智能搭建自己的网站!
-
如何建立一个自己的网站?不懂代码搭建自己网站详细教程
-
从零开始搭建前后端分离的NetCore2.2(EF Core CodeFirst+Autofac)+Vue的项目框架之九如何进行用户权限控制