libGDX 游戏在 Android 崩溃,没有任何日志/错误

libGDX game crashes on Android without any logs / errosrs

This question was asked in the thematic community, but the answer was not received. First, it is necessary to solve the problem. Secondly, I think it will be useful to make cross-references so that people who are faced with this problem can quickly find the answer. Question in the thematic community

libGDX 游戏在 Android 台设备上的控制台中无任何错误地崩溃。它发生在游戏的不同部分、不同时间的不同屏幕上。我不明白原因。 游戏运行良好,不卡顿。游戏不会在更换屏幕等资源密集型操作下崩溃,但在加载屏幕并且玩家玩了一会儿时就已经崩溃了。根据 RAM 使用图表,内存的使用可能是正常的。 CPU 也没有超载。 最奇怪的是,当游戏崩溃时,控制台中没有显示任何错误。 phone 屏幕变黑了一会儿,然后系统在主页上发出 screen.The phone 也没有在应用程序中显示错误消息等。 此外,有时在显示 AdMob 视频后,游戏停止响应输入,但图形继续工作,动画工作。

起初,我认为这可能是由于 AdMob 的实施不正确所致。但是从项目中彻底移除 AdMob 后,问题并没有消失。

什么会导致应用程序出现这种行为?

也许这是由于 AssetManager 中的一些错误?我想指出,我使用了大量的纹理(超过 170 个),打包在一个图集中。 atlas 中的所有纹理占用 4.31MB 磁盘 space 我的所有资产占用 6.2MB. 我在初始加载期间加载的所有资源使用 AssetManager.

的游戏

所以,我的 Res class:

public class Res {

    public static final String LOCALE_BUNDLE_PATH = "i18n/locale";

    public static final String MAIN_ATLAS_PATH = "packs/main/MAIN.atlas";
    public static final String MUSIC_M3_THEME_PATH = "music/atc_m3_theme.mp3";
    public static final String KICK_SOUND_PATH = "music/atc_kick.mp3";
    public static final String FADEIN_SOUND_PATH = "music/atc_fadein.mp3";
    public static final String DRAG_START_SOUND_PATH = "music/atc_drag_start.mp3";
    public static final String DRAG_STOP_SOUND_PATH = "music/atc_drag_stop.mp3";

    public static final String FONT_REGULAR_PATH = "fonts/comfortaa_regular.ttf";
    public static final String FONT_LIGHT_PATH = "fonts/comfortaa_light.ttf";
    public static final String RUSSO_ONE_REGULAR = "fonts/russo_one_regular.ttf";

    public static TextureAtlas MAIN_ATLAS;

    public static I18NBundle LOCALE;

    /* MUSIC & SOUNDS */
    public static Music M3_THEME;
    public static Sound KICK_SOUND;
    public static Sound FADE_IN_SOUND;
    public static Sound DRAG_START_SOUND;
    public static Sound DRAG_STOP_SOUND;

    private Res () {
        MAIN_ATLAS = null;
    }

}

还有我的 ResManager:

public class ResManager extends AssetManager {

    public void loadResources () {
        load(Res.MAIN_ATLAS_PATH, TextureAtlas.class);
        load(Res.MUSIC_M3_THEME_PATH, Music.class);
        load(Res.KICK_SOUND_PATH, Sound.class);
        load(Res.FADEIN_SOUND_PATH, Sound.class);
        load(Res.DRAG_START_SOUND_PATH, Sound.class);
        load(Res.DRAG_STOP_SOUND_PATH, Sound.class);
        load(Res.LOCALE_BUNDLE_PATH, I18NBundle.class);
        finishLoading();
        Res.MAIN_ATLAS = get(Res.MAIN_ATLAS_PATH, TextureAtlas.class);
        Res.M3_THEME = get(Res.MUSIC_M3_THEME_PATH, Music.class);
        Res.KICK_SOUND = get(Res.KICK_SOUND_PATH, Sound.class);
        Res.FADE_IN_SOUND = get(Res.FADEIN_SOUND_PATH, Sound.class);
        Res.DRAG_START_SOUND = get(Res.DRAG_START_SOUND_PATH, Sound.class);
        Res.DRAG_STOP_SOUND = get(Res.DRAG_STOP_SOUND_PATH, Sound.class);
        Res.LOCALE = get(Res.LOCALE_BUNDLE_PATH, I18NBundle.class);
    }

}

我知道在 Android 生态系统中做 TextureAtlas static 是个坏主意,但为了方便在代码中使用资源,必须这样做。此外,它仍然从内存中删除,因为我在应用程序关闭时杀死了进程。

@Override
    protected void onDestroy() {
        android.os.Process.killProcess(android.os.Process.myPid());
        super.onDestroy();
    }

此外,我正确处理了所有屏幕,显然将 GC 指向他应该收集的不必要的对象。例如:

@Override
    public void dispose() {
        stage.dispose(); // Stage
        loadingPane = null; // Group
        multiplexer = null; // InputMultiplexer
        firstScreen.destroy(); // Group
        secondScreen.destroy(); // Group
        firstScreen = null;
        secondScreen = null;
        bgSky = null; // Image
        ground = null; // Image
        dialogCircuit = null; // Group
        dialogModule = null; // Group
        dialogNotEnough = null; // Group
    }

试图在 LeakCanary 的帮助下捕获内存泄漏。但它没有用。日志为空。

告诉我,可能是什么原因?一个非常烦人的问题,扼杀了我玩游戏的乐趣。

更新: Logcat 日志(完整):logs。 游戏包名:net.dailytoys.afterthecrash(讽刺的是,我明白了)

以下是崩溃前的最后一个日志,关于此应用程序(为方便起见与完整日志分开):

03-19 17:18:05.198 811-907/? W/InputDispatcher: channel 'ec9957f net.dailytoys.afterthecrash/net.dailytoys.afterthecrash.AndroidLauncher (server)' ~ Consumer closed input channel or an error occurred.  events=0x9
03-19 17:18:05.198 811-907/? E/InputDispatcher: channel 'ec9957f net.dailytoys.afterthecrash/net.dailytoys.afterthecrash.AndroidLauncher (server)' ~ Channel is unrecoverably broken and will be disposed!
03-19 17:18:05.213 811-1587/? I/WindowState: WIN DEATH: Window{ec9957f u0 net.dailytoys.afterthecrash/net.dailytoys.afterthecrash.AndroidLauncher}
03-19 17:18:05.217 811-1587/? W/InputDispatcher: Attempted to unregister already unregistered input channel 'ec9957f net.dailytoys.afterthecrash/net.dailytoys.afterthecrash.AndroidLauncher (server)'
03-19 17:18:05.223 811-1251/? I/ActivityManager: Process net.dailytoys.afterthecrash (pid 482) has died
03-19 17:18:05.257 811-1251/? W/ActivityManager: Force removing ActivityRecord{19f34039 u0 net.dailytoys.afterthecrash/.AndroidLauncher t3820}: app died, no saved state
03-19 17:18:05.258 811-1587/? W/WindowManager: Force-removing child win Window{19cfd5d7 u0 SurfaceView} from container Window{ec9957f u0 net.dailytoys.afterthecrash/net.dailytoys.afterthecrash.AndroidLauncher}
03-19 17:18:08.565 11009-11046/? D/IconCache: net.dailytoys.afterthecrash
03-19 17:18:08.566 11009-11046/? W/PackageManager: Failure retrieving resources for net.dailytoys.afterthecrash: Resource ID #0x0
03-19 17:18:09.454 11009-11009/? D/IconCache: net.dailytoys.afterthecrash
03-19 17:18:09.456 11009-11009/? W/PackageManager: Failure retrieving resources for net.dailytoys.afterthecrash: Resource ID #0x0

已解决!

问题出现在非常频繁的 BitmapFont 代中。对于每个屏幕,都会生成几种字体。我这样做是因为字体大小取决于这些屏幕上某些演员的大小。我不想对字体使用缩放,因为它会破坏质量。

即使是现在,当我执行 BitmapFont.dispose() 时,仍然会占用太多内存,并且泄漏不会消失。出于这个原因,我认为我需要重新考虑我对图形用户界面进行编程的方法。

我认为最好的选择是生成大约合适大小的字体,然后缩放它们。