- How to set a timer in Android using Kotlin?
- Example
- example
- Example
- How to make a Countdown Timer in Android using Kotlin
- Make a Timer App: Countdown Timer (Ep 2) – Android Kotlin Tutorial (Code)
- You can also check out this GitHub repository: https://github.com/ResoCoder/TimerAppAndroidTutorial
- TimerActivity.kt
- PrefUtil.kt
- Count down timer with Kotlin Coroutines Flow
- A simple alternative to having android independent code
- Preface
- The Problem
- Stop!
- Solution
- First step
How to set a timer in Android using Kotlin?
This example demonstrates how to set a timer in Android using Kotlin.
Step 1 − Create a new project in Android Studio, go to File ? New Project and fill all required details to create a new project.
Step 2 − Add the following code to res/layout/activity_main.xml.
Example
Step 3 − Add the following code to src/MainActivity.kt
example
import android.os.Bundle import android.os.CountDownTimer import android.view.View import android.widget.TextView import androidx.appcompat.app.AppCompatActivity class MainActivity : AppCompatActivity() < var counter = 0 override fun onCreate(savedInstanceState: Bundle?) < super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) title = "KotlinApp" >fun startTimeCounter(view: View) < val countTime: TextView = findViewById(R.id.countTime) object : CountDownTimer(50000, 1000) < override fun onTick(millisUntilFinished: Long) < countTime.text = counter.toString() counter++ >override fun onFinish() < countTime.text = "Finished" >>.start() > >
Step 4 − Add the following code to androidManifest.xml
Example
Let’s try to run your application. I assume you have connected your actual Android Mobile device with your computer. To run the app from android studio, open one of your project’s activity files and click the Run icon from the toolbar. Select your mobile device as an option and then check your mobile device which will display your default screen
How to make a Countdown Timer in Android using Kotlin
Today, I will show you how to build a timer that countdowns until an event (e.g. new year’s day or the release date of a video game) using the Handler to update the TextView every second.
First, add a TextView in your layout, like that:
RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/colorPrimaryDark" tools:context=".MainActivity"> TextView android:id="@+id/countdown_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:text="10d 7h 15m 15s" android:textColor="@android:color/white" android:textSize="30sp" android:textStyle="bold" />
RelativeLayout>Code language: HTML, XML (xml)
Then go to your Activity and create a method with a name updateTime() and set the current date:
fun updateTime() < // Set Current Date val currentDate = Calendar.getInstance() >
Code language: Kotlin (kotlin)
fun updateTime() < // . // Set Event Date val eventDate = Calendar.getInstance() eventDate[Calendar.YEAR] = 2023 eventDate[Calendar.MONTH] = 0 // 0-11 so 1 less eventDate[Calendar.DAY_OF_MONTH] = 1 eventDate[Calendar.HOUR] = 0 eventDate[Calendar.MINUTE] = 0 eventDate[Calendar.SECOND] = 0 eventDate.timeZone = TimeZone.getTimeZone("GMT") // . >
Code language: Kotlin (kotlin)
Find how many milliseconds left until the event
fun updateTime() < // . // Find how many milliseconds until the event val diff = eventDate.timeInMillis - currentDate.timeInMillis // . >
Code language: Kotlin (kotlin)
Convert the milliseconds to days, hours, minutes, and seconds
fun updateTime() < // . // Change the milliseconds to days, hours, minutes and seconds val days = diff / (24 * 60 * 60 * 1000) val hours = diff / (1000 * 60 * 60) % 24 val minutes = diff / (1000 * 60) % 60 val seconds = (diff / 1000) % 60 // . >
Code language: Kotlin (kotlin)
Show the countdown timer in your TextView
fun updateTime() < // . // Display Countdown countdownText.text = "$ d $ h $ m $ s" // . >
Code language: Kotlin (kotlin)
Now, to call the updateTime() method every second, we’re going to use the Handler() class and repeat the handler every second (1000 milliseconds)
private lateinit var countdownText: TextView private val handler = Handler(Looper.getMainLooper()) override fun onCreate(savedInstanceState: Bundle?) < super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) countdownText = findViewById(R.id.countdown_text) // Update TextView every second handler.post(object : Runnable < override fun run() < // Keep the postDelayed before the updateTime(), so when the event ends, the handler will stop too. handler.postDelayed(this, 1000) updateTime() > >) >
Code language: Kotlin (kotlin)
If you want to show different text after the event has passed, create a method with the name endEvent and pass the currentDate and eventDate.
After you have shown your text, stop the handler from repeating it.
fun updateTime() < // . // Show different text when the event has passed endEvent(currentDate, eventDate) > private fun endEvent(currentDate: Calendar, eventDate: Calendar) < if (currentDate.time >= eventDate.time) < countdownText.text = "Happy New Year!" // Stop Handler handler.removeMessages(0) > >
Code language: Kotlin (kotlin)
If you have any questions, please feel free to leave a comment below
Make a Timer App: Countdown Timer (Ep 2) – Android Kotlin Tutorial (Code)
Learn how to create a beautiful material design timer app for Android.
In this course you will learn how to make a user interface. Later we’re going to code a timer which can run in the foreground. Then we are going to upgrade it to be able to run also in the background – and we will control it from notifications! Finally we will create a settings activity where a user will be able to set the length of the timer.
In the second part we’re coding the actual timer (CountdownTimer) which can run in the foreground. We’re also using shared preferences to persistently store certain data like timer length or seconds remaining.
This post contains all the code that’s been written in this YouTube video.
You can also check out this GitHub repository: https://github.com/ResoCoder/TimerAppAndroidTutorial
TimerActivity.kt
package com.resocoder.timertutorial import android.os.Bundle import android.os.CountDownTimer import android.support.design.widget.Snackbar import android.support.v7.app.AppCompatActivity import android.view.Menu import android.view.MenuItem import com.resocoder.timertutorial.util.PrefUtil import kotlinx.android.synthetic.main.activity_timer.* import kotlinx.android.synthetic.main.content_timer.* class TimerActivity : AppCompatActivity() < enum class TimerState< Stopped, Paused, Running >private lateinit var timer: CountDownTimer private var timerLengthSeconds: Long = 0 private var timerState = TimerState.Stopped private var secondsRemaining: Long = 0 override fun onCreate(savedInstanceState: Bundle?) < super.onCreate(savedInstanceState) setContentView(R.layout.activity_timer) setSupportActionBar(toolbar) supportActionBar?.setIcon(R.drawable.ic_timer) supportActionBar?.title = " Timer" fab_start.setOnClickListenerstartTimer() timerState = TimerState.Running updateButtons() > fab_pause.setOnClickListener < v ->timer.cancel() timerState = TimerState.Paused updateButtons() > fab_stop.setOnClickListener < v ->timer.cancel() onTimerFinished() > > override fun onResume() < super.onResume() initTimer() //TODO: remove background timer, hide notification >override fun onPause() < super.onPause() if (timerState == TimerState.Running)< timer.cancel() //TODO: start background timer and show notification >else if (timerState == TimerState.Paused) < //TODO: show notification >PrefUtil.setPreviousTimerLengthSeconds(timerLengthSeconds, this) PrefUtil.setSecondsRemaining(secondsRemaining, this) PrefUtil.setTimerState(timerState, this) > private fun initTimer() < timerState = PrefUtil.getTimerState(this) //we don't want to change the length of the timer which is already running //if the length was changed in settings while it was backgrounded if (timerState == TimerState.Stopped) setNewTimerLength() else setPreviousTimerLength() secondsRemaining = if (timerState == TimerState.Running || timerState == TimerState.Paused) PrefUtil.getSecondsRemaining(this) else timerLengthSeconds //TODO: change secondsRemaining according to where the background timer stopped //resume where we left off if (timerState == TimerState.Running) startTimer() updateButtons() updateCountdownUI() >private fun onTimerFinished() < timerState = TimerState.Stopped //set the length of the timer to be the one set in SettingsActivity //if the length was changed when the timer was running setNewTimerLength() progress_countdown.progress = 0 PrefUtil.setSecondsRemaining(timerLengthSeconds, this) secondsRemaining = timerLengthSeconds updateButtons() updateCountdownUI() >private fun startTimer() < timerState = TimerState.Running timer = object : CountDownTimer(secondsRemaining * 1000, 1000) < override fun onFinish() = onTimerFinished() override fun onTick(millisUntilFinished: Long) < secondsRemaining = millisUntilFinished / 1000 updateCountdownUI() >>.start() > private fun setNewTimerLength() < val lengthInMinutes = PrefUtil.getTimerLength(this) timerLengthSeconds = (lengthInMinutes * 60L) progress_countdown.max = timerLengthSeconds.toInt() >private fun setPreviousTimerLength() < timerLengthSeconds = PrefUtil.getPreviousTimerLengthSeconds(this) progress_countdown.max = timerLengthSeconds.toInt() >private fun updateCountdownUI()< val minutesUntilFinished = secondsRemaining / 60 val secondsInMinuteUntilFinished = secondsRemaining - minutesUntilFinished * 60 val secondsStr = secondsInMinuteUntilFinished.toString() textView_countdown.text = "$minutesUntilFinished:$" progress_countdown.progress = (timerLengthSeconds - secondsRemaining).toInt() > private fun updateButtons()< when (timerState) < TimerState.Running -> < fab_start.isEnabled = false fab_pause.isEnabled = true fab_stop.isEnabled = true >TimerState.Stopped -> < fab_start.isEnabled = true fab_pause.isEnabled = false fab_stop.isEnabled = false >TimerState.Paused -> < fab_start.isEnabled = true fab_pause.isEnabled = false fab_stop.isEnabled = true >> > override fun onCreateOptionsMenu(menu: Menu): Boolean < // Inflate the menu; this adds items to the action bar if it is present. menuInflater.inflate(R.menu.menu_timer, menu) return true >override fun onOptionsItemSelected(item: MenuItem): Boolean < // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. return when (item.itemId) < R.id.action_settings ->true else -> super.onOptionsItemSelected(item) > > >
PrefUtil.kt
package com.resocoder.timertutorial.util import android.content.Context import android.preference.PreferenceManager import com.resocoder.timertutorial.TimerActivity class PrefUtil < companion object < fun getTimerLength(context: Context): Int< //placeholder return 1 >private const val PREVIOUS_TIMER_LENGTH_SECONDS_ID = "com.resocoder.timer.previous_timer_length_seconds" fun getPreviousTimerLengthSeconds(context: Context): Long < val preferences = PreferenceManager.getDefaultSharedPreferences(context) return preferences.getLong(PREVIOUS_TIMER_LENGTH_SECONDS_ID, 0) >fun setPreviousTimerLengthSeconds(seconds: Long, context: Context) < val editor = PreferenceManager.getDefaultSharedPreferences(context).edit() editor.putLong(PREVIOUS_TIMER_LENGTH_SECONDS_ID, seconds) editor.apply() >private const val TIMER_STATE_ID = "com.resocoder.timer.timer_state" fun getTimerState(context: Context): TimerActivity.TimerState < val preferences = PreferenceManager.getDefaultSharedPreferences(context) val ordinal = preferences.getInt(TIMER_STATE_ID, 0) return TimerActivity.TimerState.values()[ordinal] >fun setTimerState(state: TimerActivity.TimerState, context: Context) < val editor = PreferenceManager.getDefaultSharedPreferences(context).edit() val ordinal = state.ordinal editor.putInt(TIMER_STATE_ID, ordinal) editor.apply() >private const val SECONDS_REMAINING_ID = "com.resocoder.timer.seconds_remaining" fun getSecondsRemaining(context: Context): Long < val preferences = PreferenceManager.getDefaultSharedPreferences(context) return preferences.getLong(SECONDS_REMAINING_ID, 0) >fun setSecondsRemaining(seconds: Long, context: Context) < val editor = PreferenceManager.getDefaultSharedPreferences(context).edit() editor.putLong(SECONDS_REMAINING_ID, seconds) editor.apply() >> >
Count down timer with Kotlin Coroutines Flow
A simple alternative to having android independent code
Preface
In the last project, we used coroutines as a way of doing asynchronous jobs. We started at the beginning of 2019 and back then Kotlin Flow as the whole Channels were experimental feature.
But our goal was to move onto coroutines and minimize places without it:
We wanted to move everything to the coroutines ideally.
As I said back then we didn’t want to use experimental Channels/Flows, so we migrated only the Callbacks section to coroutines, but the places with Rx we replaced with our own Rx-Lite Super Awesome library (maybe I will tell about it in the next article if you want please let me know in the comments). And our version of Rx as turned out was really similar to Flows in some ways which gave us a possibility of easy migration in the future.
We started to inject flows into our project in 2020. At this point, we already had an agreement about unit tests and about code structure and style. By our agreements, we wanted to avoid using Android in our unit tests and we wanted to minimize using Robolectric library for them, we wanted to have pure Kotlin logic tests.
The Problem
We had places that used timers. Specifically, count down timer. Those places we part of either business or presentation logic and, thus, should be tested. But most importantly, Android’s count-down timer provided the callback way of reacting to the timer’s updates. We wanted to have coroutines. In this scenario, Flow was the most attractive possibility.
Of course, we could build some wrappers. But to convert callback-approach to the flow approach you can spend some time and this conversion can be by the complexity be the same as if we will create just our own CountDownFlow . Pure kotlin (well, almost), pure coroutines, no Android timer callbacks at all.
Stop!
“What about built-in mechanisms in coroutines-flow?” you say. Indeed, if we will look into the library we will find an interesting method ticker which seems to do what we need. The only tiny silly problem is that it marked as @ObsoleteCoroutinesApi which means that the API will be adapted and changed in the future possibly (and also it uses System time instead of SystemClock which is also important, since the first can be altered by the time settings on your device).
Since this task was not so hard for us (we building the solution for only one project, not for the entire programming community), we decided to build something custom and in the future just replace it with what the Kotlin team will offer. Fair deal, I think.
Solution
First step
Lets first build the interface and the general usage structure, which will be available as API for other classes or entities:
If you liked that article, don’t forget to support me by clapping. If you want to support me more, just subscribe to my blog and keep an eye on new articles. Also, if you have any questions, comment me, and let’s have a discussion. Happy coding!
Also, there are other articles, that can be interesting: