有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

线程中的java方法调用导致“无法在线程内创建处理程序”异常

我正在制作一款Android游戏,但遇到了一个问题。在游戏中,“敌方太空船”将随机发射激光爆炸。因此,为了做到这一点,我决定制作一个生成随机数的方法,如果生成的数是4,那么将填充LaserBlast的ArrayList

方法如下:

// generates random number which later is used to decide if shoot ot not
public static void generateRandomNumber(ArrayList<EnemyShipLaserBlast> listOfLaserBlasts) {
    Random random = new Random();
    int number = random.nextInt(30);

    switch (number) {
        case 1:
            break;
        case 2:
            break;
        case 3:
            listOfLaserBlasts.add(new EnemyShipLaserBlast(5, 3));
            Log.i("LASER BLAST WAS ADDED", "**************");
            Log.i("size laser blasts " + listOfLaserBlasts.size(), "--------");
            break;
        case 4:
            break;

    }

然而,当我从run()方法(由线程运行)调用这个方法时,我得到一个

java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare().

我的run()方法如下所示:

 @Override
 public void run() {

    int frames = 0;
    long startTime = System.nanoTime();
    long currTime = 0;
    long lastTime = System.nanoTime();

    while (playing)
    {

        currTime = System.nanoTime();

        update((currTime - lastTime)/ 1000000000.0f); //updates the game data
        draw(); //draws the screen based on the game data
        control(); //controls how long is it until the run() method is called again

        lastTime = currTime;

        frames = frames + 1;
        if (System.nanoTime() - startTime > 100000000)
        {
            framesPerSecond = frames;
            frames = 0;
            startTime = System.nanoTime();
        }
    }

}

所以我想问你们,我是否应该把这个方法放在其他地方,或者有其他方法来解决这种问题


共 (2) 个答案

  1. # 1 楼答案

    您正在从工作线程调用update和draw。您需要从主线程中调用更新、绘制(以及处理UI的大多数其他函数)

    你怎么称呼你的runnable

    应将此参数添加到处理程序对象:

    Looper.getMainLooper()  
    

    因此,处理程序初始化类似于:

    mHandler = new Handler(Looper.getMainLooper()) {
    //your runnable
    }
    
  2. # 2 楼答案

    Handler.java是android框架提供的一个类,用于从主线程以外的线程更新GUI

    在android中,所有GUI都在主线程中更新和执行。此线程有一个与自身关联的特殊对象,即Looper对象。Looper负责使用事件队列并执行队列中的操作

    主线程通过调用Looper.prepare()来设置Looper的对象。任何线程都可以通过调用Looper.prepare()来关联Looper的对象

    如果处理程序对象是在主线程以外的线程中创建的,而主线程没有与之关联的Looper对象,则处理程序对象是毫无用处的(因为它将无法执行它打算执行的任务)。它的handleMessage方法将不会按照框架的规范调用。“

    如果您希望从主线程以外的线程(从您创建的线程)更新GUI,可以通过创建Handler的对象来实现。处理程序对象应该在主线程的执行流路径中创建(而不是从主线程以外的任何线程的run方法开始的任何其他路径)。现在,您可以使用这个处理程序对象来调用sendMessage方法(有各种重载方法,您可以在android开发者站点中读取这些方法)。Handler对象接收一个回调handleMessage,您可以在其中更新GUI

    如果您真的想挖掘更多,那么我建议您查看代码并阅读有关处理程序、Looper和ThreadLocal的内容。这些在android内部用于处理程序实现

    更多信息请参见https://developer.android.com/training/multiple-threads/communicate-ui.html#Handler