android 心跳 简书,PollingTask,一个简单的心跳轮询库

做定时任务对于android可以有好多种实现方式:

1. AlarmManager

利用系统的"闹钟"功能来做定时、心跳,这个服务的优点就是足够精确,同时根据设置不同type类型可以做到锁屏、甚至使用AlarmManager.POWER_OFF_WAKEUP关机的时候还保持心跳(这是真正利用了硬件的计时,一旦到达指定的任务执行时间就会唤醒CPU来执行,不过受限于一些SDK版本的影响,有些版本不支持),这里就不展开详细讲解,下面附上一个封装的小工具,源码:

/**

* 项目名:不告诉你

* 包名: 不告诉你

* 文件名:${}

* 作者: Jerry on 2016/12/7 15:42

* 邮箱:JerryloveEmily@163.com

*/

public class TimeTaskUtil {

private final AlarmManager mAlarManager;

public TimeTaskUtil(Context context) {

mAlarManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);

}

/**

* 开启轮询服务

*

* @param context 上下文

* @param cls service服务对象

* @param requestCode 请求码

* @param intervalSecond 每隔几秒执行一次任务

* @param bundle 轮询服务传递的参数

*/

public void startPollingService(Context context, Class> cls, String action, int requestCode, int intervalSecond, Bundle bundle) {

Intent intent = new Intent(context, cls);

intent.setAction(action);

intent.putExtra("bundle", bundle);

PendingIntent pi = PendingIntent.getService(

context, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT

);

mAlarManager.setRepeating(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime(), intervalSecond * 1000, pi);

}

/**

* 停止轮询服务

*

* @param context 上下文

* @param cls 轮询服务对象

* @param action 任务的action

*/

public void stopPollingService(Context context, Class> cls, int requestCode, String action) {

Intent intent = new Intent(context, cls);

intent.setAction(action);

PendingIntent operationIntent = PendingIntent.getService(

context, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT

);

mAlarManager.cancel(operationIntent);

}

}

以上只是针对AlarmManager和Service之间的任务心跳处理,AlarmManager还可以和Activity、BroadcastReceiver等组件做类似的心跳回调处理,就不一一介绍了和以上工具类似。

2. JDK中的Timer

同样可以用来做轮询心跳,不详述,想必小伙伴们都很熟悉它。

3. 使用Handler来做轮询

进入正题,大家都知道Handler内部维护了一个消息循环队列,不断的处理着我们send过去的消息,我们就可以利用这个机制来实现心跳轮询的效果,不多说直接上源码:

/**

* 项目名:Jerry

* 包名: Jerry

* 文件名:${PollingTask}

* 作者: Jerry on 2016/12/10 09:45

* 邮箱:JerryloveEmily@163.com

*/

public class PollingTask {

private static final String TAG = "PollingTask";

private Handler mHandler;

private InnerTask mInnerTask;

private TaskObserver mTaskObserver;

// 默认心跳时间5秒

private static final int HEART_BEAT_RATE = 5;

private long mHeartBeatRate;

private TaskObservable mObservable;

/**

* 创建任务

* @return ...

*/

public PollingTask createTask(){

createTask(HEART_BEAT_RATE);

return this;

}

/**

* 创建任务

* @param heartBeatRate 心跳时间,单位秒

* @return ...

*/

public PollingTask createTask(int heartBeatRate) {

this.mHeartBeatRate = heartBeatRate * 1000;

mHandler = new Handler();

mInnerTask = new InnerTask(this);

mTaskObserver = new TaskObserver();

mObservable = new TaskObservable();

mObservable.addObserver(mTaskObserver);

return this;

}

/**

* 设置心跳任务时间

* @param heartBeatRate 心跳时间,单位秒

* @return ...

*/

public PollingTask setHearBeatRate(int heartBeatRate){

this.mHeartBeatRate = heartBeatRate * 1000;

return this;

}

/**

* 链接启动任务

* @return ...

*/

public PollingTask connected() {

if (mHandler == null || mInnerTask == null) {

throw new RuntimeException("please call createTask method create polling task!");

}

if (mHeartBeatRate <= 0) {

throw new RuntimeException("please set HeartBeatRate by setHearBeatRate method!");

}

mHandler.removeCallbacks(mInnerTask);

mHandler.post(mInnerTask);

return this;

}

/**

* 通知任务执行完成

*/

public void notifyTaskFinish(){

mObservable.notifyTaskFinish();

}

/**

* 销毁任务

*/

public void destroyTask(){

if (mHandler == null || mInnerTask == null) {

throw new RuntimeException("please call createTask method create polling task!");

}

mHandler.removeCallbacks(mInnerTask);

}

private class InnerTask implements Runnable {

private WeakReference mWeak;

InnerTask(PollingTask wrapper) {

mWeak = new WeakReference<>(wrapper);

}

@Override

public void run() {

PollingTask outClass = mWeak.get();

if (outClass != null) {

if (outClass.mOnTaskListener != null) {

// 开始执行任务

outClass.mOnTaskListener.executeTask(outClass);

}

}

}

}

/**

* 任务观察者

*/

private class TaskObserver implements Observer {

@Override

public void update(Observable observable, Object data) {

// 通过观察者模式,被观察的任务通知了任务轮询观察者,需要去更新开启新的一轮任务的执行,利用handler的postDelayed起到延时心跳的效果

mHandler.postDelayed(mInnerTask, mHeartBeatRate);

}

}

/**

* 被观察的任务

*/

private class TaskObservable extends Observable {

public void notifyTaskFinish() {

// 标识状态或者内容发送改变

setChanged();

// 通知所有的观察者

notifyObservers();

}

}

private OnTaskListener mOnTaskListener;

/**

* 监听任务状态

* @param listener 监听接口

*/

public PollingTask setOnTaskListener(OnTaskListener listener) {

this.mOnTaskListener = listener;

return this;

}

public interface OnTaskListener {

void executeTask(PollingTask pollingTask);

}

}

使用这个库创建一个心跳任务很简单,而且是链式的调用方法:

// 初始化一个心跳任务对象

PollingTask mPushPollingTask = new PollingTask();

// 创建一个60秒为心跳的任务

mPushPollingTask.createTask(60)

.connected()

.setOnTaskListener(new PollingTask.OnTaskListener() {

@Override

public void executeTask(PollingTask pollingTask) {

// 执行一个任务,可以是同步的也可以是异步的

// 比如获取推送的新闻信息

getPushNewsInfos();

}

}

);

/**

* 获取刷新规则的数据信息

*

/

private void getPushNewsInfos() {

mApiWrapper.getPushNewsInfos(url, new ApiWrapper.HttpCallback>() {

@Override

public void success(List data) {

savaNewsInfo(data);

// 关键的一步,一旦一次任务执行完后,调用pollingTask的notifyTaskFinish方法,去通知任务观察者去更新再次发起一个任务的执行,否则轮询就无效,这个好比ListView、RecyclerView的Adatper里的数据刷新机制是一样的

mPushPollingTask .notifyTaskFinish();

}

@Override

public void failure(Exception e) {

mPushPollingTask .notifyTaskFinish();

}

});

}

// 最后需要关闭回收一个心跳任务,只要调用

mPushPollingTask.destroyTask();

总结:主要有两个知识点:

使用handler的循环队列处理机制做到轮询心跳。

利用观察者模式,对具体任务的执行与PollingTask内部的Runnable实现类InnerTask之间的解耦,因为这样不管是什么任务都不要持有handler对象来做循环的任务执行工作。这里把每一个具体的任务看做是一个被观察的对象,一旦任务执行完成,就通知观察者mPollingTask .notifyTaskFinish()。这个机制有点像ListView、RecyclerView的Adatper里的数据刷新notifyDataSetChanged(),下次就来分析分析notifyDataSetChanged的实现原理和机制。

存在的问题:

一个心跳任务就得创建一个PollingTask对象不合适

一个PollingTask对象创建的心跳任务,同时只能处理一个异步任务,如果executeTask方法中执行一个以上的异步任务,就会出现mPollingTask .notifyTaskFinish()这个方法调用时机的问题,因为不同任务执行完成的时间是不一样的。

解决方案:

暂时还没有很明确的方法,简单的思路是重构PollingTask,内部维护一个任务和任务tag的map,同时映射对应一个观察者和被观察者的map,做遍历检查任务是否已经执行完成,同时通知到对应的任务观察者去更新心跳状态。可以参考"AndroidEventBus"这个事件总线库的思路,下次我们就来分析"AndroidEventBus"这个库的实现原理。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值