我花了一段时间试图找出为什么我的模拟器会一直冻结,结果是因为我引入了一个循环。单击按钮后,输出随机数(LoadG1),然后在4秒后消失。用户然后输入一个数字,如果它等于loadg1,他们得到一个点,程序通过让另一个loadg1可用4秒然后消失等来循环...
我不能拥有循环,除非它显然是它自己的线程。我为它做了一个线程然后尝试了。按下按钮后整个应用程序冻结没有发生,但当loadg1启动4秒时,应用程序关闭。好像第一行循环工作,然后在4秒结束后失败。我收到以下错误:
android.view.ViewRootImpl $ CalledFromWrongThreadException:只有 创建视图层次结构的原始线程可以触及其视图。
在查询之后我看到我需要把它放在runOnUiThread中,所以我做了,只是遇到了同样的问题。这是我的代码:
import android.os.CountDownTimer;
import android.os.SystemClock;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.Editable;
import android.view.KeyEvent;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import java.util.Random;
public class game1 extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game1);
final Button loseStarter1;
loseStarter1 = (Button) findViewById(R.id.Starter1);
loseStarter1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
loseStarter1.setVisibility(View.GONE);
final int[] score = {0};
Random generateG1 = new Random();
final int loadG1 = generateG1.nextInt(1000000)+10000;
final TextView number = (TextView) findViewById(R.id.number);
number.setText(" "+loadG1);
new CountDownTimer(18000, 1000) {
@Override
public void onTick (long millisUntilFinished) {
}
public void onFinish() {
TextView result = (TextView) findViewById(R.id.outcome);
result.setText("Score: "+ score[0]);
TextView prompt = (TextView) findViewById(R.id.prompt);
prompt.setVisibility(View.GONE);
}
}.start();
runOnUiThread(new Runnable() {
@Override
public void run() {
Runnable myRunnable = new Runnable() {
@Override
public void run() {
while (true) {
SystemClock.sleep(4000);
number.setVisibility(View.GONE);
final TextView prompt = (TextView) findViewById(R.id.prompt);
prompt.setText(" Enter the number");
final EditText input = (EditText) findViewById(R.id.enterAnswer);
input.setVisibility(View.VISIBLE);
input.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
switch (keyCode) {
case KeyEvent.KEYCODE_ENTER:
Editable answer = input.getText();
int finalAnswer = Integer.parseInt(String.valueOf(answer));
int finalLoadG1 = Integer.parseInt(String.valueOf(loadG1));
input.setVisibility(View.GONE);
prompt.setVisibility(View.GONE);
if (finalAnswer == finalLoadG1) {
score[0]++;
}
return true;
default:
}
}
return false;
}
});
}
}
};
Thread myThread = new Thread(myRunnable);
myThread.start();
}
});
}
});
}
}
我觉得我已经如此接近解决这个问题,非常感谢所有帮助。
编辑:我尝试了一种没有循环的替代解决方案,代码在这里:
runOnUiThread(new Runnable() {
@Override
public void run() {
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
runOnUiThread(new Runnable() {
@Override
public void run() {
SystemClock.sleep(4000);
number.setVisibility(View.GONE);
final TextView prompt = (TextView) findViewById(R.id.prompt);
prompt.setText(" Enter the number");
final EditText input = (EditText) findViewById(R.id.enterAnswer);
input.setVisibility(View.VISIBLE);
input.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
switch (keyCode) {
case KeyEvent.KEYCODE_ENTER:
Editable answer = input.getText();
int finalAnswer = Integer.parseInt(String.valueOf(answer));
int finalLoadG1 = Integer.parseInt(String.valueOf(loadG1));
input.setVisibility(View.GONE);
prompt.setVisibility(View.GONE);
if (finalAnswer == finalLoadG1) {
score[0]++;
}
return true;
default:
}
}
return false;
}
});
}
});
}
}, 0, 4000);
}
});
现在生成随机数并显示4秒钟,但是当用户输入可用时,应用程序会冻结。显然跳过了238帧(我相信这会显示每四秒钟),并且“主线程”正在做太多工作。注意:即使没有RUNONUITHREAD封装我的代码,也会发生同样的结果。我没有找到任何不同的方法。
老老实实地感谢能够帮助我解决这个问题的人。
答案 0 :(得分:1)
while(true)
,这就是为什么你会卡住,甚至更多的时候不使用(真的) - 这是不好的做法。
如果你需要运行一些重复操作,可以使用计时器,你可以启动/停止计时器,你可以启动另一个计时器,甚至几次一次)
不要在线程中进行UI操作,只能在UI线程上进行。
用于硬操作使用异步任务 - 当完成所有硬操作后,再更新UI。 (在异步任务中,您可以通过发布进度更新UI),在stackoverflow吨样本上执行异步任务。
OnKeyListener
- 在非UI线程上运行,但请在上面阅读并避免使用while(true)
更新回答:
好的,如果你想这样跑并且不想有滞后,那么请继续:
创建计时器 - 无需在runOnUIThread
中启动它。所有带计算的代码移动ti异步任务,你将在计时器中启动,在异步任务中运行 - 停止计时器以避免再次运行,在异步任务中进行所有计算,结束异步任务 - 更新ui和(或者你可以在发布时更新)进度)并在async
任务结束时,您可以再次启动计时器。如果您在下次运行之前需要延迟,请使用Handler
和postDelayed