服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Android - andriod如何搭建自己的轮询框架

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

2022-09-09 15:19hankinghu Android

很多时候Android应用需要每间隔一段时间向服务器请求数据,如果服务器数据有更新则通知界面变化。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 用于每次轮询时向请求服务器接口数据。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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是一个线程池控制类。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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()来开启一个服务。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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中的方法,代码如下:

?
1
2
3
4
5
6
7
@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的生成位置:

?
1
2
3
4
5
6
7
8
9
@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 的代码如下

?
1
2
3
4
5
6
7
8
9
10
11
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具有服务的特性因此特别适合后台轮询访问服务器数据。

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

原文链接:https://juejin.im/post/5c2e0e1ae51d454671452864

延伸 · 阅读

精彩推荐