深入Android架构(从线程到AIDL)_16 应用Android的UI框架03

目录

[6、 设计一个GameLoop类别](#6、 设计一个GameLoop类别)

[7、 只诞生一次GameLoop对象​编辑](#7、 只诞生一次GameLoop对象编辑)


6、 设计一个GameLoop类别

  • 刚才的小线程,其实就扮演了游戏线程(Game thread)的角色,它负责控制游戏的循环。
java 复制代码
// 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)。
java 复制代码
// 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()函数。如下图:
java 复制代码
// 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()函数。

    java 复制代码
    // 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线程所执行的。

相关推荐
阿巴斯甜5 小时前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker6 小时前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq95277 小时前
Andorid Google 登录接入文档
android
黄林晴8 小时前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab20 小时前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿1 天前
Android MediaPlayer 笔记
android
Jony_1 天前
Android 启动优化方案
android
阿巴斯甜1 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇1 天前
AOSP15 Input专题InputReader源码分析
android
_小马快跑_1 天前
Kotlin | 协程调度器选择:何时用CoroutineScope配置,何时用launch指定?
android