深入Android架构(从线程到AIDL)_16 应用Android的UI框架03
目录
6、 设计一个GameLoop类别
7、 只诞生一次GameLoop对象编辑
6、 设计一个GameLoop类别
- 刚才的小线程,其实就扮演了游戏线程(Game thread)的角色,它负责控制游戏的循环。
// myView.java
//……
public class myView extends View {
//……….
@Override
protected void onDraw(Canvas canvas) {
//…………..
myThread t = new myThread();
t.start();
}
class myThread extends Thread{
public void run() {
postInvalidateDelayed(1000);
}
};
}
- 于是,我们将刚才的小线程部分独立出来,成为一个独立的类别,通称为游戏线程(Game Thread) 或游戏循环(Game Loop)。
// GameLoop.java
// ………
public class GameLoop extends Thread {
myView mView;
GameLoop(myView v){
mView = v;
}
public void run() {
mView.onUpdate();
mView.postInvalidateDelayed(1000);
}
}
// myView.java
// ………..
public class myView extends View {
private Paint paint= new Paint();
private int x, y;
private int line_x = 100;
private int line_y = 100;
private float count = 0;
myView(Context ctx) {
super(ctx);
}
public void onUpdate(){
if( count > 12) count = 0;
x = (int) (75.0 * Math.cos(2*Math.PI * count/12.0));
y = (int) (75.0 * Math.sin(2*Math.PI * count/12.0));
count++;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.WHITE);
paint.setColor(Color.BLUE);
paint.setStrokeWidth(3);
canvas.drawLine(line_x, line_y, line_x+x, line_y+y, paint);
paint.setStrokeWidth(2);
paint.setColor(Color.RED);
canvas.drawRect(line_x-5, line_y - 5, line_x+5, line_y + 5, paint);
paint.setColor(Color.CYAN);
canvas.drawRect(line_x-3, line_y - 3, line_x+3, line_y + 3, paint);
//--------------------------------
GameLoop loop = new GameLoop(this);;
loop.start();
}
}
- 首先由myActivity来诞生myView对象,然后由Android框架調用myView的onDraw()函数来绘图和显示。绘图完毕,立即诞生一个GameLoop对象,并調用start()函数去启动一个小线程去調用postInvalidate()函数。就触发UI线程重新調用myView的onDraw()函数。
7、 只诞生一次GameLoop对象
- 每次执行onDraw()时,都会重新诞生一次GameThread对象,也诞生一次游戏线程去調用postInvalidate()函数。似乎是UI线程控制着游戏线程,这样游戏线程就不能扮演主控者的角色了。
- 于是,可换一个方式:一开始先诞生一个游戏线程,并且使用while(true)来创造一个无限循环(Endless Loop),让游戏线程持续绕回圈,而不会停止。
- 在诞生myView时,就诞生GameLoop对象,且調用其start()函数来启动游戏线程。此时游戏线程处于<暂停>状态,虽然继续绕回圈,但是并不会調用postInvalidate()函数。接着,由Android框架調用myView的onDraw()函数来绘图和显示。
- 绘图完毕,立即調用GameLoop的loopResume()函数,让GameLoop从<暂停>状态转移到<执行>状态。此时,这游戏线程就去調用postInvalidate()函数,触发UI线程重新調用myView的onDraw()函数。如下图:
// GameLoop.java
// ……..
public class GameLoop extends Thread {
private myView mView;
private boolean bRunning;
GameLoop(myView v){
mView = v; bRunning = false; }
public void run() {
while(true){
if(bRunning){
mView.onUpdate();
mView.postInvalidateDelayed(1000);
loopPause();
}
}
}
public void loopPause(){ bRunning = false; }
public void loopResme(){ bRunning = true; }
}
- 其中, loopPause()函数将bRunning设定为false,游戏线程就处于<暂停>状态。loopResume()函数将bRunning设定为true,游戏线程就处于<执行>状态,就会調用myView的onUpdate()函数,去更新绘图的设定。
- 然后調用postInvalidate()函数,触发UI线程去重新調用onDraw()函数。
// myView.java // ……… public class myView extends View { private Paint paint= new Paint(); private int x, y; private int line_x = 100, line_y = 100; private float count; private GameLoop loop; myView(Context ctx) { super(ctx); init(); loop = new GameLoop(this); loop.start(); } public void init(){ count = 0; x = (int) (75.0 * Math.cos(2*Math.PI * count/12.0)); y = (int) (75.0 * Math.sin(2*Math.PI * count/12.0)); } public void onUpdate(){ // 游戏线程执行的 if( count > 12) count = 0; x = (int) (75.0 * Math.cos(2*Math.PI * count/12.0)); y = (int) (75.0 * Math.sin(2*Math.PI * count/12.0)); count++; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawColor(Color.WHITE); paint.setColor(Color.BLUE); paint.setStrokeWidth(3); canvas.drawLine(line_x, line_y, line_x+x, line_y+y, paint); paint.setStrokeWidth(2); paint.setColor(Color.RED); canvas.drawRect(line_x-5, line_y - 5, line_x+5, line_y + 5, paint); paint.setColor(Color.CYAN); canvas.drawRect(line_x-3, line_y - 3, line_x+3,line_y + 3, paint); //-------------------------------- loop.loopResme(); } }
• 请留意: onUpdate()函数是由游戏线程所执行的;而onDraw()则是由UI线程所执行的。