Reputation: 171
I am trying to code in kotlin android to move an image every second but I am not able to make it work. Right now I'm using a Timer
to schecule a Timer Task
every second but it is not working as expected.
Here is my code
class Actvt_Image<float> : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_actvt__image)
val pict_mario = findViewById<ImageView>(R.id.img_Mario)
val bt_down = findViewById<Button>(R.id.bt_down)
val frame = findViewById<LinearLayout>(R.id.frame)
val txt1=findViewById<TextView>(R.id.txt1)
var i =100
val timer = Timer()
val myTask = object : TimerTask() {
override fun run() {
txt1.text = (i+1).toString()
img_Mario.rotation=180f
img_Mario.translationX +=100
img_Mario.translationY +=20
}
}
bt_down.setOnClickListener {
i=0
timer.schedule(myTask, 1000, 1000)
}
}
}
Upvotes: 4
Views: 2980
Reputation: 2126
You are trying to update the UI on a background thread which is not possible. UI can only be updated on the UI thread. Also, using a Timer
and TimerTask
to create and destroy a thread every 1 second is not the right way to use threads because creating a thread is a memory expensive operation.
What you need to do is to use a Handler
and tell the UI Thread
to run a Runnable
after every desired interval. Remove Timer
and TimerTask
and use the following
val handler = Handler(Looper.getMainLooper())
handler.post(object : Runnable {
override fun run() {
txt1.text = (i+1).toString()
img_Mario.rotation=180f
img_Mario.translationX +=100
img_Mario.translationY +=20
handler.postDelayed(this, 1000)
}
})
Above code is using a handler and posting a task to the UI Thread message queue. The task itself is updating the UI and posting itself again to the UI Thread message queue using the same handler but this time after 1 second delay using the handler.postDelayed()
methond
EDIT : How to stop runnable
If you want to stop a specific runnable
you can use the following method and pass in the same runnable
object that you passed in handler.post()
. Surely you have to keep a reference to the runnable
at all time to stop it. The above code doesn't keep a reference. See the Complete code below.
handler.removeCallbacks(runnable) //stops a specific runnable
To stop all remaining callbacks or runnable
from the UI Thread message queue use this
handler.removeCallbacksAndMessages(null) //stops any pending callback in message queue
Complete code
NOTE: I have added a stop button click listener as an addition
class Actvt_Image<float> : AppCompatActivity() {
private lateinit var handler : Handler
private lateinit var runnable : Runnable // reference to the runnable object
private var i = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_actvt__image)
val pict_mario = findViewById<ImageView>(R.id.img_Mario)
val bt_down = findViewById<Button>(R.id.bt_down)
val bt_stop = findViewById<Button>(R.id.bt_stop)
val frame = findViewById<LinearLayout>(R.id.frame)
val txt1=findViewById<TextView>(R.id.txt1)
handler = Handler(Looper.getMainLooper())
runnable = Runnable {
i++
txt1.text = i.toString()
img_Mario.rotation=180f
img_Mario.translationX +=100
img_Mario.translationY +=20
handler.postDelayed(runnable, 1000)
}
bt_down.setOnClickListener {
handler.post(runnable)
}
bt_stop.setOnClickListener {
//Use this to stop all callbacks
//handler.removeCallbacksAndMessages(null)
handler.removeCallbacks(runnable)
}
}
}
Read more about processes, threads and handler here : https://developer.android.com/guide/components/processes-and-threads https://developer.android.com/reference/android/os/Handler
Upvotes: 2
Reputation: 171
I have one code and it run as I expected
val t = object : Thread() {
override fun run() {
while (!isInterrupted) {
try {
Thread.sleep(1000) //1000ms = 1 sec
runOnUiThread {
i++
txt1.text = i.toString()
img_Mario.rotation=180f
img_Mario.translationX +=20
}
} catch (e: InterruptedException) {
e.printStackTrace()
}
}
}
}
bt_down.setOnClickListener {
i=0
t.start()
}
Upvotes: 0