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