20160929152625744.jpg (59.98 KB, 下载次数: 13400)
下载附件 保存到相册
8 年前 上传
public abstract class HeartbeatScheduler { protected int timeout = 20000; protected int minHeart = 60; protected int maxHeart = 300; protected int step = 30; protected volatile boolean started = false; protected volatile long heartbeatSuccessTime; protected volatile int currentHeartType; public static final String HEART_TYPE_TAG = "heart_type"; public static final int UNKNOWN_HEART = 0, SHORT_HEART = 1, PROBE_HEART = 2, STABLE_HEART = 3, REDUNDANCY_HEART = 4; protected PendingIntent createPendingIntent(Context context, int requestCode, int heartType) { Intent intent = new Intent(); intent.setPackage(context.getPackageName()); intent.setAction(SyncAction.HEARTBEAT_REQUEST); intent.putExtra(HEART_TYPE_TAG, heartType); PendingIntent pendingIntent = PendingIntent.getBroadcast(context, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT); return pendingIntent; } protected void set(int minHeart, int maxHeart, int step) { this.minHeart = minHeart; this.maxHeart = maxHeart; this.step = step; SyncLogUtil.i("set minMax:" + minHeart + ",maxHeart:" + maxHeart + ",step:" + step); } protected boolean isStarted() { return started; } protected abstract boolean isStabled(); protected void setCurrentHeartType(int currentHeartType) { this.currentHeartType = currentHeartType; SyncLogUtil.i("set current heart type:" + currentHeartType); } protected int getTimeout() { return timeout; } protected void setTimeout(int timeout) { this.timeout = timeout; } protected long getHeartbeatSuccessTime() { return heartbeatSuccessTime; } protected void setHeartbeatSuccessTime(long heartbeatSuccessTime) { this.heartbeatSuccessTime = heartbeatSuccessTime; } protected abstract void start(Context context); protected abstract void stop(Context context); protected abstract void clear(Context context); protected abstract void adjustHeart(Context context, boolean success); protected abstract void startNextHeartbeat(Context context, int heartType); protected abstract void resetScheduledHeart(Context context); protected abstract void receiveHeartbeatFailed(Context context); protected abstract void receiveHeartbeatSuccess(Context context); protected abstract int getCurHeart(); } public class WatchHearbeatScheduler extends HeartbeatScheduler { private class Heartbeat { AtomicInteger heartbeatStabledSuccessCount = new AtomicInteger(0); // 心跳连续成功次数 AtomicInteger heartbeatFailedCount = new AtomicInteger(0); // 心跳连续失败次数 int successHeart; int failedHeart; int curHeart = 270; AtomicBoolean stabled = new AtomicBoolean(false); } private int curMaxHeart = maxHeart; private int curMinHeart = minHeart; private int maxFailedCount = 5; private int maxSuccessCount = 10; private volatile String networkTag; private int requestCode = 700; private Map<String, Heartbeat> heartbeatMap = new HashMap<>(); private List<Integer> successHeartList = new ArrayList<>(); protected WatchHearbeatScheduler() { } @Override protected void start(Context context) { started = true; networkTag = NetUtil.getNetworkTag(context); alarm(context); SyncLogUtil.i("start heartbeat,networkTag:" + networkTag); } @Override protected void stop(Context context) { heartbeatSuccessTime = 0; started = false; currentHeartType = UNKNOWN_HEART; for (Map.Entry<String, Heartbeat> entry : heartbeatMap.entrySet()) { Heartbeat heartbeat = entry.getValue(); heartbeat.heartbeatStabledSuccessCount.set(0); } cancel(context); SyncLogUtil.d("stop heartbeat..."); } @Override protected void setCurrentHeartType(int currentHeartType) { this.currentHeartType = currentHeartType; } @Override protected void set(int minHeart, int maxHeart, int step) { super.set(minHeart, maxHeart, step); curMaxHeart = maxHeart; curMinHeart = minHeart; } @Override protected boolean isStabled() { Heartbeat heartbeat = getHeartbeat(); return heartbeat.stabled.get(); } @TargetApi(Build.VERSION_CODES.KITKAT) public void alarm(Context context) { AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); Heartbeat heartbeat = getHeartbeat(); boolean stabled = heartbeat.stabled.get(); int heart; if (stabled) { heart = heartbeat.curHeart - 10; if (heart < minHeart) { heart = minHeart; } heart = heart * 1000; } else { heart = heartbeat.curHeart * 1000; } int heartType = stabled ? STABLE_HEART : PROBE_HEART; PendingIntent pendingIntent = createPendingIntent(context, requestCode, heartType); int sdk = Build.VERSION.SDK_INT; if (sdk >= Build.VERSION_CODES.KITKAT) { alarmManager.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + heart, pendingIntent); } else { alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + heart, pendingIntent); } SyncLogUtil.i("start heartbeat,curHeart [" + heartbeat.curHeart + "],heart [" + heart + "],requestCode:" + requestCode + ",stabled:" + stabled); } private void cancel(Context context) { Heartbeat heartbeat = getHeartbeat(); int heartType = heartbeat.stabled.get() ? STABLE_HEART : PROBE_HEART; AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); PendingIntent pendingIntent = createPendingIntent(context, requestCode, heartType); alarmManager.cancel(pendingIntent); SyncLogUtil.d("cancel heartbeat,requestCode:" + requestCode); } @Override public void startNextHeartbeat(Context context, int heartType) { alarm(context); } @Override public void resetScheduledHeart(Context context) { alarm(context); } private void addSuccessHeart(Integer successHeart) { if (!successHeartList.contains(successHeart)) { if (successHeartList.size() > 10) { successHeartList.remove(0); } successHeartList.add(successHeart); SyncLogUtil.i("add successHeart:" + successHeart); } SyncLogUtil.i("successHeartList:" + successHeartList); } private void removeSuccessHeart(Integer successHeart) { successHeartList.remove(Integer.valueOf(successHeart)); SyncLogUtil.i("successHeartList:" + successHeartList); } @Override protected void adjustHeart(Context context, boolean success) { if (currentHeartType == REDUNDANCY_HEART) { SyncLogUtil.d("redundancy heart,do not adjustHeart..."); return; } Heartbeat heartbeat = getHeartbeat(); if (success) { onSuccess(heartbeat); } else { onFailed(heartbeat); } SyncLogUtil.i("after success is [" + success + "] adjusted,heartbeat.curHeart:" + heartbeat.curHeart + ",networkTag:" + networkTag); } private void onSuccess(Heartbeat heartbeat) { heartbeat.successHeart = heartbeat.curHeart; curMinHeart = heartbeat.curHeart; addSuccessHeart(heartbeat.successHeart); heartbeat.heartbeatFailedCount.set(0); if (heartbeat.stabled.get()) { int count = heartbeat.heartbeatStabledSuccessCount.incrementAndGet(); SyncLogUtil.i("heartbeatStabledSuccessCount:" + heartbeat.heartbeatStabledSuccessCount.get()); if (count >= maxSuccessCount) { maxSuccessCount += 10; SyncLogUtil.i("maxSuccessCount:" + maxSuccessCount); Integer successHeart = selectMinSuccessHeart(heartbeat.curHeart); if (successHeart != null) { heartbeat.curHeart = successHeart; } else { heartbeat.stabled.set(false); curMaxHeart = maxHeart; heartbeat.curHeart = (curMinHeart + curMaxHeart) / 2; SyncLogUtil.i("curHeart = (" + curMinHeart + " + " + curMaxHeart + ") / 2 = " + heartbeat.curHeart); } } } else { heartbeat.curHeart = (curMinHeart + curMaxHeart) / 2; SyncLogUtil.i("curHeart = (" + curMinHeart + " + " + curMaxHeart + ") / 2 = " + heartbeat.curHeart); } if (heartbeat.curHeart >= maxHeart) { heartbeat.curHeart = maxHeart; heartbeat.stabled.set(true); SyncLogUtil.i("探测达到最大心跳adjust stabled:" + heartbeat.stabled.get()); } else if (curMaxHeart - curMinHeart < 10) { if (!heartbeat.stabled.get()) { heartbeat.curHeart = curMinHeart; } heartbeat.stabled.set(true); SyncLogUtil.i("二分法探测尽头adjust stabled:" + heartbeat.stabled.get()); } SyncLogUtil.i("curHeart:" + heartbeat.curHeart + ",curMinHeart:" + curMinHeart + ",curMaxHeart:" + curMaxHeart); } private void onFailed(Heartbeat heartbeat) { removeSuccessHeart(heartbeat.curHeart); heartbeat.failedHeart = heartbeat.curHeart; heartbeat.heartbeatStabledSuccessCount.set(0); int count = heartbeat.heartbeatFailedCount.incrementAndGet(); SyncLogUtil.i("heartbeatFailedCount:" + count); if (maxSuccessCount > 10) { maxSuccessCount -= 10; } if (count > maxFailedCount) { curMaxHeart = heartbeat.curHeart; } if (heartbeat.stabled.get()) { if (count > maxFailedCount) { Integer successHeart = selectMaxSuccessHeart(heartbeat.curHeart); if (successHeart != null) { heartbeat.curHeart = successHeart; } else { heartbeat.stabled.set(false); curMinHeart = minHeart; heartbeat.curHeart = (curMinHeart + curMaxHeart) / 2; SyncLogUtil.i("curHeart = (" + curMaxHeart + " + " + curMinHeart + ") / 2 = " + heartbeat.curHeart); } } else { SyncLogUtil.i("continue retry heartbeat.curHeart:" + heartbeat.curHeart + ",stabled:" + heartbeat.stabled.get()); } } else { if (count > maxFailedCount) { heartbeat.curHeart = (curMinHeart + curMaxHeart) / 2; SyncLogUtil.i("curHeart = (" + curMaxHeart + " + " + curMinHeart + ") / 2 = " + heartbeat.curHeart); } else { SyncLogUtil.i("continue retry heartbeat.curHeart:" + heartbeat.curHeart + ",stabled:" + heartbeat.stabled.get()); } } if (curMaxHeart - curMinHeart < 10) { if (!heartbeat.stabled.get()) { curMinHeart = minHeart; } SyncLogUtil.i("二分法探测达到瓶颈" + ",curHeart:" + heartbeat.curHeart); SyncLogUtil.i("curMinHeart:" + curMinHeart + ",curMaxHeart:" + curMaxHeart); } SyncLogUtil.i("curHeart:" + heartbeat.curHeart + ",curMinHeart:" + curMinHeart + ",curMaxHeart:" + curMaxHeart); } private Integer selectMaxSuccessHeart(int curHeart) { Collections.sort(successHeartList, new Comparator<Integer>() { @Override public int compare(Integer lhs, Integer rhs) { return rhs.compareTo(lhs); } }); SyncLogUtil.i("successHeartList:" + successHeartList); for (Integer heart : successHeartList) { if (curHeart >= heart) { continue; } else { return heart; } } return null; } private Integer selectMinSuccessHeart(int curHeart) { Collections.sort(successHeartList, new Comparator<Integer>() { @Override public int compare(Integer lhs, Integer rhs) { return lhs.compareTo(rhs); } }); SyncLogUtil.i("successHeartList:" + successHeartList); for (Integer heart : successHeartList) { if (curHeart >= heart) { continue; } else { return heart; } } return null; } private Heartbeat getHeartbeat() { Heartbeat heartbeat = heartbeatMap.get(networkTag); if (heartbeat == null) { heartbeat = new Heartbeat(); heartbeatMap.put(networkTag, heartbeat); } return heartbeat; } @Override protected void receiveHeartbeatFailed(Context context) { adjustHeart(context, false); } @Override protected void receiveHeartbeatSuccess(Context context) { adjustHeart(context, true); alarm(context); } @Override protected void clear(Context context) { stop(context); heartbeatMap.clear(); successHeartList.clear(); curMinHeart = minHeart; curMaxHeart = maxHeart; networkTag = null; SyncLogUtil.d("clear heartbeat..."); } @Override protected int getCurHeart() { Heartbeat heartbeat = getHeartbeat(); return heartbeat.curHeart; } }
来源:即时通讯网 - 即时通讯开发者社区!
轻量级开源移动端即时通讯框架。
快速入门 / 性能 / 指南 / 提问
轻量级Web端即时通讯框架。
详细介绍 / 精编源码 / 手册教程
移动端实时音视频框架。
详细介绍 / 性能测试 / 安装体验
基于MobileIMSDK的移动IM系统。
详细介绍 / 产品截图 / 安装体验
一套产品级Web端IM系统。
详细介绍 / 产品截图 / 演示视频
引用此评论
引用:fanfu 发表于 2017-05-16 09:53 在做及时通讯。有没有安卓端心跳总是不明白。发送返回,三次握手。感觉自己学的都没法用啊。。还是不熟练惹 ...
引用:ming06007 发表于 2018-10-24 09:46 正在做心跳方面的处理,借鉴一下
引用:椎锋陷陈 发表于 2021-09-06 11:05 关于最后的“对齐唤醒”我再补充一下: Android 6.0引入了低电耗模式与应用待机模式,并于Android 7.0加强 ...
引用:JackJiang 发表于 2021-09-06 12:39 你自已验证过,这么干是真的有效果是吧
引用:标准 AlarmManager 闹钟(包括 setExact() 和 setWindow())推迟到下一个维护期。 如果您需要设置在设备处于低电耗模式时触发的闹钟,请使用 setAndAllowWhileIdle() 或 setExactAndAllowWhileIdle()。 使用 setAlarmClock() 设置的闹钟将继续正常触发,系统会在这些闹钟触发之前不久退出低电耗模式。
精华主题数超过100个。
连续任职达2年以上的合格正式版主
为论区做出突出贡献的开发者、版主等。
经核实认证的即时通讯技术开发者、技术博主、开源工程作者、原创精华文章作者等。
积极发起、参与各类话题的讨论等,主题、发帖内容较有价值。
本人属:猪
本人属:兔
Copyright © 2014-2024 即时通讯网 - 即时通讯开发者社区 / 版本 V4.4
苏州网际时代信息科技有限公司 (苏ICP备16005070号-1)
Processed in 0.343750 second(s), 47 queries , Gzip On.