java - 如何在绘图线程中使用Android的Looper

标签 java android multithreading surfaceview

我正在尝试制作一个简单的飞机游戏来培养我的技能并获得一些乐趣。但是当我试图从一个TextViewThread 绘制我的飞机。我将尝试仅包含下面的基本代码,并使用“...”来指示省略的行。

我正在一个单独的、优秀的老式 android 线程中绘图。下面是 Thread 的构造函数:

public class BenThread extends Thread {
...
public BenThread(SurfaceHolder surfaceHolder, Context context,
        BenSurfaceView surfaceView) {
    this.surfaceHolder = surfaceHolder;
    this.context = context;
    this.surfaceView = surfaceView;
    this.isRunning = false;

    Bitmap planeImage = BitmapFactory.decodeResource(
            context.getResources(), R.drawable.fighters);
    airplane = new Airplane(50, 50, 2, 0, planeImage);
}

在我展示 run 方法之前,请注意有一个 SurfaceView 在调用 SurfaceChanged() 时创建并启动 Thread。在我的主要 ActivityonCreate() 中,我创建了自定义 SurfaceView 的最终实例:

final BenSurfaceView surfaceView = (BenSurfaceView) findViewById(R.id.surfaceView);

在 UI 布局中,有一个 TextView 位于底部中央,并连接了一个 OnTouchListener。在 onTouch() 中,对于 MotionEvent.ACTION_DOWN,调用以下行:

surfaceView.thread.handler.sendEmptyMessage(1);

回到线程类,这个空消息的处理程序是在 run 方法中创建的,同时创建了 Looper:

public void run() {
    super.run();
    Looper.prepare(); // Creates a Message Queue for the thread
    MessageQueue queue = Looper.myQueue();
    queue.addIdleHandler(new IdleHandler() {
        @Override
        public boolean queueIdle() {
            Looper.myLooper().quit();
            return false;
        }
    });
    handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            Log.i("HANDLING", "SOMETHING");
        }
    };
    Looper.loop();

    while (isRunning) {
        currentTime = System.currentTimeMillis();
        // spin in a while loop for a while
        while ((currentTime - previousTime) < REFRESH_RATE) {
            currentTime = System.currentTimeMillis();
        }
        airplane.move();
        canvas = surfaceHolder.lockCanvas();
        if (canvas != null) {
            surfaceView.draw(canvas);
            airplane.draw(canvas);
            surfaceHolder.unlockCanvasAndPost(canvas);
        }
    }
}

现在,如果我按原样运行,我会看到飞机在屏幕上移动的漂亮小动画。 enter image description here 但是,当我单击底部的 Button 时,我从日志中看到我向死线程发送了一条消息。好吧,我想我在 IdleHandler 中杀死了它。所以现在让我注释掉 quit 方法:

// Looper.myLooper().quit();

现在我的应用程序看起来不那么令人兴奋了: enter image description here

但是,当我点击底部的按钮并查看日志时,有证据表明我的消息已被处理!所以最大的问题是,我怎样才能运行消息循环并仍然看到我的动画?

最佳答案

调用 Looper.loop() 后,它不应返回,直到线程准备好停止。让您的游戏在 Looper.loop() 调用之后 循环没有意义。在那一点上,线程“死了”,因为 Looper 不再监听消息。

如果您希望您的线程在 while (isRunning) 中运行,请执行此操作。如果您希望它是消息驱动的,请执行此操作。不要试图在同一个线程中同时执行这两项操作。 (请不要在 CPU 上旋转——在移动设备上会很快耗尽电池电量。)

您可以在 this article 的附录 A 和 B 中找到有关游戏循环、SurfaceView 和线程的一些说明。 . Grafika 中有各种使用 Handler 进行动画渲染的示例.例如,“记录 GL 应用程序” Activity 使用 Choreographer 在需要绘制时向渲染线程发送消息。

关于java - 如何在绘图线程中使用Android的Looper,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24333878/

相关文章:

java - 多线程怪异行为

java - 为什么 "smallest"不返回任何内容?

c++ - 如何在C++中实现一个简单的多线程FileLogger?

matlab - 如何在 MATLAB 中进行线程化?

c++ - 抛出 'std::system_error'实例后终止调用

java - 如何从 Json 中保留 @OneToMany 和 @ManyToOne

java - 用户输入的数字不相加

Android Retrofit - 回调与不回调

c# - Xamarin 应用程序通过 https 连接到 WCF 服务时出现问题

android - Google App Engine 示例应用抛出 503