Android超简单实现验证码倒计时,页面关闭不中断,杀掉进程也不中断

在日常开发中,获取验证码是一个常见的功能,通常验证码倒计时的实现思路都是使用CountDownTimer来实现,但是存在一个问题就是当页面关闭之后重新进入页面,倒计时是不会继续进行的,如果后端验证码接口做了时间限制,那么我们再次请求的时候就会报错,用户体验不好。
作为一名CV工程师,在一番百度之后,唯一找到的一个实现方案还需要花钱下载,哎。。。无奈只能自己想了。

实现思路

其实实现思路很简单,使用CountDownTimer进行倒计时,在开始倒计时的时候,把 当前时间+倒计时总时间 持久化存储,再次打开页面的时候判断一下当前时间是否在倒计时时间的范围内,如果在就继续倒计时。

效果如下

在这里插入图片描述

倒计时工具类

持久化存储我使用了腾讯的MMKV,当前你也可以使用SharedPreference
如果你使用的也是MMKV,别忘了在Application中初始化

package com.lzk.jetpacktest.code

import android.os.CountDownTimer
import com.tencent.mmkv.MMKV

/**
 * @Author: LiaoZhongKai
 * @Date: 2021/8/17 16:38
 * @Description: 验证码倒计时工具类
 */
object CodeCountDownUtil {
    private const val KEY_TIME = "TotalTimeMills"
    private val mMkv: MMKV = MMKV.mmkvWithID("CodeCountDownUtil")
    private var mTotalTimeMills = 0L
    private var mListener: OnCountDownListener? = null

    private val mCountDownTimer: CountDownTimer
        get() {
            return object : CountDownTimer(getCountTimeMills(),1000){
                override fun onTick(millisUntilFinished: Long) {
                    mListener?.onTick(millisUntilFinished/1000)
                }

                override fun onFinish() {
                    mListener?.onFinish()
                }

            }
        }

    /**
     * 开始倒计时
     * [totalTimeMills] 倒计时时间毫秒值
     */
    fun start(totalTimeMills: Long){
        mTotalTimeMills = totalTimeMills+System.currentTimeMillis()
        mMkv.encode(KEY_TIME, mTotalTimeMills)
        mCountDownTimer.start()
    }

    /**
     * 继续倒计时
     */
    fun continueCount(){
        mCountDownTimer.start()
    }

    /**
     * 取消倒计时
     */
    fun cancel(){
        mCountDownTimer.cancel()
    }

    /**
     * 获取当前的倒计时时间毫秒值
     */
    fun getCountTimeMills(): Long{
        mTotalTimeMills = mMkv.decodeLong(KEY_TIME)
        return mTotalTimeMills - System.currentTimeMillis()
    }

    /**
     * 当前时间是否在倒计时范围内
     * @return true: 倒计时正在进行 false:倒计时未进行
     */
    fun isCounting(): Boolean{
        mTotalTimeMills = mMkv.decodeLong(KEY_TIME)
        return System.currentTimeMillis() < mTotalTimeMills
    }

    /**
     * 设置监听器
     */
    fun setOnCountDownListener(listener: OnCountDownListener){
        mListener = listener
    }

    interface OnCountDownListener{
        /**
         * 倒计时
         * [seconds] 倒计时剩余时间,秒为单位
         */
        fun onTick(seconds: Long)

        /**
         * 倒计时结束
         */
        fun onFinish()
    }
}
复制代码

使用示例

package com.lzk.jetpacktest.code

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import androidx.databinding.DataBindingUtil
import com.lzk.jetpacktest.R
import com.lzk.jetpacktest.databinding.ActivityVerificationCodeBinding

/**
 * @Author: LiaoZhongKai
 * @Date: 2021/8/18 9:22
 * @Description: 验证码页面
 */
class VerificationCodeActivity : AppCompatActivity() {

    companion object{
    	//验证码倒计时总时间
    	//60秒
        private const val COUNT_DOWN_TIME = 60*1000L
    }

    private lateinit var mBinding: ActivityVerificationCodeBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        mBinding = DataBindingUtil.setContentView(this,R.layout.activity_verification_code)
        initView()
        initEvent()
    }

    //千万不要忘记在onDestroy中取消倒计时
    //千万不要忘记在onDestroy中取消倒计时
    //千万不要忘记在onDestroy中取消倒计时
    override fun onDestroy() {
        super.onDestroy()
        CodeCountDownUtil.cancel()
    }

    private fun initView(){
        //如果当前时间仍在倒计时范围内,则显示倒计时
        if (CodeCountDownUtil.isCounting()){
            CodeCountDownUtil.continueCount()
            mBinding.btn.isEnabled = false
        }else{//否则显示获取验证码
            mBinding.btn.text = "获取验证码"
        }
    }

    private fun initEvent(){
        //设置监听器
        CodeCountDownUtil.setOnCountDownListener(object : CodeCountDownUtil.OnCountDownListener{
            override fun onTick(seconds: Long) {
                mBinding.btn.text = "$seconds 秒后重新获取"
            }

            override fun onFinish() {
                mBinding.btn.isEnabled = true
                mBinding.btn.text = "获取验证码"
            }

        })

        //获取验证码按钮
        mBinding.btn.setOnClickListener {
            //模拟验证码发送成功
            Toast.makeText(this,"验证码已发送",Toast.LENGTH_SHORT).show()
            //按照正常流程,以下代码应该在验证码发送成功之后再调用
            //开始倒计时
            CodeCountDownUtil.start(COUNT_DOWN_TIME)
            mBinding.btn.isEnabled = false
        }
    }

}
复制代码
xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>

    </data>

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".code.VerificationCodeActivity">

        <Button
            android:id="@+id/btn"
            android:layout_width="150dp"
            android:layout_height="50dp"
            android:layout_gravity="center"
            android:text="获取验证码" />
    </FrameLayout>
</layout>
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享