LibGDX And​​roid应用程序只运行一次

时间:2015-03-08 23:28:09

标签: android libgdx

我无法弄清楚为什么我的LibGDX游戏只能在Android上成功运行一次。

假设游戏尚未安装在设备上,当我从eclipse运行应用程序时,游戏运行正常。关闭游戏后,尝试通过手机打开游戏再次运行游戏(不通过eclipse),它似乎永远挂在这个屏幕上:

http://i.stack.imgur.com/QcLCW.png

从我的测试中,我发现我的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)

1 个答案:

答案 0 :(得分:0)

经过几天的压力,我终于解决了这个问题。在主线程上执行回溯后,我发现在尝试加载Google Analytics跟踪器时程序停止了。这是线程回溯:

  

在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(未知来源)

然后我对这个结果做了一些研究。它似乎是尝试从xml文件加载跟踪器时导致的错误。这个错误在这里有更详细的讨论:

为防止此错误,我不再通过在AndroidManifest.xml中删除此行来从其相应的xml文件中加载跟踪器:

<meta-data 
        android:name="com.google.android.gms.analytics.globalConfigResource"
        android:resource="@xml/analytics_global_config" />

问题已解决,谢谢你们。