http://blog.csdn.net/sk719887916/article/details/51398416 skay亲笔

Android开发中经常会用到周期性执行一个动作的需求,大的场景有推送,统计,即时通讯,小的场景有客户端进行一些小范围的计时器,列入有以下场景。

统计:客户端不断轮询去请求服务器某个接口,上报数据等

1. 统计方案见《 Android 优质精准的用户行为和日志打捞方案》

2. 日志抓取见:《Android全局异常处理(可以做强制退出和carsh日志抓取)》

推送:客户端定时去检测服务器有无新的消息,也有采用socket进行长连接主动推,那么这一类我们可以归类到即时通信中

聊天: 客户端和服务端双向采用轮询机制,业内不叫轮询,称之为心跳机制。客户端定时的连接服务器,服务器轮询去检测客户端是否在线,这叫保证了客户端断线时能及时连接到服务器,服务器也能及时在和客户端掉线时更新状态,

不死进程:话说不死进程我们可以用轮询监测某个服务是否存活,但是一般实现不死进程时候不建议采取轮询机制,一般采用三方互相守护来实现。

常有客户端轮询方案有如下:

一 采用Thread+Service方式

 此方式在客户单开启时成功开启一个后台服务,并在服务里启动一个线程,让线程定时去执行应任务,

public class PollService extends Service {

 private Boolean isStart = true;

@Override
public IBinder onBind(Intent intent) {

    new MyThread().start();
    return null;
}

@Override
public void onCreate() {
    System.out.println("oncreate()");

    MyThread thread = new MyThread();
    thread.start();

    super.onCreate();
}

private class MyThread extends Thread {
    @Override
    public void run() {

        while (isStart) {

            try {
                // 每个5秒向服务器发送一次请求
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
       // do something

        }
    }
}

@Override
public void onDestroy() {
    isStart = false;
    super.onDestroy();
}

}

二 采用Handler 进行定时轮询

此方式只采用handler加入到 ThreadLocal中,定时sendMessge和handleMessage,来完成我们的定时功能。

public class StatiPollMgr {
/** 超期消息 */
private static final int MSG_TIMEOUT = 1;
private PaStaticsManagerImpl staticsManagerImpl;
/** 心跳周期 */
private long mCardiacCycle;
/** 默认心跳周期,即初始化而来的周期 */
private long mDefaultCycle;

public StatiPollMgr(){
}

/**
 * 开启心跳
 *
 * @param aCardiacCycle
 *            心跳周期
 */
public void start(long aCardiacCycle) {
    mDefaultCycle = aCardiacCycle;
    mCardiacCycle = aCardiacCycle;

    checkDateChanging();
    stop();
    loop();
}

/**
 * 停止心跳
 */
public void stop() {
    sPrivateHandler.get().removeMessages(MSG_TIMEOUT);
}

/**
 * 循环
 */
private void loop() {
    Message msg = sPrivateHandler.get().obtainMessage(MSG_TIMEOUT, this);
    sPrivateHandler.get().sendMessageDelayed(msg, mCardiacCycle);
}

/**
 * 超期通知
 */
public void onTimeOut() {
    // do something
}

/**
 * 检测将要跨天时,调整心跳周期;跨天之后,调回默认值
 */
private void checkDateChanging() {
    Time time = new Time();
    time.setToNow();
    int hour = time.hour; //24小时制
    int minute = time.minute;
    if (hour == 23) { //SUPPRESS CHECKSTYLE
        int cycle = 61 - minute; // SUPPRESS CHECKSTYLE 12:01访问
        long timeSchedule = cycle * DateUtils.MINUTE_IN_MILLIS;
        if (timeSchedule < mCardiacCycle) {
            mCardiacCycle = timeSchedule;
        }
    } else {
        if (mCardiacCycle != mDefaultCycle) {
            mCardiacCycle = mDefaultCycle;
        }
    }
}

/**
 * Handler
 */
private static final ThreadLocal<Handler> sPrivateHandler = new ThreadLocal<Handler>() {
    @Override
    protected Handler initialValue() {
        return new Handler(Looper.getMainLooper()) {

            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case MSG_TIMEOUT:
                        StatiPollMgr schedule = (StatiPollMgr) msg.obj;
                        if (schedule != null) {
                            schedule.onTimeOut();
                            schedule.checkDateChanging();
                            schedule.loop();
                        }
                        break;
                    default:
                        break;
                }
            }

        };
    }
};

}

三 采用AlarmManager和Broadcast

采用Anrdoid自带的Alarm机制来做定时操作,本API本来用作系统的铃声操作,我们可以借助他来完成定时操作,一般我们在Alarm来启动一个Receiver,在Receiver中去执行我们的需求代码就可以了

Receiver 用来接收消息

public class CoreReceiver extends BroadcastReceiver {

public static final String REPORT_ACTION = "action.base.send_report";

@Override
public void onReceive(Context context, Intent intent) {

    if (context == null || intent ==null ) {
        return;
    }

    if (TextUtils.equals(intent.getAction(), REPORT_ACTION)) {

        Toast.makeText(context, "send statData", Toast.LENGTH_LONG).show();

        //do some 列入去请求网络,或其它更新UI操作等

    }

AlarmManager

用来设定时间和触发广播

public class PollUtil {

  static CoreReceiver receiver;

/**开启轮询服务
 * @param context
 * @param seconds
 * @param cls
 * @param action
 */
public static void startPollingService(Context context, int seconds, Class<?> cls, String action) {

    //获取AlarmManager系统服务
    AlarmManager manager = (AlarmManager) context
            .getSystemService(Context.ALARM_SERVICE);

    //包装需要执行Service的Intent
    Intent intent = new Intent(context, cls);
    intent.setAction(action);
    PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0,
            intent, PendingIntent.FLAG_UPDATE_CURRENT);

    //触发服务的起始时间
    long triggerAtTime = SystemClock.elapsedRealtime();

    //使用AlarmManger的setRepeating方法设置定期执行的时间间隔(seconds秒)和需要执行的Service
    manager.setRepeating(AlarmManager.ELAPSED_REALTIME, triggerAtTime,
            seconds * 1000, pendingIntent);
}

/**
 * 停止轮询服务
 * @param context
 * @param cls
 * @param action
 */
public static void stopPollingService(Context context, Class<?> cls, String action) {
    AlarmManager manager = (AlarmManager) context
            .getSystemService(Context.ALARM_SERVICE);
    Intent intent = new Intent(context, cls);
    intent.setAction(action);
    PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0,
            intent, PendingIntent.FLAG_UPDATE_CURRENT);
    //取消正在执行的服务
    manager.cancel(pendingIntent);

}

接下来我们的Activity中直接可以调用轮询工具类的start方法,

PollUtil.stopPollingService(mContext, CoreReceiver.class, CoreReceiver.REPORT_ACTION , 3);

总结

上面三种方法都可以实现本地轮询器,那么哪种方式比较靠谱呢,

显然第一种是开启一个Service,这样消耗显而易见,在app内存持续暴涨情况下这个服务又被kill的可能,我们可以把Service声明成进程,以及提高到前台,也可以采用广播来启动,但逃不过第三方安全软件kill的可能,在保证功能情况下,这种方式也不可取的。我们APP退出时更保证不正常的轮询

第二种采用handler, 性能开销相对很低,我们也可以在app启动时做一些轮询操作,但是当我们的App退出时就无法进行轮询操作的,这种实现方式,我们可以app启动的相对需求中采用,比如去计时去采集app的行为日志,性能开销等,

第三种,借助系统的Api,那么本身的系统就进行闹铃操作,也可以在app退出是进行定时,比如推送功能我们可以借助这种方案,但是会存在手机兼容问题,比如国产的手机已经对我们的Alarm加入权限,第三方应用无法对此操作。

不管那种方式,我们也可以采取多方式配合,比如我们广播启动Service,Service在被杀的时候发送来触发广播,广播竟可能的监听系统多种广播来启动我们的Service, 也可以将Alarm加入进来,来守护某个Service

当然性能方面第二种是最优的,功能全面来说第三种最优

自定义统计SDK:

http://www.jianshu.com/p/cd83e81b78aa

Android 推送和统计最优轮循(心跳策略)探究实践的更多相关文章

  1. Android推送服务(2)微信智能心跳方案

    http://mp.weixin.qq.com/s?__biz=MzAwNDY1ODY2OQ==&mid=207243549&idx=1&sn=4ebe4beb8123f1b5 ...

  2. Android推送服务——百度云推送

    一.推送服务简介 消息推送,顾名思义,是由一方主动发起,而另一方与发起方以某一种方式建立连接并接收消息.在Android开发中,这里的发起方我们把它叫做推送服务器(Push Server),接收方叫做 ...

  3. Mosquitto搭建Android推送服务(一)MQTT简介

    总体概要: MQTT系列文章分为4部分 1.MQTT简介 2.mosquitto服务器搭建 3.编写Mosquitto的可视化工具 4.使用Mosquitto完成Android推送服务 文章钢要: 对 ...

  4. Android 推送实现

    解决数据同步的问题:常用的方法有2种. (1) 定时去服务器上查询数据,也叫Polling. (2) 手机跟服务器之间维护一个 TCP 长连接,或者使用SMS,当服务器有数据时,实时推送到客户端,也就 ...

  5. Android推送通知指南

      Android推送通知指南 在开发Android和iPhone应用程序时,我们往往需要从服务器不定的向手机客户端即时推送各种通知消息,iPhone上已经有了比较简单的和完美的推送通知解决方案,可是 ...

  6. Android推送技术研究

    前言 最近研究Android推送的实现, 研究了两天一夜, 有了一点收获, 写下来既为了分享, 也为了吐槽. 需要说明的是有些东西偏底层硬件和通信行业, 我对这些一窍不通, 只能说说自己的理解. 为什 ...

  7. Android推送分析

     cpu多核利用能够实现Android推送的吞吐量. 讲明白这点,我们需要了解Android推送的基本原理了.如果实现C(客户端)与server(客户端)实时通讯了.这里有两种思路了: 1.一种是定时 ...

  8. Android推送方案

    一. 常见的推送原理: 1)轮询(Pull)方式:应用程序应当阶段性的与服务器进行连接并查询是否有新的消息到达,你必须自己实现与服务器之间的通信,例如消息排队等.而且你还要考虑轮询的频率,如果太慢可能 ...

  9. 转:Android推送技术研究

    Android推送技术研究 字数5208 阅读4026 评论5 喜欢35 前言 最近研究Android推送的实现, 研究了两天一夜, 有了一点收获, 写下来既为了分享, 也为了吐槽. 需要说明的是有些 ...

随机推荐

  1. ●BZOJ 2669 [cqoi2012]局部极小值

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=2669 题解: 容斥,DP,DFS 先看看 dp 部分:首先呢,X的个数不会超过 8个.个数很 ...

  2. udacity/CarND-Path-Planning-Project 工程详细配置过程——吐血整理

    本人原创,转载请注明地址 学习udacity/CarND-Path-Planning-Project 工程过程 1.首先登陆 jeremy-shannon/CarND-Path-Planning-Pr ...

  3. C++变量和基本类型——2.3.1引用

    引用:为对象起了另外一个名字,通常将申明符写成&d的形式来定义引用类型,其中d是申明的变量名: int ival =1024; int &refVal=ival 一般在初始化变量时,初 ...

  4. C++多态?

    以前看资料只是理解多态是"一个接口,多种调用" ,但是没有理解其真正意思,不明白具体咋么实现. 不过看了这位博主的博客后对多态有了一些理解,链接:https://www.cnblo ...

  5. switch 循环中的case理解

    case后面的常量表达式是程序的入口,一旦找到入口后,后面的其他的case就没有用了,程序就会继续执行后面的所有代码

  6. ml-agent:Win10下环境安装

    这是我看到的最全面最详细的ml-agent讲解.(只用于学习与知识分享,如有侵权,联系删除.谢谢!) 来自CodeGize的个人博客 .源链接:https://www.cnblogs.com/Code ...

  7. 春招实习面经分享(已拿到腾讯春招Offer)

    十分幸运地收到了腾讯的Offer..回来报答一下各位牛客网的战友们,说起来也是有点运气成分,最后通过腾讯的内推收到了offer!之前也屡遭重创,阿里的内推一面挂了(寒假过早地投简历,电话面试应对地不太 ...

  8. centos7 支持中文显示

    http://www.linuxidc.com/Linux/2017-07/145572.htm这篇文章比较全.我印证了一下,没有问题 centos7的与centos6有少许不同: 1.安装中文包: ...

  9. Mysql--七种 Join 查询

    Mysql 系列文章主页 =============== 1 准备数据 1.1 建立 Employee 表 DROP TABLE IF EXISTS employee; CREATE TABLE IF ...

  10. dataview findrows

    DataView dvStu = dsStu.Tables[0].Copy().DefaultView;//当前学年学期下所有学生 dvStu.Sort = "bjmc,xm"; ...