展开说说:Android之常用的延时执行策略

总结了以下六种常用的Android延时执行策略,以此记录:

1、 TimerTask

2、 Handler.postDelayed

3、 Handler.sendEnptyMessageDelayeed

4、 Thread.sleep 线程休眠 - 需要在子线程

5、 使用 AlarmManager- 定时器或者闹钟

6、Wait

首先定义一个时间常量:

复制代码
public static final long DELAYTIME = 2000L;

1、TimerTask

复制代码
TimerTask mTimerTask = new TimerTask() {
        @Override
        public void run() {
            Log.e(TAG, "TimerTask -run:");
        }
    };
//timer可以复用,timerTask不可复用,否则闪退
if (mTimer ==null){
    mTimer = new Timer();
}
mTimer.schedule(mTimerTask,DELAYTIME);

Handler.postDelayed
handler.postDelayed(new Runnable() {
    @Override
    public void run() {
        Log.e(TAG, "handler.postDelayed :");
    }
},DELAYTIME);

注意:以上用法timer 可以复用, timerTask 不可复用。

第二种和第三中都依赖Handler,先定义一个handler

复制代码
public static class MyHandler extends Handler{

    private final WeakReference<Activity> activityWeak;

    public MyHandler(Activity activity){
        activityWeak = new WeakReference<>(activity);
    }

    @Override
    public void handleMessage(@NonNull Message msg) {
        super.handleMessage(msg);
        TimerActivity activity = (TimerActivity) activityWeak.get();
        switch (msg.what){
            case TimerActivity.MESSAGE1:
                Log.e(TAG, "handleMessage: what="+msg.what );
                break;
            default:
                Log.e(TAG, "handleMessage:      default      -what="+msg.what );
                break;
        }
    }
}

2、Handler.postDelayed

复制代码
handler.postDelayed(new Runnable() {
    @Override
    public void run() {
        Log.e(TAG, "handler.postDelayed :");
    }
},DELAYTIME);

3、Handler.sendEnptyMessageDelayeed

复制代码
Log.e(TAG, "handler.sendEmptyMessageAtTime :start");
handler.sendEmptyMessageDelayed(MESSAGE1,DELAYTIME);
Log.e(TAG, "handler.sendEmptyMessageAtTime :");

4、Thread.sleep 线程休眠 -需要在子线程, sleep 是线程的方法,他休眠中不会释放锁

复制代码
Log.e(TAG, "Thread.sleep:  onClick" );
Object lock = new Object();
new Thread() {
    @Override
    public void run() {
        super.run();
        try {
            synchronized (lock){
                Log.e(TAG, "Thread.sleep:  子线程start" );
                Thread.sleep(20000);
                Log.e(TAG, "Thread.sleep:  子线程end" );
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}.start();
try {
    Log.e(TAG, "Thread.sleep:  onClick-1" );
    Thread.sleep(200);//此行代码影响甚大,需灵活注释,
虽然上面new Thread耗时很短,但是也是有一定开销足以让它在主线程顺序之后执行
    Log.e(TAG, "Thread.sleep:  主线程执行-准备获取锁" );
    synchronized (lock){
        Log.e(TAG, "Thread.sleep:  主线程已获得锁" );
    }
    Log.e(TAG, "Thread.sleep:  主线程已释放锁锁" );
} catch (InterruptedException e) {
    e.printStackTrace();
}

主线程没有 200毫秒延时也就是注释Thread.sleep (200)就会先执行主线程然后进入子线程,虽然上面 new Thread 耗时很短,但是也是有一定开销足以让它在主线程顺序之后执行,以上代码测试发现从new Thread到子线程内第一行代码执行耗时不足1毫秒。以下是运行日志:
2023-12-11 15:12:26.944 18617-18617/com.example.testdemo3 E/com.example.testdemo3.activity.TimerActivity: Thread.sleep: onClick
2023-12-11 15:12:26.945 18617-18617/com.example.testdemo3 E/com.example.testdemo3.activity.TimerActivity: Thread.sleep: onClick-1
2023-12-11 15:12:26.945 18617-18617/com.example.testdemo3 E/com.example.testdemo3.activity.TimerActivity: Thread.sleep: 主线程执行 - 准备获取锁
2023-12-11 15:12:26.946 18617-18617/com.example.testdemo3 E/com.example.testdemo3.activity.TimerActivity: Thread.sleep: 主线程已获得锁
2023-12-11 15:12:26.946 18617-18919/com.example.testdemo3 E/com.example.testdemo3.activity.TimerActivity: Thread.sleep: 子线程 start
2023-12-11 15:12:46.947 18617-18919/com.example.testdemo3 E/com.example.testdemo3.activity.TimerActivity: Thread.sleep: 子线程 end

======================================

主线程有 200 毫秒延时也就是不注释Thread.sleep (200),就会先进入子线程执行完

然后进入主线程**。以下是运行日志:**
2023-12-11 15:09:40.785 17990-17990/com.example.testdemo3 E/com.example.testdemo3.activity.TimerActivity: Thread.sleep: onClick
2023-12-11 15:09:40.786 17990-17990/com.example.testdemo3 E/com.example.testdemo3.activity.TimerActivity: Thread.sleep: onClick-1
2023-12-11 15:09:40.786 17990-18231/com.example.testdemo3 E/com.example.testdemo3.activity.TimerActivity: Thread.sleep: 子线程 start
2023-12-11 15:09:40.987 17990-17990/com.example.testdemo3 E/com.example.testdemo3.activity.TimerActivity: Thread.sleep: 主线程执行 - 准备获取锁
2023-12-11 15:10:00.787 17990-18231/com.example.testdemo3 E/com.example.testdemo3.activity.TimerActivity: Thread.sleep: 子线程 end
2023-12-11 15:10:00.787 17990-17990/com.example.testdemo3 E/com.example.testdemo3.activity.TimerActivity: Thread.sleep: 主线程已获得锁

5、使用 AlarmManager- 定时器或者闹钟。适用一直在后台运行的定时任务,此处放在一个 service 执行

复制代码
Intent intent = new Intent();
intent.setAction("short");
ComponentName component = new ComponentName(TimerActivity.this, MyReceiver.class);
intent.setComponent(component);
//这里除了启动广播也可以换成启动Activity和service
PendingIntent sender = PendingIntent.getBroadcast(TimerActivity.this,0,intent,0);

Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.SECOND,5);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP,System.currentTimeMillis(),sender);

6、Wait- 必须使用 synchronized ,他是 Object 的方法,他休眠会释放锁

复制代码
 Object lock = new Object();
                new Thread(){
                    @Override
                    public void run() {
                        super.run();
                        try {
//                            synchronized (lock){  //没有synchronized锁就会报错:java.lang.IllegalMonitorStateException: object not locked by thread before wait()
                                Log.e(TAG, "Thread.wait:  start" );
				//以下两行需灵活注释
                                lock.wait(2000);
//                                Thread.sleep(2000);
                                Log.e(TAG, "Thread.wait:  end" );
//                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        Log.e(TAG, "Thread.wait:  子线程第二条" );
                    }
                }.start();

                try {
                    Thread.sleep(200);
                    Log.e(TAG, "Thread.wait:  主线程开始获取锁" );
                    synchronized (lock){
                        Log.e(TAG, "Thread.wait:  主线程已获得锁" );
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

**lock.wait(2000)放开,**Thread.sleep(2000)注释,日志如下:
2023-12-11 14:21:34.371 9385-9748/com.example.testdemo3 E/com.example.testdemo3.activity.TimerActivity: Thread.wait: start
2023-12-11 14:21:34.571 9385-9385/com.example.testdemo3 E/com.example.testdemo3.activity.TimerActivity: Thread.wait: 主线程开始获取锁
2023-12-11 14:21:34.571 9385-9385/com.example.testdemo3 E/com.example.testdemo3.activity.TimerActivity: Thread.wait: 主线程已获得锁
2023-12-11 14:21:36.372 9385-9748/com.example.testdemo3 E/com.example.testdemo3.activity.TimerActivity: Thread.wait: end
2023-12-11 14:21:36.372 9385-9748/com.example.testdemo3 E/com.example.testdemo3.activity.TimerActivity: Thread.wait: 子线程第二条

Thread.sleep(2000) **放开,lock.wait(2000)**注释,日志如下:

sleep 是线程的方法,他休眠中不会释放锁
2023-12-11 14:24:27.519 10346-10750/com.example.testdemo3 E/com.example.testdemo3.activity.TimerActivity: Thread.wait: start
2023-12-11 14:24:27.719 10346-10346/com.example.testdemo3 E/com.example.testdemo3.activity.TimerActivity: Thread.wait: 主线程开始获取锁
2023-12-11 14:24:29.520 10346-10750/com.example.testdemo3 E/com.example.testdemo3.activity.TimerActivity: Thread.wait: end
2023-12-11 14:24:29.520 10346-10750/com.example.testdemo3 E/com.example.testdemo3.activity.TimerActivity: Thread.wait: 子线程第二条
2023-12-11 14:24:29.520 10346-10346/com.example.testdemo3 E/com.example.testdemo3.activity.TimerActivity: Thread.wait: 主线程已获得锁

相关推荐
aqi003 分钟前
FFmpeg开发笔记(六十四)使用国产的RedPlayer播放器观看网络视频
android·ffmpeg·音视频·直播·流媒体
雨白5 分钟前
扩展函数和运算符重载
android
casual_clover1 小时前
Android Studio 解决首次安装时下载 Gradle 慢问题
android·ide·android studio
天天爱吃肉82182 小时前
新能源汽车热管理核心技术解析:冬季续航提升40%的行业方案
android·python·嵌入式硬件·汽车
快乐觉主吖2 小时前
Unity的日志管理类
android·unity·游戏引擎
明月看潮生2 小时前
青少年编程与数学 01-011 系统软件简介 06 Android操作系统
android·青少年编程·操作系统·系统软件·编程与数学
snetlogon203 小时前
JDK17 Http Request 异步处理 源码刨析
android·网络协议·http
消失的旧时光-19433 小时前
Android USB 通信开发
android·java
吃汉堡吃到饱4 小时前
【Android】浅析View.post()
android
咕噜企业签名分发-淼淼4 小时前
开发源码搭建一码双端应用分发平台教程:逐步分析注意事项
android·ios