更新libgdx 1.7.0到1.7.2时,libgdx timer.schedule错误

时间:2017-01-11 09:04:57

标签: java android timer libgdx

我试图从1.7.0更新libgdx - > 1.7.2 之后,我的代码开始在Timer / Timer.task中出现一些错误

这是我不知道如何解决的第一个代码 请帮忙..

void loadScreen(String screen) {
    clearScreen();
    nextScreen = screen;
    Timer.schedule(SHOW_SCREEN, Math.min(Gdx.graphics.getDeltaTime(), 0.02f));
}

// SHOW_SCREEN
Task SHOW_SCREEN = new Task() {
@Override
public void run() {
    screen = nextScreen;

    if (screen.equals("main")) { // MAIN
        // load screen
        map = new JsonReader().parse(Gdx.files.internal("main.hmp"));
        mapWidth = map.getInt("map_width", 0);


        // layers
        Lib.addGroup("bg", map, stage.getRoot(), 0);

        // menu buttons array
        Array<Act> buttons = new Array<Act>();

        // btnStart
        buttons.add(Lib.addLayer("btnStart", map, stage.getRoot(), 0).first());

        // sign button
        btnSign = Lib.addLayer("btnSign", map, stage.getRoot(), 0).first();
        buttons.add(btnSign);
        setSigned(isSigned);

        // btnLeaders
        buttons.add(Lib.addLayer("btnLeaders", map, stage.getRoot(), 0).first());

        // btnOptions
        buttons.add(Lib.addLayer("btnOptions", map, stage.getRoot(), 0).first());

        // groupOptions
        groupOptions = Lib.addGroup("groupOptions", map, stage.getRoot(), 0);
        groupOptions.setVisible(false);
        btnSound = groupOptions.findActor("btnSound");
        btnSound.tex = new TextureRegion(assetManager.get(
                pref.getBoolean("soundMute", false) ? "btnSoundOn.png" : "btnSoundOff.png", Texture.class));

// map config
    mapHeight = map.getInt("map_height", 0);
    screenColor = map.getString("map_color", null);

    // stage keyboard focus
    Act a = new Act("");
    stage.addActor(a);
    a.addListener(controlListener);
    stage.setKeyboardFocus(a);

    // set stage moving XY limit
    stageLimit();
}
};

这是错误日志:

Exception in thread "Timer" com.badlogic.gdx.utils.GdxRuntimeException: Task failed: com.badlogic.gdx.utils.Timer
at com.badlogic.gdx.utils.Timer$TimerThread.run(Timer.java:245)
at java.lang.Thread.run(Thread.java:745)

引起:java.lang.NullPointerException

at com.badlogic.gdx.utils.Timer.update(Timer.java:125)
at com.badlogic.gdx.utils.Timer$TimerThread.run(Timer.java:243)
... 1 more

这是libgdx版本1.7.0的time.java:

package com.badlogic.gdx.utils;

import com.badlogic.gdx.Application;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.LifecycleListener;

/** Executes tasks in the future on the main loop thread.
* @author Nathan Sweet */
public class Timer {
static final Array<Timer> instances = new Array(1);
static TimerThread thread;
static private final int CANCELLED = -1;
static private final int FOREVER = -2;

/** Timer instance for general application wide usage. Static methods on {@link Timer} make convenient use of this instance. */
static Timer instance = new Timer();

static public Timer instance () {
    if (instance == null) {
        instance = new Timer();
    }
    return instance;
}

private final Array<Task> tasks = new Array(false, 8);

public Timer () {
    start();
}

/** Schedules a task to occur once as soon as possible, but not sooner than the start of the next frame. */
public Task postTask (Task task) {
    return scheduleTask(task, 0, 0, 0);
}

/** Schedules a task to occur once after the specified delay. */
public Task scheduleTask (Task task, float delaySeconds) {
    return scheduleTask(task, delaySeconds, 0, 0);
}

/** Schedules a task to occur once after the specified delay and then repeatedly at the specified interval until cancelled. */
public Task scheduleTask (Task task, float delaySeconds, float intervalSeconds) {
    return scheduleTask(task, delaySeconds, intervalSeconds, FOREVER);
}

/** Schedules a task to occur once after the specified delay and then a number of additional times at the specified interval. */


public Task scheduleTask (Task task, float delaySeconds, float intervalSeconds, int repeatCount) {

    if (task.repeatCount != CANCELLED) throw new IllegalArgumentException("The same task may not be scheduled twice.");
    task.executeTimeMillis = System.nanoTime() / 1000000 + (long)(delaySeconds * 1000);
    task.intervalMillis = (long)(intervalSeconds * 1000);
    task.repeatCount = repeatCount;

    synchronized (tasks) {
        tasks.add(task);
    }
    wake();


    return task;
}

/** Stops the timer, tasks will not be executed and time that passes will not be applied to the task delays. */
public void stop () {
    synchronized (instances) {
        instances.removeValue(this, true);
    }
}

/** Starts the timer if it was stopped. */
public void start () {
    synchronized (instances) {
        if (instances.contains(this, true)) return;
        instances.add(this);
        if (thread == null) thread = new TimerThread();
        wake();
    }
}

/** Cancels all tasks. */
public void clear () {
    synchronized (tasks) {
        for (int i = 0, n = tasks.size; i < n; i++)
            tasks.get(i).cancel();
        tasks.clear();
    }
}









long update (long timeMillis, long waitMillis) {
    synchronized (tasks) {
        for (int i = 0, n = tasks.size; i < n; i++) {
            Task task = tasks.get(i);

            if (task.executeTimeMillis > timeMillis) {
                waitMillis = Math.min(waitMillis, task.executeTimeMillis - timeMillis);
                continue;
            }
            if (task.repeatCount != CANCELLED) {
                if (task.repeatCount == 0) {
                    // Set cancelled before run so it may be rescheduled in run.
                    task.repeatCount = CANCELLED;

                }


                Gdx.app.postRunnable(task);
            }

            if (task.repeatCount == CANCELLED) {
                tasks.removeIndex(i);
                i--;
                n--;
            } else {
                task.executeTimeMillis = timeMillis + task.intervalMillis;
                waitMillis = Math.min(waitMillis, task.intervalMillis);
                if (task.repeatCount > 0) task.repeatCount--;

            }
        }
    }
    return waitMillis;
}

/** Adds the specified delay to all tasks. */
public void delay (long delayMillis) {
    synchronized (tasks) {
        for (int i = 0, n = tasks.size; i < n; i++) {
            Task task = tasks.get(i);

            task.executeTimeMillis += delayMillis;

        }
    }
}

static void wake () {
    synchronized (instances) {
        instances.notifyAll();
    }
}

/** Schedules a task on {@link #instance}.
 * @see #postTask(Task) */
static public Task post (Task task) {
    return instance().postTask(task);
}

/** Schedules a task on {@link #instance}.
 * @see #scheduleTask(Task, float) */
static public Task schedule (Task task, float delaySeconds) {
    return instance().scheduleTask(task, delaySeconds);
}

/** Schedules a task on {@link #instance}.
 * @see #scheduleTask(Task, float, float) */
static public Task schedule (Task task, float delaySeconds, float intervalSeconds) {
    return instance().scheduleTask(task, delaySeconds, intervalSeconds);
}

/** Schedules a task on {@link #instance}.
 * @see #scheduleTask(Task, float, float, int) */
static public Task schedule (Task task, float delaySeconds, float intervalSeconds, int repeatCount) {
    return instance().scheduleTask(task, delaySeconds, intervalSeconds, repeatCount);
}

/** Runnable with a cancel method.
 * @see Timer
 * @author Nathan Sweet */
static abstract public class Task implements Runnable {
    long executeTimeMillis;
    long intervalMillis;
    int repeatCount = CANCELLED;


    /** If this is the last time the task will be ran or the task is first cancelled, it may be scheduled again in this method. */


    abstract public void run ();

    /** Cancels the task. It will not be executed until it is scheduled again. This method can be called at any time. */
    public void cancel () {
        executeTimeMillis = 0;
        repeatCount = CANCELLED;
    }

    /** Returns true if this task is scheduled to be executed in the future by a timer. */









    public boolean isScheduled () {
        return repeatCount != CANCELLED;
    }

    /** Returns the time when this task will be executed in milliseconds */
    public long getExecuteTimeMillis () {
        return executeTimeMillis;
    }
}

/** Manages the single timer thread. Stops thread on libgdx application pause and dispose, starts thread on resume.
 * @author Nathan Sweet */
static class TimerThread implements Runnable, LifecycleListener {
    Application app;

    private long pauseMillis;

    public TimerThread () {
        Gdx.app.addLifecycleListener(this);
        resume();
    }

    public void run () {
        while (true) {
            synchronized (instances) {
                if (app != Gdx.app) return;

                long timeMillis = System.nanoTime() / 1000000;
                long waitMillis = 5000;
                for (int i = 0, n = instances.size; i < n; i++) {
                    try {
                        waitMillis = instances.get(i).update(timeMillis, waitMillis);
                    } catch (Throwable ex) {
                        throw new GdxRuntimeException("Task failed: " + instances.get(i).getClass().getName(), ex);
                    }
                }

                if (app != Gdx.app) return;

                try {
                    if (waitMillis > 0) instances.wait(waitMillis);
                } catch (InterruptedException ignored) {
                }
            }
        }
    }

    public void resume () {
        long delayMillis = System.nanoTime() / 1000000 - pauseMillis;
        synchronized (instances) {
            for (int i = 0, n = instances.size; i < n; i++) {
                instances.get(i).delay(delayMillis);
            }
        }
        app = Gdx.app;
        Thread t = new Thread(this, "Timer");
        t.setDaemon(true);
        t.start();
        thread = this;
    }

    public void pause () {
        pauseMillis = System.nanoTime() / 1000000;
        synchronized (instances) {
            app = null;
            wake();
        }
        thread = null;
    }

    public void dispose () {
        pause();
        Gdx.app.removeLifecycleListener(this);
        instances.clear();
        instance = null;
    }
}
}

这是针对最新版本的1.7.2 timer.java libgdx:

package com.badlogic.gdx.utils;

import com.badlogic.gdx.Application;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.LifecycleListener;

/** Executes tasks in the future on the main loop thread.
 * @author Nathan Sweet */
public class Timer {
static final Array<Timer> instances = new Array(1);
static TimerThread thread;
static private final int CANCELLED = -1;
static private final int FOREVER = -2;

/** Timer instance for general application wide usage. Static methods on {@link Timer} make convenient use of this instance. */
static Timer instance = new Timer();

static public Timer instance () {
    if (instance == null) {
        instance = new Timer();
    }
    return instance;
}

private final Array<Task> tasks = new Array(false, 8);

public Timer () {
    start();
}

/** Schedules a task to occur once as soon as possible, but not sooner than the start of the next frame. */
public Task postTask (Task task) {
    return scheduleTask(task, 0, 0, 0);
}

/** Schedules a task to occur once after the specified delay. */
public Task scheduleTask (Task task, float delaySeconds) {
    return scheduleTask(task, delaySeconds, 0, 0);
}

/** Schedules a task to occur once after the specified delay and then repeatedly at the specified interval until cancelled. */
public Task scheduleTask (Task task, float delaySeconds, float intervalSeconds) {
    return scheduleTask(task, delaySeconds, intervalSeconds, FOREVER);
}

/** Schedules a task to occur once after the specified delay and then a number of additional times at the specified interval. */


public Task scheduleTask (Task task, float delaySeconds, float intervalSeconds, int repeatCount) {

    if (task.repeatCount != CANCELLED) throw new IllegalArgumentException("The same task may not be scheduled twice.");
    task.executeTimeMillis = System.nanoTime() / 1000000 + (long)(delaySeconds * 1000);
    task.intervalMillis = (long)(intervalSeconds * 1000);
    task.repeatCount = repeatCount;

    synchronized (tasks) {
        tasks.add(task);
    }
    wake();


    return task;
}

/** Stops the timer, tasks will not be executed and time that passes will not be applied to the task delays. */
public void stop () {
    synchronized (instances) {
        instances.removeValue(this, true);
    }
}

/** Starts the timer if it was stopped. */
public void start () {
    synchronized (instances) {
        if (instances.contains(this, true)) return;
        instances.add(this);
        if (thread == null) thread = new TimerThread();
        wake();
    }
}

/** Cancels all tasks. */
public void clear () {
    synchronized (tasks) {
        for (int i = 0, n = tasks.size; i < n; i++)
            tasks.get(i).cancel();
        tasks.clear();
    }
}









long update (long timeMillis, long waitMillis) {
    synchronized (tasks) {
        for (int i = 0, n = tasks.size; i < n; i++) {
            Task task = tasks.get(i);

            if (task.executeTimeMillis > timeMillis) {
                waitMillis = Math.min(waitMillis, task.executeTimeMillis - timeMillis);
                continue;
            }
            if (task.repeatCount != CANCELLED) {
                if (task.repeatCount == 0) {
                    // Set cancelled before run so it may be rescheduled in run.
                    task.repeatCount = CANCELLED;

                }


                Gdx.app.postRunnable(task);
            }

            if (task.repeatCount == CANCELLED) {
                tasks.removeIndex(i);
                i--;
                n--;
            } else {
                task.executeTimeMillis = timeMillis + task.intervalMillis;
                waitMillis = Math.min(waitMillis, task.intervalMillis);
                if (task.repeatCount > 0) task.repeatCount--;

            }
        }
    }
    return waitMillis;
}

/** Adds the specified delay to all tasks. */
public void delay (long delayMillis) {
    synchronized (tasks) {
        for (int i = 0, n = tasks.size; i < n; i++) {
            Task task = tasks.get(i);

            task.executeTimeMillis += delayMillis;

        }
    }
}

static void wake () {
    synchronized (instances) {
        instances.notifyAll();
    }
}

/** Schedules a task on {@link #instance}.
 * @see #postTask(Task) */
static public Task post (Task task) {
    return instance().postTask(task);
}

/** Schedules a task on {@link #instance}.
 * @see #scheduleTask(Task, float) */
static public Task schedule (Task task, float delaySeconds) {
    return instance().scheduleTask(task, delaySeconds);
}

/** Schedules a task on {@link #instance}.
 * @see #scheduleTask(Task, float, float) */
static public Task schedule (Task task, float delaySeconds, float intervalSeconds) {
    return instance().scheduleTask(task, delaySeconds, intervalSeconds);
}

/** Schedules a task on {@link #instance}.
 * @see #scheduleTask(Task, float, float, int) */
static public Task schedule (Task task, float delaySeconds, float intervalSeconds, int repeatCount) {
    return instance().scheduleTask(task, delaySeconds, intervalSeconds, repeatCount);
}

/** Runnable with a cancel method.
 * @see Timer
 * @author Nathan Sweet */
static abstract public class Task implements Runnable {
    long executeTimeMillis;
    long intervalMillis;
    int repeatCount = CANCELLED;


    /** If this is the last time the task will be ran or the task is first cancelled, it may be scheduled again in this method. */


    abstract public void run ();

    /** Cancels the task. It will not be executed until it is scheduled again. This method can be called at any time. */
    public void cancel () {
        executeTimeMillis = 0;
        repeatCount = CANCELLED;
    }

    /** Returns true if this task is scheduled to be executed in the future by a timer. */









    public boolean isScheduled () {
        return repeatCount != CANCELLED;
    }

    /** Returns the time when this task will be executed in milliseconds */
    public long getExecuteTimeMillis () {
        return executeTimeMillis;
    }
}

/** Manages the single timer thread. Stops thread on libgdx application pause and dispose, starts thread on resume.
 * @author Nathan Sweet */
static class TimerThread implements Runnable, LifecycleListener {
    Application app;

    private long pauseMillis;

    public TimerThread () {
        Gdx.app.addLifecycleListener(this);
        resume();
    }

    public void run () {
        while (true) {
            synchronized (instances) {
                if (app != Gdx.app) return;

                long timeMillis = System.nanoTime() / 1000000;
                long waitMillis = 5000;
                for (int i = 0, n = instances.size; i < n; i++) {
                    try {
                        waitMillis = instances.get(i).update(timeMillis, waitMillis);
                    } catch (Throwable ex) {
                        throw new GdxRuntimeException("Task failed: " + instances.get(i).getClass().getName(), ex);
                    }
                }

                if (app != Gdx.app) return;

                try {
                    if (waitMillis > 0) instances.wait(waitMillis);
                } catch (InterruptedException ignored) {
                }
            }
        }
    }

    public void resume () {
        long delayMillis = System.nanoTime() / 1000000 - pauseMillis;
        synchronized (instances) {
            for (int i = 0, n = instances.size; i < n; i++) {
                instances.get(i).delay(delayMillis);
            }
        }
        app = Gdx.app;
        Thread t = new Thread(this, "Timer");
        t.setDaemon(true);
        t.start();
        thread = this;
    }

    public void pause () {
        pauseMillis = System.nanoTime() / 1000000;
        synchronized (instances) {
            app = null;
            wake();
        }
        thread = null;
    }

    public void dispose () {
        pause();
        Gdx.app.removeLifecycleListener(this);
        instances.clear();
        instance = null;
    }
}
}

1 个答案:

答案 0 :(得分:0)

问题

Gdx.app在以下行中update方法的上下文中似乎为空。

Gdx.app.postRunnable(task);
  

在较新版本中,Gdx.app被分配给Task的成员   可以在source中看到。

     

null检查已在版本1.95中添加,如此commit中所示。   可能没有必要更新到1.95。

解决方案

不要在成员声明中调用Task的构造函数,而是尝试在resizecreate方法的上下文中调用它。

祝你好运。