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. hdu4542 && ZOJ2562(反素数)

    反素数: 对于任何正整数,其约数个数记为,例如,如果某个正整数满足:对任意的正整 数,都有,那么称为反素数. 有两个特点: 1.一个反素数的质因子必是从2开始的质数 2.如果,那么必有 最常见的问题如 ...

  2. hdu 2871 线段树(各种操作)

    Memory Control Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) T ...

  3. hdu 5646DZY Loves Partition(构造)

    DZY Loves Partition  Accepts: 154  Submissions: 843  Time Limit: 4000/2000 MS (Java/Others)  Memory ...

  4. Spring学习笔记1——入门

    Spring是一个基于IOC和AOP的结构J2EE系统的框架 IOC 反转控制 是Spring的基础,Inversion Of Control 简单说就是创建对象由以前的程序员自己new 构造方法来调 ...

  5. day4 liaoxuefeng---高级特性

    掌握了Python的数据类型.语句和函数,基本上就可以编写出很多有用的程序了. 但是在Python中,代码不是越多越好,而是越少越好.代码不是越复杂越好,而是越简单越好. 基于这一思想,我们来介绍Py ...

  6. Linux下用程序实现统计cpu和内存的利用率

    Linux下没有直接可以调用系统函数知道CPU占用和内存占用.那么如何知道CPU和内存信息呢.只有通过proc伪文件系统来实现. proc伪文件就不介绍了,只说其中4个文件.一个是/proc/stat ...

  7. 原生js移动端列表无缝间歇向上滚动

    在项目开发中尤其是在项目的活动页面的开发中,经常需要将用户的购买信息或中奖信息等以列表的形式展示在页面当中,并可以使其自动间歇向上滚动来达到在有限的区域内展示所有信息的目的.通常的做法是通过将列表父元 ...

  8. Linux下常用设置文件和文件夹读写权限操作

    1.查看权限 ls -l xxx.xxx (xxx.xxx是文件名)   2.常见权限 -rw------- (600) 只有所有者才有读和写的权限 -rw-r--r-- (644) 只有所有者才有读 ...

  9. SpringBoot学习之启动探究

    SpringApplication是SpringBoot的启动程序,我们通过它的run方法可以快速启动一个SpringBoot应用.可是这里面到底发生了什么?它是处于什么样的机制简化我们程序启动的?接 ...

  10. iis部署python运行环境

    IIS部署 1.启用或者关闭windows功能,选择安装CGI,我这里已经安装过了. 2.安装后重新打开IIS看到CGI 3.配置ISAPI和CGI限制 4.右上角添加,路径是python安装路径,注 ...