我无法弄清楚为什么我的LibGDX游戏只能在Android上成功运行一次。
假设游戏尚未安装在设备上,当我从eclipse运行应用程序时,游戏运行正常。关闭游戏后,尝试通过手机打开游戏再次运行游戏(不通过eclipse),它似乎永远挂在这个屏幕上:
从我的测试中,我发现我的Android Launcher代码都没有被执行,.onCreate()
从未被调用过。 LogCat显示没有抛出错误,应用程序似乎只加载LibGDX库,然后什么都没有。这是整个LogCat输出:http://i.imgur.com/5DQ5sHY.png
在LogCat中唯一引起我注意的是:
Launch timeout has expired, giving up wake lock! Activity idle timeout for ActivityRecord
有时在我的设备上清除游戏的缓存和数据似乎暂时解决了问题,但并非总是如此。
这是AndroidLauncher类:
package com.ifs_studios.cheekychameleon.android;
import java.util.HashMap;
import android.content.Intent;
import android.content.IntentSender.SendIntentException;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.RelativeLayout;
import android.widget.RelativeLayout.LayoutParams;
import android.widget.Toast;
import com.badlogic.gdx.backends.android.AndroidApplication;
import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration;
import com.google.android.gms.ads.AdListener;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.AdSize;
import com.google.android.gms.ads.AdView;
import com.google.android.gms.ads.InterstitialAd;
import com.google.android.gms.analytics.GoogleAnalytics;
import com.google.android.gms.analytics.HitBuilders;
import com.google.android.gms.analytics.Logger.LogLevel;
import com.google.android.gms.analytics.Tracker;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks;
import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
import com.google.android.gms.games.Games;
import com.google.android.gms.plus.Plus;
import com.ifs_studios.cheekychameleon.ActionResolver;
import com.ifs_studios.cheekychameleon.CheekyChameleon;
/**
* MemoryBlox Android Launcher.
*
* @author BleedObsidian (Jesse Prescott)
*/
public class AndroidLauncher extends AndroidApplication implements ActionResolver, ConnectionCallbacks, OnConnectionFailedListener {
/**
* Banner Advert AdMob key.
*/
private static final String BANNER_ADMOB_UNIT_ID= "XXXXX";
/**
* Fullscreen Advert AdMob key.
*/
private static final String FULLSCREEN_ADMOB_UNIT_ID= "XXXXX";
/**
* Google API Client.
*/
private GoogleApiClient googleApiClient;
/**
* If currently resolving a sign in error.
*/
private boolean isResolvingSignInError;
/**
* Global Leaderboard ID.
*/
private static final String LEADERBOARD_ID = "XXXXX";
/**
* Unique request resolve error ID.
*/
private static final int REQUEST_RESOLVE_ERROR = 1267;
/**
* Unique request for achievements ID.
*/
private static final int REQUEST_ACHIEVEMENTS = 1268;
/**
* Unique request for leaderboards ID.
*/
private static final int REQUEST_LEADERBOARD = 1269;
/**
* Google Analytics Trackers.
*/
private HashMap<TrackerName, Tracker> trackers = new HashMap<TrackerName, Tracker>();
/**
* Google Analytics App Tracker.
*/
private Tracker appTracker;
/**
* Google Analytics Global Tracker.
*/
private Tracker globalTracker;
/**
* Google Analytics Ecommerce Tracker.
*/
private Tracker ecommerceTracker;
/**
* If the game has been started.
*/
private boolean isStarted = false;
/**
* Advertisement View.
*/
protected AdView adView;
/**
* Interstitial Advertisement.
*/
protected InterstitialAd interstitialAd;
/**
* Game View.
*/
protected View gameView;
@Override
protected void onCreate (Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
this.setTitle("Cheeky Chameleon");
this.appTracker = this.getTracker(TrackerName.APP_TRACKER);
this.globalTracker = this.getTracker(TrackerName.GLOBAL_TRACKER);
this.ecommerceTracker = this.getTracker(TrackerName.ECOMMERCE_TRACKER);
this.appTracker.enableAdvertisingIdCollection(true);
this.globalTracker.enableAdvertisingIdCollection(true);
this.ecommerceTracker.enableAdvertisingIdCollection(true);
AndroidApplicationConfiguration config = new AndroidApplicationConfiguration();
config.useAccelerometer = false;
config.useCompass = false;
config.useWakelock = true;
config.hideStatusBar = true;
config.useImmersiveMode = true;
RelativeLayout layout = new RelativeLayout(this);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
this.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
this.createInterstitialAd();
this.createAdView();
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE);
params.addRule(RelativeLayout.CENTER_HORIZONTAL, RelativeLayout.TRUE);
layout.addView(this.adView, params);
this.createGameView(config);
layout.addView(this.gameView);
this.setContentView(layout);
this.startAdvertising();
}
@Override
public void onStart() {
super.onStart();
GoogleAnalytics.getInstance(this).reportActivityStart(this);
GoogleAnalytics.getInstance(this).getLogger()
.setLogLevel(LogLevel.INFO);
this.googleApiClient = new GoogleApiClient.Builder(this)
.addApi(Plus.API).addScope(Plus.SCOPE_PLUS_LOGIN)
.addApi(Games.API).addScope(Games.SCOPE_GAMES)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
}
@Override
public void onStop() {
super.onStop();
System.out.println("Stop");
}
@Override
public void onDestroy() {
super.onDestroy();
GoogleAnalytics.getInstance(this).reportActivityStop(this);
this.googleApiClient.disconnect();
System.out.println("Destroy");
}
/**
* Create AdView.
*
* @return AdView.
*/
private void createAdView() {
this.adView = new AdView(this);
this.adView.setAdSize(AdSize.SMART_BANNER);
this.adView.setAdUnitId(AndroidLauncher.BANNER_ADMOB_UNIT_ID);
this.adView.setId(12398);
this.adView.setBackgroundColor(Color.WHITE);
}
/**
* Create fullscreen AdView.
*/
private void createInterstitialAd() {
this.interstitialAd = new InterstitialAd(AndroidLauncher.this);
this.interstitialAd.setAdUnitId(AndroidLauncher.FULLSCREEN_ADMOB_UNIT_ID);
AdRequest adRequest = new AdRequest.Builder().build();
this.interstitialAd.loadAd(adRequest);
}
@Override
public void loadInterstitialAdvert() {
AdRequest adRequest = new AdRequest.Builder().build();
interstitialAd.loadAd(adRequest);
}
/**
* Create GameView.
*
* @param config AndroidApplicationConfiguration.
* @return View.
*/
private void createGameView(AndroidApplicationConfiguration config) {
this.gameView = this.initializeForView(new CheekyChameleon(this), config);
this.gameView.setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.ALIGN_PARENT_TOP, RelativeLayout.TRUE);
params.addRule(RelativeLayout.CENTER_HORIZONTAL, RelativeLayout.TRUE);
params.addRule(RelativeLayout.ABOVE, adView.getId());
this.gameView.setLayoutParams(params);
}
/**
* Start Advertising.
*
* @param adView AdView.
*/
private void startAdvertising() {
AdRequest.Builder adRequestBuilder = new AdRequest.Builder();
AdRequest adRequest = adRequestBuilder.build();
adView.setAdListener(new AdListener() {
@Override
public void onAdFailedToLoad(int error) {
System.out.println("Error: " + error);
}
});
adView.loadAd(adRequest);
}
@Override
public void setTrackerScreenName(String name) {
this.globalTracker.setScreenName(name);
this.globalTracker.send(new HitBuilders.AppViewBuilder().build());
System.out.println("Tracking screen: " + name);
}
/**
* Get google analytics tracker.
*
* @param trackerName TrackerName.
* @return Tracker.
*/
public synchronized Tracker getTracker(TrackerName trackerName) {
if (!this.trackers.containsKey(trackerName)) {
GoogleAnalytics analytics = GoogleAnalytics.getInstance(this);
Tracker tracker = (trackerName == TrackerName.APP_TRACKER) ? analytics
.newTracker(R.xml.app_tracker)
: (trackerName == TrackerName.GLOBAL_TRACKER) ? analytics
.newTracker(R.xml.global_tracker) : analytics
.newTracker(R.xml.ecommerce_tracker);
tracker.enableAdvertisingIdCollection(true);
this.trackers.put(trackerName, tracker);
}
return this.trackers.get(trackerName);
}
/**
* Enum used to identify the tracker that needs to be used for tracking.
*
* A single tracker is usually enough for most purposes. In case you do need
* multiple trackers, storing them all in Application object helps ensure
* that they are created only once per application instance.
*/
public enum TrackerName {
APP_TRACKER, // Tracker used only in this app.
GLOBAL_TRACKER, // Tracker used by all the apps from a company. eg: roll-up tracking.
ECOMMERCE_TRACKER, // Tracker used by all ecommerce transactions from a company.
}
@Override
public void displayInterstitialAdvert() {
if(interstitialAd.isLoaded()) {
this.interstitialAd.show();
} else {
AdRequest adRequest = new AdRequest.Builder().build();
this.interstitialAd.loadAd(adRequest);
this.interstitialAd.show();
}
}
@Override
public void signInGooglePlayServices() {
if(!this.isResolvingSignInError) {
this.googleApiClient.connect();
}
}
@Override
public void signOutGooglePlayServices() {
this.googleApiClient.disconnect();
}
@Override
public boolean isSignedInGooglePlayServices() {
return this.googleApiClient.isConnected();
}
@Override
public void displayAchievements() {
if(this.googleApiClient.isConnected()) {
this.startActivityForResult(Games.Achievements.getAchievementsIntent(this.googleApiClient), AndroidLauncher.REQUEST_ACHIEVEMENTS);
} else {
this.googleApiClient.connect();
}
}
@Override
public void displayLeaderboards() {
if(this.googleApiClient.isConnected()) {
this.startActivityForResult(Games.Leaderboards.getLeaderboardIntent(this.googleApiClient,
AndroidLauncher.LEADERBOARD_ID), AndroidLauncher.REQUEST_LEADERBOARD);
} else {
this.googleApiClient.connect();
}
}
@Override
public void submitScore(int score) {
if(this.googleApiClient.isConnected()) {
System.out.println("Submiting score: " + score);
Games.Leaderboards.submitScore(this.googleApiClient, AndroidLauncher.LEADERBOARD_ID, score);
}
}
@Override
public void onConnectionFailed(ConnectionResult result) {
if(this.isResolvingSignInError) {
return;
} else if (result.hasResolution()){
try {
this.isResolvingSignInError = true;
result.startResolutionForResult(this, AndroidLauncher.REQUEST_RESOLVE_ERROR);
System.out.println("Failed to connect to Google Play Services, Resolving");
} catch(SendIntentException exception) {
this.googleApiClient.connect();
}
} else {
GooglePlayServicesUtil.showErrorDialogFragment(result.getErrorCode(), this, AndroidLauncher.REQUEST_RESOLVE_ERROR);
this.isResolvingSignInError = false;
System.out.println("Failed to connect to Google Play Services: " + result.getErrorCode());
}
}
@Override
public void onConnected(Bundle bundle) {
System.out.println("Connected to Google Play Services");
}
@Override
public void onConnectionSuspended(int number) {
System.out.println("Google Play Services connection suspended");
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == AndroidLauncher.REQUEST_RESOLVE_ERROR) {
this.isResolvingSignInError = false;
if (resultCode == RESULT_OK) {
if (!this.googleApiClient.isConnecting() &&
!this.googleApiClient.isConnected()) {
this.googleApiClient.connect();
}
} else {
System.out.println("Sign in failed: " + resultCode);
}
} else if(requestCode == AndroidLauncher.REQUEST_ACHIEVEMENTS) {
if (resultCode != RESULT_OK && resultCode != RESULT_CANCELED) {
Toast.makeText(this, "Failed to show achivements", Toast.LENGTH_SHORT).show();
System.out.println("Failed to display achievements.");
}
}
}
}
这是我的AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ifs_studios.cheekychameleon.android"
android:versionCode="29"
android:versionName="0.4.1" >
<uses-sdk android:minSdkVersion="11" android:targetSdkVersion="21" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="com.android.vending.BILLING" />
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/>
<uses-permission android:name="com.google.android.providers.gsf.permission.WRITE_GSERVICES"/>
<application
android:allowBackup="false"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name">
<activity
android:name="com.ifs_studios.cheekychameleon.android.AndroidLauncher"
android:label="@string/app_name"
android:screenOrientation="portrait"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.google.android.gms.ads.AdActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"/>
<meta-data android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
<meta-data
android:name="com.google.android.gms.analytics.globalConfigResource"
android:resource="@xml/global_tracker" />
<meta-data android:name="com.google.android.gms.games.APP_ID"
android:value="@string/app_id" />
</application>
</manifest>
从LogCat的输出中我不知道问题是什么。我在Xperia U和Xperia Z1上测试了这个,问题仍然存在。谢谢你的帮助。
修改 - 额外信息:
我正在使用LibGDX的最新版本(1.5.4)
答案 0 :(得分:0)
经过几天的压力,我终于解决了这个问题。在主线程上执行回溯后,我发现在尝试加载Google Analytics跟踪器时程序停止了。这是线程回溯:
然后我对这个结果做了一些研究。它似乎是尝试从xml文件加载跟踪器时导致的错误。这个错误在这里有更详细的讨论:在com.google.android.gms.analytics.ae.getLogger(未知来源)
在com.google.android.gms.analytics.ae.W(未知来源)
在com.google.android.gms.analytics.z $ a.f(未知来源) 在com.google.android.gms.analytics.n.a(未知来源)
在com.google.android.gms.analytics.n.x(未知来源)
在com.google.android.gms.analytics.GoogleAnalytics.eZ(未知来源)
在com.google.android.gms.analytics.GoogleAnalytics。(未知来源)
在com.google.android.gms.analytics.GoogleAnalytics。(未知来源)
在com.google.android.gms.analytics.GoogleAnalytics.getInstance(未知来源)
为防止此错误,我不再通过在AndroidManifest.xml中删除此行来从其相应的xml文件中加载跟踪器:
<meta-data
android:name="com.google.android.gms.analytics.globalConfigResource"
android:resource="@xml/analytics_global_config" />
问题已解决,谢谢你们。