Android定时相关

执行定时任务的方法:

1、使用Timer

package com.hjqjl.whdemo.feature.feature0.ui.activity;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;

import com.blankj.utilcode.util.ToastUtils;
import com.hjqjl.whdemo.R;
import com.hjqjl.whdemo.base.BaseActivity;

import java.util.Timer;
import java.util.TimerTask;

public class TimerActivity extends BaseActivity {
    public static void start(Context context) {
        Intent starter = new Intent(context, TimerActivity.class);
        context.startActivity(starter);
    }

    private Timer timer;
    private TimerTask task;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_timer);
    }

    @Override
    protected void onStart() {
        super.onStart();
        startTimer();
    }

    @Override
    protected void onStop() {
        super.onStop();
        stopTimer();
    }

    /**
     * 启动定时器
     */
    public void startTimer() {
        if (timer == null) {
            timer = new Timer();
        }
        if (task != null) {
            task.cancel();
        }
        task = new TimerTask() {
            @Override
            public void run() {
                //执行定时任务
                ToastUtils.showShort("执行定时任务Timer");
            }
        };
        if (timer != null) {
            timer.schedule(task, 3000, 60000);
        }
    }

    /**
     * 停止定时器 刷新上传数据
     */
    private void stopTimer() {
        if (timer != null) {
            task.cancel();
            timer.cancel();
            timer.purge();
            timer = null;
        }
    }
}

2、使用ScheduledExecutorService

package com.hjqjl.whdemo.feature.feature0.ui.activity;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;

import com.blankj.utilcode.util.ToastUtils;
import com.hjqjl.whdemo.R;
import com.hjqjl.whdemo.base.BaseActivity;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class TimerActivity extends BaseActivity {
    public static void start(Context context) {
        Intent starter = new Intent(context, TimerActivity.class);
        context.startActivity(starter);
    }

    private ScheduledExecutorService exec;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_timer);
    }

    @Override
    protected void onStart() {
        super.onStart();
        initTimer();
    }

    @Override
    protected void onStop() {
        super.onStop();
        endExecutorScan();
    }

    private boolean isTimerRun = true;

    private void initTimer() {
        endExecutorScan();
        exec = Executors.newSingleThreadScheduledExecutor();//启动定时线程池
        if (exec != null) {
            exec.scheduleWithFixedDelay(new Runnable() {
                                            @Override
                                            public void run() {
                                                if (isTimerRun) {
                                                    //执行定时任务
                                                    ToastUtils.showShort("执行定时任务ScheduledExecutorService");
                                                }
                                            }
                                        },
                    3, 60, TimeUnit.SECONDS);
        }
    }

    private void endExecutorScan() {
        if (exec != null) {
            isTimerRun = false;
            exec.shutdownNow();
        }
        exec = null;//非单例模式,置空防止重复的任务
    }
}

3、倒计时按钮

实现如发送短信验证码等功能,通常需要倒计时功能,防止用户频繁按按钮发送短信。
效果如下:
在这里插入图片描述

import android.os.CountDownTimer;
import android.widget.Button;

/**
 * 倒计时Button帮助类
 * 用法
 * CountDownButtonHelper countDownButtonHelper = new CountDownButtonHelper(smsBtn);
 * countDownButtonHelper.start();//开始
 * ----------------
 * countDownButtonHelper.cancel();//取消
 */
public class CountDownButtonHelper {
    // 倒计时timer
    private CountDownTimer countDownTimer;
    // 计时结束的回调接口
    private OnFinishListener listener;

    private Button mButton;
    private String btnText;

    /**
     * @param button 需要显示倒计时的Button
     */
    public CountDownButtonHelper(Button button) {
        this.mButton = button;
        // 由于CountDownTimer并不是准确计时,在onTick方法调用的时候,time会有1-10ms左右的误差,这会导致最后一秒不会调用onTick()
        // 因此,设置间隔的时候,默认减去了10ms,从而减去误差。
        // 经过以上的微调,最后一秒的显示时间会由于10ms延迟的积累,导致显示时间比1s长max*10ms的时间,其他时间的显示正常,总时间正常
        countDownTimer = new CountDownTimer(10 * 1000, 1 * 1000 - 10) {//倒计时的最大值10s;倒计时的间隔1s

            @Override
            public void onTick(long time) {
                // 第一次调用会有1-10ms的误差,因此需要+15ms,防止第一个数不显示,第二个数显示2s
                mButton.setText("(" + ((time + 15) / 1000) + "秒)");
                //Logger.d("time = " + (time) + " text = " + ((time + 15) / 1000));
            }

            @Override
            public void onFinish() {
                mButton.setEnabled(true);
                if (btnText == null) {
                    mButton.setText("验证码");
                } else {
                    mButton.setText(btnText);//设置button上的文字
                }
                if (listener != null) {
                    listener.finish();
                }
            }
        };
    }

    /**
     * 开始倒计时
     */
    public void start() {
        mButton.setEnabled(false);
        countDownTimer.start();
    }

    /**
     * 关闭倒计时,一般onDestroy里会用到
     */
    public void cancel() {
        if (countDownTimer != null) {
            countDownTimer.cancel();
        }
    }

    /**
     * 设置倒计时结束的监听器
     *
     * @param listener
     */
    public void setOnFinishListener(OnFinishListener listener) {
        this.listener = listener;
    }

    /**
     * 计时结束的回调接口(外部要调用所以用public)
     */
    public interface OnFinishListener {
        void finish();
    }

    /**
     * 设置按钮里的文字
     */
    public void setBtnText(String btnText) {
        this.btnText = btnText;
    }
}

在activity中的实现方法参考如下:

import android.content.Context;
import android.content.Intent;
import android.view.View;

import com.hjqjl.whdemo.databinding.ActivityCountDownBinding;
import com.hjqjl.whdemo.utils.CountDownButtonHelper;
import com.hjqjl.whdemo.utils.ToastUtils;

/**
 * 倒计时按钮
 */
public class CountDownActivity extends BaseActivity {
    public static void actionStart(Context context) {
        Intent intent = new Intent(context, CountDownActivity.class);
        context.startActivity(intent);
    }

    private CountDownButtonHelper countDownButtonHelper;
    private ActivityCountDownBinding binding;

    @Override
    protected void initData() {
        binding = ActivityCountDownBinding.inflate(getLayoutInflater());
        View view = binding.getRoot();
        setContentView(view);

        countDownButtonHelper = new CountDownButtonHelper(binding.btnCountDown);
    }

    @Override
    protected void processLogic() {
        binding.btnCountDown.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                countDownButtonHelper.start();
            }
        });
        countDownButtonHelper.setOnFinishListener(new CountDownButtonHelper.OnFinishListener() {
            @Override
            public void finish() {
                ToastUtils.showToast(mContext, "倒计时结束调用");
            }
        });
    }

    @Override
    protected void onDestroy() {
        if (null != countDownButtonHelper) {
            countDownButtonHelper.cancel();
        }
        super.onDestroy();
    }
}

4、利用AlarmManager定时执行任务

需要用到广播

package com.apep.fivefive.utils;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;

import com.apep.fivefive.receiver.ReLaunchAppReceiver;
import com.blankj.utilcode.util.LogUtils;
import com.blankj.utilcode.util.TimeUtils;
import com.blankj.utilcode.util.ToastUtils;

import java.util.Calendar;
import java.util.Random;
import java.util.TimeZone;

/**
 * 2021/7/8 17:05 wh
 */
public class ReLaunchAppUtils {
    public static void reLaunchApp(Context context, String msg) {
        ToastUtils.make().setTextSize(50).setDurationIsLong(true).show("" + msg);
        Intent intent = new Intent(context, ReLaunchAppReceiver.class);
        PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, 0);
        //得到AlarmManager实例
        AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        am.set(AlarmManager.RTC, System.currentTimeMillis() + (1000 * 10), pi);//定时10s之后
    }

    /**
     * 凌晨一定时间内重启
     *
     * @param context 上下文
     */
    public static void reLaunchApp2(Context context) {
        //得到日历实例,主要是为了下面的获取时间
        Calendar mCalendar = Calendar.getInstance();
        mCalendar.setTimeInMillis(System.currentTimeMillis());

        // 这里时区需要设置一下,不然可能个别手机会有8个小时的时间差
        mCalendar.setTimeZone(TimeZone.getTimeZone("GMT+8"));
        //是设置日历的时间,主要是让日历的年月日和当前同步
        mCalendar.setTimeInMillis(System.currentTimeMillis());
        //设置在几点提醒  设置的为点
        int randomH = new Random().nextInt(4);
        mCalendar.set(Calendar.HOUR_OF_DAY, randomH);
        //设置在几分提醒  设置的为0分
        int randomM = new Random().nextInt(60);
        mCalendar.set(Calendar.MINUTE, randomM);
        //下面这两个看字面意思也知道
        int randomS = new Random().nextInt(60);
        mCalendar.set(Calendar.SECOND, randomS);
        //设置下一天
        mCalendar.add(Calendar.DAY_OF_MONTH, 1);

//        ToastUtils.make().setTextSize(50).setDurationIsLong(true).show("" + msg);
		ReLaunchAppReceiver.class为广播接受者
        Intent intent = new Intent(context, ReLaunchAppReceiver.class);
        PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, 0);
        //得到AlarmManager实例
        AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        LogUtils.v(TimeUtils.millis2String(mCalendar.getTimeInMillis()));
         //**********注意!!下面的三个根据实际需求任选其一即可*********

        /*
         * 单次提醒 
         * RTC_WAKEUP 在设备关闭时唤醒设备。
         * RTC 此警报不会唤醒设备;如果它在设备睡眠时关闭,则直到设备下次醒来时才会发送。
         * mCalendar.getTimeInMillis() 上面设置的11点0分的时间点毫秒值
         */
        am.set(AlarmManager.RTC_WAKEUP, mCalendar.getTimeInMillis(), pi);

        /*
         * 重复提醒
         * 第一个参数是警报类型;下面有介绍
         * 第二个参数网上说法不一,很多都是说的是延迟多少毫秒执行这个闹钟,但是我用的刷了MIUI的三星手机的实际效果是与单次提醒的参数一样,即设置的13点25分的时间点毫秒值
         * 第三个参数是重复周期,也就是下次提醒的间隔 毫秒值 我这里是一天后提醒
         */
//        am.setRepeating(AlarmManager.RTC_WAKEUP, mCalendar.getTimeInMillis(), (1000 * 60 * 60 * 24), pi);

        /*
         * 时间要求比set精准(耗能大)
         */
//        am.setExact(AlarmManager.RTC_WAKEUP, mCalendar.getTimeInMillis(), pi);
    }
    
	/**
	  * 关闭定时
	  */
	 private void stopRemind(Context context){
	     Intent intent = new Intent(context, ReLaunchAppReceiver .class);
	     PendingIntent pi = PendingIntent.getBroadcast(context, 0,
	             intent, 0);
	     AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);
	     //取消警报
	     am.cancel(pi);
	     Toast.makeText(this, "关闭了提醒", Toast.LENGTH_SHORT).show();
	 }
}

广播ReLaunchAppReceiver 不要忘记在AndroidManifest.xml中配置

public class ReLaunchAppReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        //当系统到我们设定的时间点的时候会发送广播,执行这里
        LogUtils.e("ReLaunchReceiver");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值