Libgdx Developer's Guide(Libgdx開發者手冊)-7(查詢,日誌,執行緒,特定平臺程式碼的介面)
查詢
應用程式介面提供了豐富的方法來查詢執行時環境的屬性。
獲取應用型別
有時,對一些特殊案例來說,很有必要依賴於它所執行的平臺而編寫部分應用。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);
}