定期在屏幕上创建按钮

Create Buttons On-Screen in regular intervals

我有一个功能可以在屏幕上的随机位置动态创建按钮。我试图定期调用此函数,直到达到屏幕上允许的最大按钮数量。我也想在几秒钟后使用类似的逻辑来控制按钮的可见性。

我已经尝试使用 Timer 和 TimerTask 来执行此操作,但应用程序总是崩溃,我是否做错了什么我应该改用 Runnables 还是 Threads?

var numOfBtns: Int = 0
var randX = 0
var randY = 0
val numberOfButtonsToCreate = 3

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_test_buttons)

    val displaymetrics = DisplayMetrics()
    windowManager.defaultDisplay.getMetrics(displaymetrics)
    val width = displaymetrics.widthPixels // 1080
    val height = displaymetrics.heightPixels // 1794

    val timer: Timer = Timer()
    var timerTask = timerTask {
        run(){

                randX = Random.nextInt(30, width - 250)
                randY = Random.nextInt(90, height - 144)
                CreateButtons(randX, randY)

        }
    }

    timer.schedule(timerTask, 3000)

}

崩溃信息:

/AndroidRuntime: FATAL EXCEPTION: Timer-0
Process: com.example.clickinggameproject, PID: 10626
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
    at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:8798)
    at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:1606)
    at android.view.View.requestLayout(View.java:25390)
    at android.view.View.requestLayout(View.java:25390)
    at android.view.View.requestLayout(View.java:25390)
    at android.view.View.requestLayout(View.java:25390)
    at android.view.View.requestLayout(View.java:25390)
    at android.view.ViewGroup.addView(ViewGroup.java:5062)
    at android.view.ViewGroup.addView(ViewGroup.java:5036)
    at androidx.appcompat.app.AppCompatDelegateImpl.addContentView(AppCompatDelegateImpl.java:713)
    at androidx.appcompat.app.AppCompatActivity.addContentView(AppCompatActivity.java:185)
    at com.example.clickinggameproject.testButtonsActivity.CreateButtons(testButtonsActivity.kt:63)
    at com.example.clickinggameproject.testButtonsActivity$CreateButtonTimer$$inlined$timerTask.run(Timer.kt:150)
    at java.util.TimerThread.mainLoop(Timer.java:562)
    at java.util.TimerThread.run(Timer.java:512)

将此添加到解决问题的 CreateButtons 函数中,但现在我无法弄清楚为什么其他按钮在第一个 运行 之后没有出现在屏幕上??

 fun CreateButtons(posx: Int, posy: Int){
    this.runOnUiThread() {
 }

您已经发现您只能在主线程上使用您的视图。至于为什么只运行一次:你调用了timer.schedule没有指定间隔,所以只运行一次。如果你想让它重复运行,你必须指定函数的第三个参数。

此外,如果你有一个重复计时器,你必须在 onDestroy() 中对其调用 cancel(),否则它将在 Activity 之后保持 运行ning关闭。因此,将您的计时器存储在 属性 中,以便您可以在 onDestroy() 中访问它以取消它,如下所示:

private val timer = Timer()

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    //...

    val timerTask = timerTask {
        run(){
            val randX = Random.nextInt(30, width - 250)
            val randY = Random.nextInt(90, height - 144)
            CreateButtons(randX, randY)

        }
    }

    timer.schedule(timerTask, 3000)

}

override fun onDestroy() {
    super.onDestroy()
    timer.cancel()
}

我还想提一下,因为你的函数没有做任何阻塞,所以用协程来做会更简单。然后您不必担心取消它或确保您不在某个后台线程上。您可以从 CreateButtons 函数中删除 runOnUiThread 并执行此操作:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    //...

    lifecycleScope.launch {
        while(true){
            delay(3000)
            val randX = Random.nextInt(30, width - 250)
            val randY = Random.nextInt(90, height - 144)
            CreateButtons(randX, randY)
        }
    }

}