# Libgdx Application Lifecycle

> Use when writing a libGDX ApplicationListener or ApplicationAdapter, structuring a game's main class, or debugging lifecycle issues like missing disposal, initialization crashes, or incorrect pause/resume behavior. Use when asking where to put initialization code, how to get delta time, or which types need dispose().

- **Type:** Skill
- **Install:** `agentstack add skill-kyu-n-gdx-claude-skills-libgdx-application-lifecycle`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [kyu-n](https://agentstack.voostack.com/s/kyu-n)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [kyu-n](https://github.com/kyu-n)
- **Source:** https://github.com/kyu-n/gdx-claude-skills/tree/master/skills/libgdx-application-lifecycle

## Install

```sh
agentstack add skill-kyu-n-gdx-claude-skills-libgdx-application-lifecycle
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# libGDX Application Lifecycle

Reference for ApplicationListener, ApplicationAdapter, lifecycle method order, frame-independent updates, resource disposal, and platform-specific pause/resume behavior.

## ApplicationListener Interface

```java
public interface ApplicationListener {
    void create();             // App created — OpenGL context now available
    void resize(int w, int h); // Window/viewport resized
    void render();             // Called every frame (update + draw combined)
    void pause();              // App losing focus / going to background
    void resume();             // App regaining focus / returning to foreground
    void dispose();            // App shutting down — release all resources
}
```

**There is no `update()` method.** All game logic and drawing happen in `render()`.

## ApplicationAdapter (Use This)

`ApplicationAdapter` implements `ApplicationListener` with empty defaults. Extend it and override only what you need — avoids boilerplate empty methods.

```java
// YES — extend ApplicationAdapter
public class MyGame extends ApplicationAdapter { ... }

// NO — don't implement ApplicationListener directly unless you need all 6 methods
public class MyGame implements ApplicationListener { ... }
```

## Lifecycle Order

```
create() → resize(w,h) → [render() loop] → pause() → dispose()
                          ↕
                   pause() ↔ resume()
```

**Startup:** `create()` → `resize(w, h)` → `render()` ...
**Exit:** `pause()` → `dispose()`

On Android, `dispose()` may **not** be called if the OS kills the process while backgrounded. Save critical state in `pause()`, not `dispose()`.

## Initialization: create(), Not the Constructor

**All GPU/audio/file initialization must happen inside `create()`.** The OpenGL context and libGDX subsystems (`Gdx.graphics`, `Gdx.audio`, `Gdx.files`, etc.) do not exist until `create()` is called. Constructing a `Texture`, `SpriteBatch`, or any GL-dependent object as a field initializer or in the constructor will crash.

```java
// WRONG — crashes: no GL context at field-init time
public class MyGame extends ApplicationAdapter {
    SpriteBatch batch = new SpriteBatch();   // CRASH
    Texture img = new Texture("pic.png");    // CRASH
}

// RIGHT — create() has a valid GL context
public class MyGame extends ApplicationAdapter {
    SpriteBatch batch;
    Texture img;

    @Override
    public void create() {
        batch = new SpriteBatch();
        img = new Texture("pic.png");
    }
}
```

## render() = Update + Draw

There is no separate `update()` callback. Combine logic and rendering in `render()`:

```java
@Override
public void render() {
    // 1. Delta time for frame-independent movement
    float dt = Gdx.graphics.getDeltaTime();  // seconds since last frame

    // 2. Update
    x += 100 * dt;  // 100 pixels/second regardless of frame rate

    // 3. Draw — ScreenUtils.clear() is the modern shorthand (since 1.10.0)
    //    replacing the verbose Gdx.gl.glClearColor() + Gdx.gl.glClear() pattern
    ScreenUtils.clear(0, 0, 0, 1);
    batch.begin();
    batch.draw(img, x, 0);
    batch.end();
}
```

`getDeltaTime()` is on **`Gdx.graphics`**, not `Gdx.app`.

## pause() / resume() — Platform Differences

| Event | Desktop (LWJGL3) | Android | iOS (RoboVM) |
|---|---|---|---|
| Window minimized / Home button | `pause()` fires | `pause()` fires | `pause()` fires |
| Window loses focus (Alt+Tab) | **Nothing** — render continues | — | — |
| Incoming call / screen off | — | `pause()` fires | `pause()` fires |
| render() during pause | **Continues running** | **Stops entirely** | **Stops entirely** |
| GL context on pause | **Retained** | **Destroyed** — managed resources auto-reloaded | **Retained** |
| dispose() on kill | Called | **May not be called** | Called |

**Desktop:** `pause()` only fires on **iconification**, not on focus loss. `render()` keeps running even when iconified — if you have network timers or other continuous work in `render()`, it won't stop on desktop. Check the pause state explicitly if needed.

**Android:** The render loop **stops entirely** during pause. Any work in `render()` (heartbeats, timers, network pings) ceases. Use a background thread or Android service for work that must continue. The GL context is destroyed during pause; libGDX automatically reloads *managed* resources on resume. Only raw, unmanaged GL handles need manual recreation.

**iOS (RoboVM):** Behaves like Android for pause triggers (home button, incoming call, app switcher), but the GL context is **retained** like desktop. `render()` stops during pause.

## resize() on Android — configChanges Gotcha

On Android, device rotation triggers `resize()` **only** if `android:configChanges` includes `orientation|screenSize` in the manifest. Without it, Android destroys and recreates the Activity — a full `dispose()` → `create()` cycle, not a `resize()`. The Android backend skill covers manifest setup.

## Gdx.app.exit()

`Gdx.app.exit()` schedules a **graceful shutdown** — it is NOT immediate. Code after `exit()` still executes in the current frame. The shutdown triggers `pause()` → `dispose()`. On Android, it calls `finish()` on the Activity.

```java
if (Gdx.input.isKeyJustPressed(Input.Keys.ESCAPE)) {
    Gdx.app.exit();
    return;  // necessary — exit() is non-blocking
}
```

## Disposal: Types That Need dispose()

These types allocate native memory or GPU resources outside the JVM heap. The garbage collector **cannot** free them — you must call `dispose()` explicitly, typically in your `ApplicationAdapter.dispose()`.

| Type | Resource held |
|---|---|
| `Texture` | GPU texture |
| `SpriteBatch` | Mesh + shader |
| `BitmapFont` | Texture(s) |
| `ShaderProgram` | GL shader program |
| `FrameBuffer` | GL framebuffer + texture |
| `Sound` | Native audio buffer |
| `Music` | Native audio stream |
| `Pixmap` | Native pixel buffer |
| `TextureAtlas` | Texture(s) |
| `Skin` | Textures + fonts |
| `Stage` | SpriteBatch (if owns it) |

**Rule of thumb:** if you created it, dispose it. Dispose in reverse order of creation when possible. In non-trivial projects, `AssetManager` handles disposal via `unload()` and `clear()` — prefer it over manual tracking.

## Lifecycle Debugging with Gdx.app.log()

```java
Gdx.app.setLogLevel(Application.LOG_DEBUG); // in create()

Gdx.app.log("Game", "info message");    // LOG_INFO level
Gdx.app.debug("Game", "debug message"); // LOG_DEBUG level
Gdx.app.error("Game", "error message"); // LOG_ERROR level
```

**Log level constants** (`com.badlogic.gdx.Application`):

| Constant | Value | Shows |
|---|---|---|
| `LOG_NONE` | 0 | Nothing |
| `LOG_ERROR` | 1 | error() only |
| `LOG_INFO` | 2 | error() + log() |
| `LOG_DEBUG` | 3 | All messages |

Default level is `LOG_INFO`. Output goes to stdout (desktop), LogCat (Android), or NSLog (iOS).

## Minimal Working Example

```java
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.utils.ScreenUtils;

public class MyGame extends ApplicationAdapter {
    @Override
    public void create() {
        Gdx.app.log("MyGame", "create()");
    }

    @Override
    public void render() {
        // ScreenUtils.clear() replaces the old glClearColor()+glClear() pattern (since 1.10.0)
        ScreenUtils.clear(Color.CORAL);
    }

    @Override
    public void dispose() {
        Gdx.app.log("MyGame", "dispose()");
    }
}
```

## Common Mistakes

1. **Initializing GL objects in constructor or as field initializers** — No OpenGL context exists yet. Move to `create()`.
2. **Looking for an `update()` method** — It doesn't exist. Put logic in `render()`.
3. **Using `Gdx.app.getDeltaTime()`** — Wrong location. It's `Gdx.graphics.getDeltaTime()`.
4. **Forgetting to dispose native resources** — Texture, SpriteBatch, BitmapFont, Sound, Music, etc. all leak if not disposed. Use `AssetManager` for non-trivial projects.
5. **Implementing `ApplicationListener` directly** — Use `ApplicationAdapter` to avoid empty method stubs.
6. **Assuming desktop pause() fires on focus loss** — On LWJGL3, only iconification (minimize) triggers it. Focus loss alone does nothing.
7. **Manually reloading textures on Android resume** — libGDX reloads managed resources automatically. Only raw GL handles need manual recreation.
8. **Assuming render() keeps running on Android during pause** — The render loop stops entirely. Use a background thread or Android service for work that must continue.
9. **Treating Gdx.app.exit() as immediate** — It schedules shutdown. Code after `exit()` still executes in the current frame.
10. **Missing configChanges in Android manifest** — Without `orientation|screenSize` in `android:configChanges`, rotation destroys and recreates the Activity instead of calling `resize()`.

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [kyu-n](https://github.com/kyu-n)
- **Source:** [kyu-n/gdx-claude-skills](https://github.com/kyu-n/gdx-claude-skills)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-kyu-n-gdx-claude-skills-libgdx-application-lifecycle
- Seller: https://agentstack.voostack.com/s/kyu-n
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
