这周接到个新需求,核算用户在线时长,累积到必定时长后上报,可以经过计时器来完结。本篇文章介绍下安卓端完结计时器的三种方式。

Timer、TimerTask

经过TimerTimerTask完结计时,代码如下:

class TimeChangeExample : BaseGestureDetectorActivity() {
    private lateinit var binding: LayoutTimeChangeExampleActivityBinding
    private val dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS")
    private var timerHandler = object : Handler(Looper.myLooper() ?: Looper.getMainLooper()) {
        override fun handleMessage(msg: Message) {
            super.handleMessage(msg)
            if (msg.what == 0) {
                setCountdownTimeText(msg.obj as Long)
            }
        }
    }
    private var timer: Timer? = null
    private var timerTask: TimerTask? = null
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.setContentView(this, R.layout.layout_time_change_example_activity)
        binding.btnCountdownByTimer.setOnClickListener {
            clearText()
            binding.tvCountdownText.text = "countdown by timer\n"
            startCountdownByTime()
        }
        binding.btnStopTimer.setOnClickListener {
            stopTimer()
        }
    }
    private fun startCountdownByTime() {
        stopTimer()
        timerTask = object : TimerTask() {
            override fun run() {
                timerHandler.sendMessage(timerHandler.obtainMessage(0, System.currentTimeMillis()))
            }
        }
        timer = Timer()
        timer?.schedule(timerTask, 0, 1000)
    }
    private fun stopTimer() {
        timer?.cancel()
        timer = null
        timerTask = null
    }
    private fun setCountdownTimeText(time: Long) {
        binding.tvCountdownText.run {
            post {
                text = text.toString() + "${dateFormat.format(Date(time))}\n"
            }
        }
    }
    private fun clearText() {
        binding.tvCountdownText.text = ""
    }
    override fun onDestroy() {
        super.onDestroy()
        stopTimer()
    }
}

作用如图:

两次计时之间的差错都是毫秒级的。

Android 完结计时器

BroadCastReceiver

经过注册广播,监听系统时刻改动完结计时,可是广播回调触发的间隔固定为一分钟,代码如下:

class TimeChangeExample : BaseGestureDetectorActivity() {
    private lateinit var binding: LayoutTimeChangeExampleActivityBinding
    private val dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS")
    private val timeChangeBroadcastReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            if (intent?.action == Intent.ACTION_TIME_TICK) {
                setCountdownTimeText(System.currentTimeMillis())
            }
        }
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.setContentView(this, R.layout.layout_time_change_example_activity)
        binding.btnCountdownByBroadcast.setOnClickListener {
            clearText()
            binding.tvCountdownText.text = "countdown by broadcast\n"
            startCountdownByBroadcast()
        }
        binding.btnStopBroadcast.setOnClickListener {
            stopBroadcast()
        }
    }
    private fun startCountdownByBroadcast() {
        registerReceiver(timeChangeBroadcastReceiver, IntentFilter().apply {
            addAction(Intent.ACTION_TIME_TICK)
        })
    }
    private fun stopBroadcast() {
        unregisterReceiver(timeChangeBroadcastReceiver)
    }
    private fun setCountdownTimeText(time: Long) {
        binding.tvCountdownText.run {
            post {
                text = text.toString() + "${dateFormat.format(Date(time))}\n"
            }
        }
    }
    private fun clearText() {
        binding.tvCountdownText.text = ""
    }
    override fun onDestroy() {
        super.onDestroy()
        stopBroadcast()
    }
}

作用如图:

两次计时之间的差错都是毫秒级的。

Android 完结计时器

Handler

经过HandlerRunnable来完结计时,代码如下:

class TimeChangeExample : BaseGestureDetectorActivity() {
    private lateinit var binding: LayoutTimeChangeExampleActivityBinding
    private val dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.setContentView(this, R.layout.layout_time_change_example_activity)
        binding.btnCountdownByHandler.setOnClickListener {
            clearText()
            binding.tvCountdownText.text = "countdown by handler\n"
            startCountdownByHandler()
        }
        binding.btnStopHandler.setOnClickListener {
            stopHandler()
        }
    }
    private val handler = Handler(Looper.myLooper() ?: Looper.getMainLooper())
    private val countdownRunnable = object : Runnable {
        override fun run() {
            setCountdownTimeText(System.currentTimeMillis())
            val currentTime = SystemClock.uptimeMillis()
            val nextTime = currentTime + (1000 - currentTime % 1000)
            handler.postAtTime(this, nextTime)
        }
    }
    private fun startCountdownByHandler() {
        val currentTime = SystemClock.uptimeMillis()
        val nextTime = currentTime + (1000 - currentTime % 1000)
        handler.postAtTime(countdownRunnable, nextTime)
    }
    private fun stopHandler() {
        handler.removeCallbacks(countdownRunnable)
    }
    private fun setCountdownTimeText(time: Long) {
        binding.tvCountdownText.run {
            post {
                text = text.toString() + "${dateFormat.format(Date(time))}\n"
            }
        }
    }
    private fun clearText() {
        binding.tvCountdownText.text = ""
    }
    override fun onDestroy() {
        super.onDestroy()
        stopHandler()
    }
}

作用如图:

两次计时之间的差错都是毫秒级的。

Android 完结计时器

示例

在示例Demo中添加了相关的演示代码。

ExampleDemo github

ExampleDemo gitee