2

I have a function function(). How can I ensure, when the function is called multiple times, that it would run one after another, and not concurrently? I am using Kotlin 1.3 in Android Studio 3.5.

My code is

 button.setOnClickListener{function()}

The problem is, the button can be pressed multiple times while the function() is still running, hence I want the subsequent invocations of function() to be executed sequentially, one after another, instead of at the same time.

EDIT: My function definition is

fun function(){
    image.animate().rotationBy(360F).setDuration(500)
}

The user could press the button more than once, hence the result is that the image(image) gets rotated to an angle, as the image is being rotated again while it did not complete the full rotation, ending up being rotated at another angle instead of 0°.

LCZ
  • 589
  • 1
  • 9
  • 15
  • 1
    Hey there, what do you mean by **not concurrently**? Could you explain more and could you paste some code on what you have done so far? – ravi Oct 14 '19 at 04:31
  • Ok. My code is ```button.setOnClickListener{function()}```. The problem is, the button can be pressed multiple times while the ```function()``` is still running, hence I want the subsequent invocations of ```function()``` to be executed sequentially, one after another, instead of at the same time. – LCZ Oct 14 '19 at 05:14
  • 2
    you can use the button.setEnabled(false) at the beginning of function and at the end of function button.setEnabled(true).In that way, it will only allow the user to click the button only when your function has finished the job. Or if you still want the click event to be clicked then use @Synchronized before the method or synchronized(this){} inside the function based on your need – Naval Kishor Jha Oct 14 '19 at 06:28
  • if long-running operation is there then Call your function inside an AyncTask{doInbackground(){}} call the AsyncTask on the button clicked also keep the record and removed it once done or cancel the task when activity gets destroy to release the resources...or use intentservice, Please elaborate your question with more content for a better answer. – Naval Kishor Jha Oct 14 '19 at 06:54
  • @LCZ Could you also paste the function definition here? – ravi Oct 15 '19 at 10:38

4 Answers4

1

The @Synchronized annotation does exactly what you want:

@Synchronized
private fun function() {
    //...
}
Mousa
  • 2,190
  • 3
  • 21
  • 34
0

Take a Boolean as hasRan = false

And when you call the function, check if the hasRan is false, and at the end of the function set hasRan = true, execute the function only if the value of hasRan is false.

This way the function will only run once.

Jaswant Singh
  • 9,900
  • 8
  • 29
  • 50
  • This approach will ignore consecutive calls. The OP wants them to be queued and called one after another. – Mousa Oct 14 '19 at 06:53
0

I'd suggest WorkManager (especially if the function is some long running async job) to enqueue a job.

  1. Add it to gradle:
implementation "androidx.work:work-runtime-ktx:2.2.0"
  1. Create the class containing your method (function)
class Task(appContext: Context, workerParams: WorkerParameters) : Worker(appContext, workerParams) {

    override fun doWork(): Result {
        //Call the function
        return Result.success()
    }
}
  1. Create a job with parameters:
val uploadWorkRequest = OneTimeWorkRequestBuilder<Task>()
.build()
  1. Enqueue the job on button click:
WorkManager.getInstance(myContext).enqueue(uploadWorkRequest)
Simon
  • 1,657
  • 11
  • 16
-1

You can call this function only from an IntentService. The IntentService offloads task from the main thread and runs them over a Worker Thread. The tasks in Worker Thread are executed sequentially.

class SampleIntentService(): IntentService("SampleIntentService") {
override fun onHandleIntent(intent: Intent?) {
//TODO call function() here
 }
}

You can start this service using startService() method.

Sushant Somani
  • 1,450
  • 3
  • 13
  • 31