查找
应用程序接口提供了丰富的方法来查找运行时环境的属性。
获取应用类型
有时,对一些特殊案例来说,很有必要依赖于它所运行的平台而编写部分应用。Application.getApplicationType() 方法返回当前应用程序正在使用的平台。
switch(Gdx.app.getApplicationType()) {
case ApplicationType.Android:
// android specific code
case ApplicationType.Desktop:
// desktop specific code
case ApplicationType.WebGl:
/// HTML5 specific code
}
Android中,也可查找当前应用运行的Android版本。
int androidVersion = Gdx.app.getVersion();
这会返回当前设备支持的SDK版本号,如:3 是 Android 1.5。
内存消耗
为了调试和分析,通常需要了解Java堆和本地堆的内存消耗。
int javaHeap = Gdx.app.getJavaHeap();
int nativeHeap = Gdx.app.getNativeHeap();
这两个方法都返回当前各自堆中已使用的字节数。
日志
应用程序接口提供了一个简单的可控制粒度的日志工具。
一个信息可以是普通的info信息,可选异常的error信息和一个debug信息:
Gdx.app.log("MyTag", "my informative message");
Gdx.app.error("MyTag", "my error message", exception);
Gdx.app.debug("MyTag", "my error message");
依赖于平台,这些信息被记录在控制台(桌面应用),LogCat(Android),或者是一个由GwtApplicationConfiguration提供或自动生成的GWT文本域(html5)。
日志可以指定为特定的日志级别:
Gdx.app.setLogLevel(logLevel);
其中 logLevel 可以是下面其中一个值:
- Application.LOG_NONE: 忽略所有记录。
- Application.LOG_DEBUG:记录所有信息。
- Application.LOG_ERROR:只记录错误信息。
- Application.LOG_INFO: 记录错误与正常信息。
线程
所有的 ApplicationListener 的方法都在同一个线程里被调用。该线程是一个可创建OpenGL调用的渲染线程。对大多数游戏而言在方法ApplicationListener.render()中通过渲染线程同时实现逻辑更新和渲染就可以了。
任何直接涉及OpenGL的图形操作都需要在渲染线程里执行。在其他线程里操作会导致未知的行为。这是因为OpenGL上下文仅仅活跃于渲染线程内。在其他线程里创建当前上下文在很多Android设备上都有问题,因此不支持。
要想从其他线程向渲染线程传递数据,我们推荐使用 Application.postRunnable()。它会在ApplicationListener.render()调用前,使代码在下一帧里运行在渲染线程的Runnable中。
new Thread(new Runnable() {
@Override
public void run() {
// do something important here, asynchronously to the rendering thread
final Result result = createResult();
// post a Runnable to the rendering thread that processes the result
Gdx.app.postRunnable(new Runnable() {
@Override
public void run() {
// process the result, e.g. add it to an Array<Result> field of the ApplicationListener.
results.add(result);
}
});
}
}).start();
HTML5
Javascript 一直是单线程的。因此,线程就不可用了。Web Workers 可能是未来的一种方法,然而,数据能够通过线程间信息进行传递。Java使用不同的线程原理和机制,不会直接移植线程代码到 Web Workers。
平台特定代码的接口
这里是相应的讨论区forum discussion,同时也包含iOS特定的东西。
有时需要访问平台特定API,例如:添加广告服务或者由框架提供的leaderboard,比如: Swarm。这可以通过用Facade实现这些API来完成,为每个目标提供平台特定的实现。
下面的例子纯属虚构,并假设想要使用一个非常简单的无继承的API,该API仅在Android上可用。对于其他平台,我们只记录调用信息或者提供一个模拟的返回值。
Android API 如下所示:
/** Let's assume this is the API provided by Swarm **/
public class LeaderboardServiceApi {
public void submitScore(String user, int score) { ... }
}
第一步是以接口的形式创建一个该抽象API。
该接口位于核心工程(see Project Setup):
public interface Leaderboard {
public void submitScore(String user, int score);
}
下一步,我们为每个平台创建具体实现,并把这些放置在各自工程内。
/** Android implementation, can access LeaderboardServiceApi directly **/
public class AndroidLeaderboard implements Leaderboard {
private final LeaderboardServiceApi service;
public AndroidLeaderboard() {
// Assuming we can instantiate it like this
service = new LeaderboardServiceApi();
}
public void submitScore(String user, int score) {
service.submitScore(user, score);
}
}
下面的代码放入桌面工程:
/** Desktop implementation, we simply log invocations **/
public class DesktopLeaderboard implements Leaderboard {
public void submitScore(String user, int score) {
Gdx.app.log("DesktopLeaderboard", "would have submitted score for user " + user + ": " + score");
}
}
下面代码放进 HTML5工程:
/** Html5 implementation, same as DesktopLeaderboard **/
public class Html5Leaderboard implements Leaderboard {
public void submitScore(String user, int score) {
Gdx.app.log("DesktopLeaderboard", "would have submitted score for user " + user + ": " + score");
}
}
接下来, ApplicationListener 实现一个构建器,这样就可以传入具体的 Leaderboard 实现:
public class MyGame implements ApplicationListener {
private final Leaderboard leaderboard;
public MyGame(Leaderboard leaderboard) {
this.leaderboard = leaderboard;
}
// rest omitted for clarity
}
然后在每个 启动类 中实例化 MyGame,传入相应的 Leaderboard 实现作为参数,如,桌面应用:
public static void main(String[] argv) {
LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
new LwjglApplication(new MyGame(new DesktopLoaderboard()), config);
}