How to call a function after delay in Kotlin?
You can use Schedule
inline fun Timer.schedule(
delay: Long,
crossinline action: TimerTask.() -> Unit
): TimerTask (source)
example (thanks @Nguyen Minh Binh - found it here: http://jamie.mccrindle.org/2013/02/exploring-kotlin-standard-library-part-3.html)
import java.util.Timer
import kotlin.concurrent.schedule
Timer("SettingUp", false).schedule(500) {
doSomething()
}
How to set delay in Kotlin?
there are some ways:
1- use Handler(base on mili-second)(Deprecated):
println("hello")
Handler().postDelayed({
println("world")
}, 2000)
2- by using Executors(base on second):
println("hello")
Executors.newSingleThreadScheduledExecutor().schedule({
println("world")
}, 2, TimeUnit.SECONDS)
3- by using Timer(base on mili-second):
println("hello")
Timer().schedule(2000) {
println("world")
}
How to call a method after a delay in Android
Kotlin
Handler(Looper.getMainLooper()).postDelayed({
//Do something after 100ms
}, 100)
Java
final Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
@Override
public void run() {
//Do something after 100ms
}
}, 100);
Kotlin: call a function every second
Problem: Timer class uses a background thread with a queue to queue and execute all tasks sequentially. From your code, because you update UI (changing TextView content in minusOneSecond
function). That why the app throws the following exception and make your app crash.
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the
original thread that created a view hierarchy can touch its views.
Solution: There are many ways to achieve your task, but I prefer using post() and postDelayed() method from Handler class. Because it's simple and easy to understand.
val mainHandler = Handler(Looper.getMainLooper())
mainHandler.post(object : Runnable {
override fun run() {
minusOneSecond()
mainHandler.postDelayed(this, 1000)
}
})
Update: From author's comment about how to pause/resume the task from Handler. Here is an example.
class MainActivityKt : AppCompatActivity() {
lateinit var mainHandler: Handler
private val updateTextTask = object : Runnable {
override fun run() {
minusOneSecond()
mainHandler.postDelayed(this, 1000)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Your logic code
...
mainHandler = Handler(Looper.getMainLooper())
}
override fun onPause() {
super.onPause()
mainHandler.removeCallbacks(updateTextTask)
}
override fun onResume() {
super.onResume()
mainHandler.post(updateTextTask)
}
fun minusOneSecond() {
if secondsLeft > 0 {
secondsLeft -= 1
seconds_thegame.text = secondsLeft.toString()
}
}
}
I want to Stop my function to execute, which is written in post delay, whenever I interrupt it with textChangedListner In Kotlin
Best way to use coroutines for such a case in kotlin.
If you don't know coroutines or don't want to use it. Then you can use Timer.
private Timer timer = new Timer();
private final long DELAY = 500; // Milliseconds
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int){
timer.cancel();
timer = new Timer();
timer.schedule(
new TimerTask() {
@Override
public void run() {
// TODO: Do what you need here.
val lengthoftext = searchCompany.text.length
mycompanies.clear()
callforapi(s.toString())
}
},
DELAY
);
}
}
}
Android Kotlin Coroutines - Call Api Every X Seconds on Background
You could add a loop with a delay in your use case:
class GetCoinsUseCase @Inject constructor(
private val repository: CoinRepository
) {
operator fun invoke(): Flow<Resource<List<Coin>>> = flow {
while (currentCoroutineContext().isActive) {
try {
emit(Resource.Loading<List<Coin>>())
val coins = repository.getCoins().map { it.toCoin() }
emit(Resource.Success<List<Coin>>(coins))
} catch(e: HttpException) {
emit(Resource.Error<List<Coin>>(e.localizedMessage ?: "An unexpected error occured"))
} catch(e: IOException){
emit(Resource.Error<List<Coin>>("Couldn't reach to server. Check your internet connection."))
}
// Wait until next request
delay(3000)
}
}
}
You could also move the loop and delay call around depending on the precise functionality you are looking for. For example, to stop once there is an error you could do
class GetCoinsUseCase @Inject constructor(
private val repository: CoinRepository
) {
operator fun invoke(): Flow<Resource<List<Coin>>> = flow {
emit(Resource.Loading<List<Coin>>())
try {
while (currentCoroutineContext().isActive) {
val coins = repository.getCoins().map { it.toCoin() }
emit(Resource.Success<List<Coin>>(coins))
// Wait until next request
delay(3000)
}
} catch(e: HttpException) {
emit(Resource.Error<List<Coin>>(e.localizedMessage ?: "An unexpected error occured"))
} catch(e: IOException){
emit(Resource.Error<List<Coin>>("Couldn't reach to server. Check your internet connection."))
}
}
}
This should already naturally "run in the background" as long as your app is running and you are not cancelling the coroutine manually when going in the background.
Trying to execute line after delay in Android Studio with Kotlin
Doing this way, you're asking to display 5 strings but with the same delay.
To my mind, you have to use a CountDownTimer to display another piece of text following a regular interval.
Here is a sample code
class Ball (val Ball: TextView, val messagesList: List<String>){
private var index = 0
fun textChange(interval: Long) {
val time = interval * messagesList.size
val timer = object: CountDownTimer(time, interval) {
override fun onTick(millisUntilFinished: Long) {
Ball.append(" " +messagesList[index++])
}
override fun onFinish() {
//nothing to do
}
}
timer.start()
}
}
class MainActivity : AppCompatActivity() {
var messageList = mutableListOf<String>("Hello", "World", "How are you ?")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
fun playButtonPressed(view:View){
// will update the text every second during until the list is empty
Ball(textView, messageList).textChange(1000)
}
}
cancelling a suspend function in kotlin if the same function is called again
This kind of event processing is usually handled using reactive streams and is often named the debounce operator. It exists in both ReactiveX (Debounce) and in Kotlin flows (debounce()).
As you already use coroutines, I suggest going with Kotlin flows. Please see the example below:
private val flow = MutableStateFlow(0)
suspend fun main() = coroutineScope {
launch {
// consumer of events
flow
.debounce(2.seconds)
.collect { println(it) }
}
// producer
delay(100)
addCounter() // 1
delay(500)
addCounter() // 2, ignore 1
delay(500)
addCounter() // 3, ignore 2
delay(2500) // show 3
addCounter() // 4
delay(500)
addCounter() // 5, ignore 4
delay(3000) // show 5
}
fun addCounter() {
flow.value++
}
It shows only 3
and 5
, because all other events were "cancelled" by subsequent events that came too fast.
Related Topics
How to Set Cursor Position in Edittext
Expandable List with Recyclerview
Android Studio: Drawable Folder: How to Put Images for Multiple Dpi
Webview Showing Err_Cleartext_Not_Permitted Although Site Is Https
What Are the Differences Between Activity and Fragment
Navigationview Menu Items with Counter on the Right
How to Get Images Dynamically from Drawable Folder
How to Create an Android Library Jar with Gradle Without Publicly Revealing Source Code
Android Studio: Cannot Recover Key
Example: Android Bi-Directional Network Socket Using Asynctask
Custom Seekbar (Thumb Size, Color and Background)
Android Permissions: Phone Calls: Read Phone State and Identity
How to Log Request and Response Body with Retrofit-Android
How to Draw Text with a Border on a Mapview in Android
Action_View Intent for a File with Unknown Mimetype