几个小时以来,我一直在使用我的新Android应用程序,但是在一个非常奇怪的例外情况下纠结自己。 意味着异常是明确的,但我不理解其背后的内容。
我有一个名为MainActivity的活动,如下所示:
公共类MainActivity扩展了Activity实现Observer {
private gameState st = new gameState();
private gameEngine bc;
public RelativeLayout gameLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
st.addObserver(this);
gameLayout = (RelativeLayout) findViewById(R.id.gLayout);
startGame();
}
@Override
public void update(Observable observable, Object data) {
int gameState = ((gameState) observable).getState();
if(gameState == 1){
continueGame();
}
if(gameState == 2){
killGame();
}
}
private void killGame(){
if(!bc.BarThread.isInterrupted()){
bc.BarThread.interrupt();
}
gameLayout.removeAllViewsInLayout();
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT
);
TextView tv = new TextView(this);
gameLayout.addView(tv, params);
tv.setText("Game Over");
}
}
我的简单gameState类:
public class gameState extends Observable{
private int state = 0;
public gameState() {
}
public void setState(int var){
synchronized(this){
state = var;
}
setChanged();
notifyObservers();
}
public synchronized int getState(){
return state;
}
}
我的gameEngine(实例化为bc),太长了,无法在此发布,但我可以尝试用简单的单词解释内容。
游戏引擎具有一些游戏元素,如按钮,ProgressBar和线程(BarThread),可以持续填充栏。 如果用户成功,则gameEngine将gameState设置为1,MainActivity执行类似killGame()方法的操作,该方法完美无缺。
如果用户太慢且ProgressBar已满,则BarThread将gameState设置为2。 然后MainActivity执行killGame并抛出
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
但是我无法理解为什么线程会通过观察者产生影响?
答案 0 :(得分:0)
我在猜BarThread
来电setState(int var)
,对吗?如果这是真的,那么在不是主线程的线程上调用该方法。这意味着setState()
调用的所有内容(例如notifyObservers()
)都未在主线程上调用。我猜测notifyObservers()
最终会调用MainActivity.update(Observable observable, Object data)
,调用killGame()
,这会更改视图层次结构(即添加文本视图)。这意味着您的视图层次结构是从不是主线程的线程修改的。
您可能需要在Handler
中创建MainActivity
。然后在killGame()
中,致电Handler.post(Runnable runnable)
。像这样:
private Handler handler;
@Override
public void onCreate(Bundle savedInstanceState) {
handler = new Handler();
}
private void killGame() {
if(!bc.BarThread.isInterrupted()){
bc.BarThread.interrupt();
}
handler.post(new Runnable() {
@Override
public void run() {
gameLayout.removeAllViewsInLayout();
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT
);
TextView tv = new TextView(MainActivity.this);
gameLayout.addView(tv, params);
tv.setText("Game Over");
}
});
}