欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

andriod如何搭建自己的轮询框架

程序员文章站 2022-03-23 13:49:07
很多时候android应用需要每间隔一段时间向服务器请求数据,如果服务器数据有更新则通知界面变化。android中最常用的红点一般采用的就是轮询,红点是为了在数据有更新时及...

很多时候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机制,如下图,维护一个消息队列,循环的从消息队列中取出消息来执行,轮询框架可以定时的向消息队列中加入消息,然后循环中消息队列中取出消息执行。

andriod如何搭建自己的轮询框架

可以自己实现一个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();
 }
}

代码分析

先给出类图之间的关系如下:

andriod如何搭建自己的轮询框架 

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具有服务的特性因此特别适合后台轮询访问服务器数据。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。