首页 > 其他分享 >关于安卓Handler之延时我不准时

关于安卓Handler之延时我不准时

时间:2024-11-02 20:15:27浏览次数:5  
标签:return 安卓 private delay Handler long 延时 public

背景

最近在做一个小功能,其中涉及到一个延时处理逻辑,如果是通过定时去轮询并且执行,那么就会导致一个耗电问题,所以定时轮询是不实际的,所以暂停的思路,就是通过延时实现。

思考

安卓延时,好家伙,一看还能有几个能实现,第一个handler,第二个AlarmManager,还有一些什么thread pool interval之类的。本文只会讲述,Handler实现,其他后续有机会再讲解。

开发环境

win10,as4+,jdk8+

过程

文末将会放出,所有关联的代码
要点

有小伙子可能会发现,哟,这个不是手到拈来吗,直接handler postDelay就行了啊,何必再浪费口舌?的确,这种思路上是没有任何问题,有问题的是,系统的cpu会休眠,如果handler delay的时间过长,那么就会导致时间不准。

举个例子,如果业务上面,需要延时10个小时,直接用handler的delay实现,你会发现百分之九十九都是不准的。一般情况,都会延时个几分钟,甚至十几分钟。导致这种原因,就是cpu休眠以及应用冻结等方面的影响,具体源码不再一一列出了。

还有一种场景,有一个业务,handler做定时器,一秒执行一次,如果手机机型了锁屏,正常情况,handler也会失效,这也和系统的休眠机制有关系。所以,这里就涉及到一个结束时间的概念,要以结束时间为准,而不是算好delay的次数为准。

实现

那么,有了以上的问题,应该要怎么去实现,怎么去避免?目前有一个大概的思路,就是把延时的时间,就行一个“阶梯划分”。
举例:如果你要延时一个小时执行,那么就不能直接delay一个小时,我们需要划分为,先delay个半小时,然后半小时到了,再计算剩余时间,然后再delay个十五分钟,同样地,最后粒度越来越小,这种就能够保证大部分情况下,延时的准确性,当然,这是大部分情况。博主实测,应用挂后台24小时,延时任务依旧按时执行。

这个逻辑,虽然有点麻烦,但是按道理是实用的。不过这种实现方式,不适用于对时间要求很高的场景。

下面是全部关联的代码,博主把它们封装成为一个类了:

package com.example.demo.utils;

import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;

import androidx.annotation.NonNull;

import java.io.Serializable;

/**
 * FileName: HandlerDelayer
 * Author: lzt
 * Date: 2024/10/31 10:06
 * Description:延时工具类
 */
public class ModuleTimerHandlerDelayer implements Serializable {

    private static final String TAG = ModuleTimerHandlerDelayer.class.getSimpleName();
    private final Handler mDelayHandler;
    private DelayCallback mDelayCallback;
    //延时阈值
    private static final long DELAY_THRESHOLD = 2 * 1000 * 60;
    //多线程锁
    private final Object SYNC_LOCK = new Object();
    //是否结束了
    private boolean isRelease = false;

    public ModuleTimerHandlerDelayer() {
        mDelayHandler = new Handler(Looper.getMainLooper()) {
            @Override
            public void handleMessage(@NonNull Message msg) {
                super.handleMessage(msg);
                Object messageObj = msg.obj;
                if (!(messageObj instanceof DelayClass)) {
                    return;
                }
                DelayClass delayClass = (DelayClass) messageObj;
                if (!delayClass.isSegment()) {
                    //不用切割,直接回调
                    if (getDelayCallback() != null) {
                        getDelayCallback().runTask(delayClass.getMessage());
                    }
                    return;
                }
                //需要切割,重新切割
                long endTime = delayClass.getEndTime();
                long nextDelay = getDelayTime(endTime);
                if (nextDelay <= 0) {
                    if (getDelayCallback() != null) {
                        getDelayCallback().runTask(delayClass.getMessage());
                    }
                    return;
                }
                //存在延时,继续delay
                Message obtMessage = mDelayHandler.obtainMessage();
                obtMessage.what = delayClass.messageWhat;
                obtMessage.obj = delayClass;
                mDelayHandler.sendMessageDelayed(obtMessage, nextDelay);
            }
        };
    }

    private String createMessageKey() {
        return String.valueOf(System.currentTimeMillis());
    }

    public DelayCallback getDelayCallback() {
        return mDelayCallback;
    }

    public Message getMessage() {
        return mDelayHandler.obtainMessage();
    }

    /**
     * 传入结束时间,计算delay
     */
    private long getDelayTime(long endTime) {
        if (System.currentTimeMillis() >= endTime) {
            //已经结束了
            return 0L;
        }
        long interval = endTime - System.currentTimeMillis();
        if (interval > 1000 * 60 * 60L * 2L) {
            //大于两小时
            return 1000 * 60 * 60L;
        } else if (interval > 1000 * 60 * 30L) {
            //大于三十分钟
            return 1000 * 30L;
        } else if (interval > 1000 * 60 * 10L) {
            //大于十分钟
            return 1000 * 10L;
        } else if (interval > 1000 * 60L) {
            //大于一分钟
            return 1000 * 20L;
        } else {
            return interval;
        }
    }


    /**
     * 延时包装类
     */
    private static class DelayClass implements Serializable {
        private final int messageWhat;
        private final long startTime;
        private final long endTime;
        private final long delayTime;
        private final Message message;
        private final String key;

        //是否为分段延时
        private boolean isSegment = false;

        private DelayClass(String key, int messageWhat, long startTime, long endTime, long delayTime, Message message) {
            this.messageWhat = messageWhat;
            this.key = key;
            this.startTime = startTime;
            this.endTime = endTime;
            this.delayTime = delayTime;
            this.message = message;
        }

        public boolean isSegment() {
            return isSegment;
        }

        public void setSegment(boolean segment) {
            isSegment = segment;
        }

        public String getKey() {
            return key;
        }

        public long getEndTime() {
            return endTime;
        }

        public int getMessageWhat() {
            return messageWhat;
        }

        public long getStartTime() {
            return startTime;
        }

        public long getDelayTime() {
            return delayTime;
        }

        public Message getMessage() {
            return message;
        }
    }


    public interface DelayCallback {
        void runTask(Message message);
    }


    //外部回调--------------------------------------------------------------------

    public void setDelayCallback(DelayCallback delayCallback) {
        mDelayCallback = delayCallback;
    }


    //外部调用--------------------------------------------------------------------

    public void delay(long delay, Message message) {
        if (isRelease) {
            return;
        }
        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (SYNC_LOCK) {
                    try {
                        Thread.sleep(20);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    String messageKey = createMessageKey();
                    Log.d(TAG, "delay start messageKey: " + messageKey);
                    int what = message.what;
                    long endTime = System.currentTimeMillis() + delay;
                    DelayClass delayClass = new DelayClass(messageKey, what, System.currentTimeMillis(), endTime, delay, message);
                    if (delay <= DELAY_THRESHOLD) {
                        //直接发送
                        delayClass.setSegment(false);
                        Message obtMessage = mDelayHandler.obtainMessage();
                        obtMessage.what = delayClass.messageWhat;
                        obtMessage.obj = delayClass;
                        mDelayHandler.sendMessageDelayed(obtMessage, delayClass.delayTime);
                        return;
                    }
                    //分段延时
                    delayClass.setSegment(true);
                    Message obtMessage = mDelayHandler.obtainMessage();
                    obtMessage.what = delayClass.messageWhat;
                    obtMessage.obj = delayClass;
                    long delayTime = getDelayTime(endTime);
                    mDelayHandler.sendMessageDelayed(obtMessage, delayTime);
                }
            }
        }).start();
    }


    public void emptyDelay(int what, long nextTaskDelayTime) {
        synchronized (SYNC_LOCK) {
            String messageKey = createMessageKey();
            long endTime = System.currentTimeMillis() + nextTaskDelayTime;

            Message orgMessage = getMessage();
            orgMessage.what = what;

            DelayClass delayClass = new DelayClass(messageKey, what, System.currentTimeMillis(), endTime, nextTaskDelayTime, orgMessage);
            delayClass.setSegment(true);
            Message obtMessage = mDelayHandler.obtainMessage();
            obtMessage.what = delayClass.messageWhat;
            obtMessage.obj = delayClass;
            mDelayHandler.sendMessageDelayed(obtMessage, delayClass.delayTime);
        }

    }

    public void release() {
        isRelease = true;
        mDelayHandler.removeCallbacksAndMessages(null);
    }

}

代码解析

对于上面代码核心的思路,就是通过一个wrapper,进行包装外部传入的message,同时把结束时间也带上,方便后续的结束时间重新计算。聪明的你们,估计一看代码,就会恍然大悟了。

注意,用完以后,记得release哦

that’s all---------------------------------------------------

标签:return,安卓,private,delay,Handler,long,延时,public
From: https://blog.csdn.net/motosheep/article/details/143455217

相关文章

  • 安卓13可用的黄鸟神器(HttpCanary)
    安卓13可用的黄鸟神器(HttpCanary)MIUI14系统版本13(API33)设备XiaomiRedmi系统架构arm64-v8a4个安装包名称如下:1.HttpCanary3.3.6arm64-v8aMonet2.HttpCanary3.3.6armeabi-v7aMonet3.HttpCanary3.3.6x86Monet4.HttpCanaryb3.3.6x86_64Monet不知道系统架构的,打开L......
  • 安卓Android 图片/Bitmap工具类
    图片/Bitmap工具类1、根据uri解码图片,通常用在从相册选择照片(1)此方法包含了压缩Bitmap,根据目标尺寸缩放等/***根据Uri解码图片**@paramselectedImage图片的Uri*@return解码后的Bitmap对象*@throwsFileNotFoundException如果文件找不......
  • 为什么安卓不去掉 Java 语言底层_2
    为什么安卓不去掉Java语言底层?在探讨为什么安卓不去掉Java语言底层时,我们可以立即指出几个核心原因:兼容性保持、开发生态成熟度、跨平台性能。其中,兼容性保持是最为关键的一点。Android平台自推出以来,就大量采用Java语言进行应用开发。这背后不仅仅是因为Java语言的广泛使用......
  • 安卓APP开发中,如何使用加密芯片?
    加密芯片是一种专门设计用于保护信息安全的硬件设备,它通过内置的加密算法对数据进行加密和解密,以防止敏感数据被窃取或篡改。如下图HD-RK3568-IOT工控板,搭载ATSHA204A加密芯片,常用于有安全防护要求的工商业场景,下文将为大家介绍安卓APP开发中,如何使用此类加密芯片。1. Android......
  • 安卓dispatchKeyEvent事件
    示例:publicclassMyActivityextendsActivity{@OverridepublicbooleandispatchKeyEvent(KeyEventevent){//检查是否按下了回退键(通常是物理按键或者是导航键)if(event.getKeyCode()==KeyEvent.KEYCODE_BACK){//检查事件类......
  • 无法在<fastCGI>应用程序中找到<handler>scriptProcessor
    解决方案总结更换操作系统原因:当前使用的Windows操作系统不支持PHP程序。操作步骤:备份站点数据和数据库数据。更改主机操作系统为Linux。参考文档:更改主机操作系统和备份和恢复数据。升级云虚拟主机原因:当前云虚拟主机配置不支持PHP框架。操作步骤:将云虚拟主......
  • 基于安卓Android的自来水收费系统APP(源码+文档+部署+讲解)
    !!!!!!!!!选题不知道怎么选不清楚自己适合做哪块内容都可以免费来问我会持续一直更新下去有问必答一键收藏关注不迷路源码获取:https://pan.baidu.com/s/1aRpOv3f2sdtVYOogQjb8jg?pwd=jf1d提取码:jf1d !!!!!!!!!项目介绍随着智能水务管理的发展和用户对便捷服务的需求增加,一个功能全......
  • 【JavaEE初阶】深入理解TCP协议特性之延时应答,捎带应答,面向字节流以及异常处理
     前言......
  • SpringBoot安卓开发的水果商城app (案例分析)-附源码
    摘  要在移动互联网的快速发展背景下,手机应用已成为人们生活中不可或缺的一部分。水果商城App作为电商领域的重要应用之一,为用户提供便捷的购物体验和丰富的商品选择。本研究旨在基于Android平台开发水果商城App,结合SpringBoot框架和Mysql数据库,以实现功能强大、操作简......
  • 从0到1,解读安卓ASO优化!
     大家好,我是互金行业的一名ASO运营专员,目前是负责我们两个APP的ASO方面的维护,今天分享的内容主要是关于安卓ASO优化方案。大致内容分为三块:首先我要讲一下ASO是什么;接下来就是安卓的渠道的选择,安卓主流市场的关键词的覆盖方案;最后我想跟大家讲一下安卓CPD投放的那些坑。......