Issue
I am trying to modify an existing example app where the app adds views to the main activity when the user touches the screen. These views are bitmap images that float around the screen. Touching anywhere on the screen adds one of these images at that location.
It does this by creating a new view (the bitmap image) for each touch.
It works fine as is, but I am trying to add a feature where it adds these views programmatically without any user input.
In the below code, I added the onResume() to attempt this functionality. (Adding the same code in onCreate() does not work either.)
Unfortunately it does not add them as I had hoped- instead of adding one every 500ms after the user starts the app, it pauses for 5s and then adds all ten at once.
Obviously I am new to android dev so I don't know where to go from here.
What do I need to do to implement a delay such that it adds one new view every half second? and why does it do it this way by default?
Thanks!
class ImageScreen : Activity(){
public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.imagescreen)
mFrame = findViewById<View>(R.id.frame) as FrameLayout
mBitmap = BitmapFactory.decodeResource(resources, R.drawable.myBitmapImage)
mFrame!!.setOnTouchListener { _, event ->
createImage(event.x, event.y)
true
}
}
override fun onResume() {
super.onResume()
for (i in 0..10) {
createImage(xpos.random(), ypos.random())
sleep(500)
}
}
private fun createImage(x: Float, y: Float){
mFrame!!.addView(myImage(applicationContext, x, y))
}
inner class myImage internal constructor(context: Context, x: Float, y: Float) : View(context) {
private fun createScaledBitmap(r: Random) {
mScaledBitmap = Bitmap.createScaledBitmap(mBitmap!!, mScaledBitmapWidth, mScaledBitmapWidth, false)
}
fun start() {
val executor = Executors.newScheduledThreadPool(1)
mMoverFuture = executor.scheduleWithFixedDelay({
if (changePosIfStillOnScreen()) {
postInvalidate()
} else stop(false)
}, 0, REFRESH_RATE.toLong(), TimeUnit.MILLISECONDS)
}
private fun stop() {
mFrame!!.removeView(this@myImage)
}
@Synchronized
override fun onDraw(canvas: Canvas) {
canvas.save()
canvas.drawBitmap(mScaledBitmap!!, mXPos, mYPos, mPainter)
canvas.restore()
}
}
}
// Additional code, such as functions and variable declarations that are not pertinent to this question, have been removed for simplicity
Solution
Note: the following snippet is from a java perspective, you may need to modify it to kotlin
Handler handler = new Handler(getMainLooper());
Runnable runnable = new Runnable() {
@Override
public void run() {
if (counter < 5) {
createImage(0, 0); //your positions
handler.postDelayed(this, 500);
counter++;
}
}
};
handler.postDelayed(runnable, 500);
Note: counter is an int variable to determine... count.
Reasoning:
All the code you do in any UI class (activities, fragments, views) defaults to the UI thread. If you do any Thread.sleep()
operations in that thread, the whole UI will freeze for that time being, which in some cases can lead to an ANR crash ANR.
Handler
can help you here. It takes a Looper
reference to instantiate. When you call the post(Runnable)
or optionally postDelayed(Runnable, long millis)
, it will take the Runnable
and execute it on the UI thread (delayed or otherwise). However, for each use, you need to call post
again, i.e. make the post
call recursive in the Runnable
.
I hope this helps!!
Answered By - Abdullah Z Khan
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.