java - 我的 Android 应用程序的 gameLoop 线程在退出时崩溃

标签 java android multithreading

问题是,当我在游戏中并单击主页按钮时,gameLoop 线程(我猜)变得困惑,然后弹出“不幸的是,'app name' 已停止。”

我编写了一个非常简单的程序来解决这个问题。这个程序所做的就是在屏幕上显示一个数字,并在您触摸屏幕时增加它。 当我在 GameLoopThread 中注释掉 view.onDraw(c) 时,一切似乎都运行良好。

错误信息:

FATAL EXEPTION: Thread-23207
java.lang.NullPointerExeption
at com.example.crashtest.GameView.onDraw(GameView.java:61)
at com.example.crashtest.GameLoopThread.run(GameLoopThread.java:34)

代码如下:

主 Activity .java

package com.example.crashtest;

import android.os.Bundle;
import android.app.Activity;
import android.content.res.Configuration;
import android.view.KeyEvent;
import android.view.Window;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(new GameView(this));
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        switch (keyCode) {
            case KeyEvent.KEYCODE_BACK:
                return true;

            case KeyEvent.KEYCODE_MENU:
                return true;

            case KeyEvent.KEYCODE_VOLUME_UP:
                return true;

            case KeyEvent.KEYCODE_VOLUME_DOWN:
                return true;

            default:
                return false;
        }
    }
}

游戏 View .java

package com.example.crashtest;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class GameView extends SurfaceView { 
    private SurfaceHolder holder;
    private GameLoopThread gameLoopThread;

    private int num = 0;

    public GameView(final Context context) {
        super(context);

        holder = getHolder();
        holder.addCallback(new SurfaceHolder.Callback() {

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {

                   boolean retry = true;
                   gameLoopThread.setRunning(false);
                   while (retry) {
                          try {
                                gameLoopThread.join();
                                retry = false;
                          } catch (InterruptedException e) {}
                   }
            }

            @Override
            public void surfaceCreated(SurfaceHolder holder) {

                makeThread();
                gameLoopThread.start();
                gameLoopThread.setRunning(true);
            }

            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

            }
        });
    }

    private void makeThread() {
        gameLoopThread = new GameLoopThread(this);
    }

    @SuppressLint({ "WrongCall", "DrawAllocation" })
    @Override
    protected void onDraw(Canvas canvas) {
        // Draw black background - Write variable 'num' on the screen
        canvas.drawColor(Color.BLACK);

        Paint paint = new Paint();
        paint.setARGB(255, 0, 255, 0);
        paint.setTextSize(50);
        paint.setTextAlign(Align.CENTER);

        canvas.drawText(Integer.toString(num), getWidth() / 2, getHeight() / 2, paint);
    }

    public boolean onTouchEvent(MotionEvent event) {
        if(event.getAction() == MotionEvent.ACTION_DOWN) {
            // Increase 'num' with 1 every touch
            num++;
        }

        return super.onTouchEvent(event);
    }
}

游戏循环线程.java

package com.example.crashtest;

import android.annotation.SuppressLint;
import android.graphics.Canvas;

public class GameLoopThread extends Thread {
      static final long FPS = 10;
       private GameView view;
       public boolean running = false;
       public boolean pause = false;

       public GameLoopThread(GameView view) {
             this.view = view;
       }

       public void setRunning(boolean run) {
             running = run;
       }

       @SuppressLint("WrongCall")
       @Override
       public void run() {
           long ticksPS = 1000 / FPS;
           long startTime = 0;
           long sleepTime = 0;

             while (running) {
                    Canvas c = null;
                    startTime = System.currentTimeMillis();

                    try {
                           c = view.getHolder().lockCanvas();
                           synchronized (view.getHolder()) {
                               view.onDraw(c);
                           }
                    } finally {
                           if (c != null) {
                                  view.getHolder().unlockCanvasAndPost(c);
                           }
                    }

                    sleepTime = ticksPS-(System.currentTimeMillis() - startTime);
                    try {
                           if (sleepTime > 0)
                                  sleep(sleepTime);
                           else
                                  sleep(10);
                    } catch (Exception e) {}
             }
       }
}

最佳答案

当你关闭 Activity 时看看你需要什么你需要从我的代码中停止你的线程才能看到它:

GameView gameView ;
 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        gameView = new GameView(this); 
        setContentView(gameView);
    }

 @Override
protected void onPause() {
    // TODO Auto-generated method stub
    super.onPause();
    gameView.StopView();

}

并且您需要像这样在您的GameView 中实现名为StopView() 的方法

 public void StopView() {

    if (gameLoopThread != null) {
        gameLoopThread.setRunning(false);

    }
}

问题是因为在尝试阻塞线程后您仍然在线程中调用 run 方法,因此您需要在使用 join 阻塞它之前停止它。 我用新的实现测试了你的代码,它很适合我,反馈给我

关于java - 我的 Android 应用程序的 gameLoop 线程在退出时崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21517681/

相关文章:

android - 使用 FFMPEG 在 Android 上转码 Mp4 视频

java - Android vector 图标-添加边框

multithreading - 是否可以在不使用偏移量的情况下将指针存储在共享内存中?

java - spring boot 获取url参数的方法

java - 如何在Java中的快速排序中计算比较和交换?

java - Flink ParquetSinkWriter FileAlreadyExistsException

java - 在 @BeforeStep 之前初始化测试中的 Mock

java - 如何隐藏弹出 Activity 的标题栏

c - windows vista 的 slim reader writer locks 有跨平台版本吗?

java - 守护线程不工作 T1、T2、T3 是类。我是分开写的。我犯了什么错误?为什么我的守护线程无法访问?