注:此处用例改编自《疯狂Android讲义》第二版P359页,原书中将自定义View放在Activity中,这里将自定义View抽离出来。
起初我的程序是这样写的
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
gameView = new GameView(this);
gameView.setBackgroundColor(Color.BLUE);
setContentView(gameView);
final Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
// TODO Auto-generated method stub
gameView.running();
if( gameView.isLose()){
timer.cancel();
}
}
}, 0, 100);
}
但是在运行的时候程序报如下错误:
02-26 20:34:49.193: E/AndroidRuntime(1147): FATAL EXCEPTION: Timer-0
02-26 20:34:49.193: E/AndroidRuntime(1147): Process: com.example.android_ball_play, PID: 1147
02-26 20:34:49.193: E/AndroidRuntime(1147): android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
在网上搜了一下这个错误,说是由于Android的UI不是线程安全的,Android规定只能在主线程中更新UI。
我这里的程序在timer启动的线程中有对UI的更新(gameView.running()),所以导致了上面的错误,对程序做了如下修改就正确了。
final Handler handler = new Handler();
final Timer timer = new Timer();
final Runnable runnable = new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
gameView.running();
if( gameView.isLose()){
timer.cancel();
}
}
};
timer.schedule(new TimerTask() {
@Override
public void run() {
// TODO Auto-generated method stub
handler.post(runnable);
}
}, 0, 100);
这样就使得UI的更新在主线程中了。