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

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

}

}

复制代码

代码分析

先给出类图之间的关系如下:0a810d8b265c9cd84e5012f86307786d.png

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

更改

经过评论区的提醒,又测试了几遍发现每次轮询确实都会新建和销毁IntentService,这样就没有利用到消息队列,所以重写了一个PollingIntentService类继承Service,使得每次使用时不会重写创建Service,达到复用的效果。同时增加了enterPollingQueue()方法,可以直接往PollingIntentService的队列中增加轮询的Intent消息。

PollingIntentService代码

* Created time 11:40.

*

* @author huhanjun

* @since 2019/1/7

*/

public abstract class PollingIntentService extends Service{

private volatile Looper mServiceLooper;

private volatile ServiceHandler mServiceHandler;

private String mName;

private boolean mRedelivery;

private final class ServiceHandler extends Handler{

public ServiceHandler(Looper looper){

super(looper);

}

@Override

public void handleMessage(Message msg){

onHandleIntent((Intent) msg.obj);

}

}

public PollingIntentService(String name){

super();

mName = name;

}

@Override

public void onCreate(){

super.onCreate();

Log.d(TAG, "onCreate");

HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");

thread.start();

mServiceLooper = thread.getLooper();

mServiceHandler = new ServiceHandler(mServiceLooper);

}

//进入轮询队列

public void enterPollingQueue(@Nullable Intent intent, int startId){

Log.d(TAG, "enterPollingQueue");

Message msg = mServiceHandler.obtainMessage();

msg.arg1 = startId;

msg.obj = intent;

mServiceHandler.sendMessage(msg);

}

@Override

public int onStartCommand(@Nullable Intent intent, int flags, int startId){

Log.d(TAG, "onStartCommand");

enterPollingQueue(intent, startId);

return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;

}

//停止服务

public void onStopService(){

stopSelf();

}

@Override

public void onDestroy(){

mServiceLooper.quit();

Log.d(TAG, "onDestroy");

}

@Override

@Nullable

public IBinder onBind(Intent intent){

return null;

}

@WorkerThread

protected abstract void onHandleIntent(@Nullable Intent intent);

}

复制代码

PollingIntentService 继承Service,在ServiceHandler 的handleMessage方法执行后并不执行stopSelf方法,而是专门提供了onStopService方法来停止整个Service。另外暴露出enterPollingQueue方法,可以直接通过这个方法往轮询队列中加入轮询消息。

使用: 只需将

PollingService extends IntentService{

}

复制代码

改为

PollingService extends PollingIntentService{

}

复制代码

轮询框架重构

根据评论区的反馈,我将会使用WorkManager对轮询框架进行重构,重构文章链接:juejin.im/post/684490…

我的scdn

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值