agentsclimarketplace

Libgdx android backend

Skill kyu-n/gdx-claude-skills/skills/libgdx-android-backend

Use when writing libGDX Java/Kotlin code targeting Android — AndroidApplication launcher, AndroidApplicationConfiguration, AndroidManifest.xml setup, Android lifecycle mapping to libGDX, OpenGL context loss on pause, file access (internal/local/external with permissions), Android input (back button, accelerometer, on-screen keyboard), screen density, safe insets/notch, or GL thread posting. Use when debugging black textures after resume, Activity recreation on rotation, or missing file permissions.From its SKILL.md

Install
npx -y skills add kyu-n/gdx-claude-skills --skill libgdx-android-backend

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 4 stars4 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

12.2 KB, ~2.9k tokens by cl100k_base, as published. Nobody here has run it

libGDX Android Backend

Reference for Android-specific launcher setup, manifest configuration, lifecycle mapping, file access, input handling, screen density, safe insets, and threading.

Launcher Setup

AndroidApplication extends Activity. Call initialize() in onCreate():

public class AndroidLauncher extends AndroidApplication {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        AndroidApplicationConfiguration config = new AndroidApplicationConfiguration();
        config.useAccelerometer = true;   // default true — set false to save battery
        config.useCompass = false;        // default true — set false to save battery
        config.useGyroscope = false;      // default false
        config.useImmersiveMode = true;   // hides nav/status bars — libGDX handles it fully
        config.numSamples = 2;            // MSAA anti-aliasing (0 = off)
        config.useWakelock = true;        // keeps screen on during gameplay
        config.useGL30 = false;           // set true for GL ES 3.0 (Gdx.gl30); null if false
        initialize(new MyGame(), config);
    }
}

Do NOT add manual immersive mode code (deprecated SYSTEM_UI_FLAG_* constants, onWindowFocusChanged(), visibility listeners). config.useImmersiveMode = true is sufficient — libGDX manages the system UI internally. Never show working SYSTEM_UI_FLAG code examples, even as a "what not to do" — users will copy them.

For Fragment-based hosting, use AndroidFragmentApplication instead of AndroidApplication. It extends Fragment and works with FragmentActivity.

AndroidManifest.xml

<activity
    android:name=".AndroidLauncher"
    android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
    android:screenOrientation="landscape"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

android:configChanges is critical. Without orientation|screenSize, Android destroys and recreates the Activity on rotation — a full dispose()create() cycle with GL context loss. With it, libGDX handles rotation via resize().

Permissions

PermissionWhen needed
WRITE_EXTERNAL_STORAGEGdx.files.external() — also needs runtime permission on API 23+
INTERNETAny networking (HttpURLConnection, WebSocket, etc.)
VIBRATEHaptic feedback via Gdx.input.vibrate()
WAKE_LOCKAdded automatically when config.useWakelock = true

Runtime permissions (API 23+): libGDX has no cross-platform permission API. Request in the launcher:

// In AndroidLauncher (any class extending AndroidApplication works)
if (Build.VERSION.SDK_INT >= 23) {
    requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE);
}
// Result arrives in onRequestPermissionsResult() — check grantResults before using external()

Lifecycle Mapping

AndroidlibGDXWhat happens
onCreate()create()App initialization
onResume()resume()App returns to foreground
onPause()pause()App goes to background
finish() / system killdispose()App shutting down

Use libGDX's ApplicationListener callbacks (create/render/pause/resume/dispose), NOT Android Activity lifecycle methods directly. Override onCreate() only for the launcher's initialize() call.

The render loop stops entirely during pause on Android. Any work in render() — timers, heartbeats, network pings — ceases when the app is backgrounded. Use a background thread or Android service for work that must continue.

OpenGL Context Loss on Pause

On Android, the OpenGL context IS destroyed when the app is paused. This is not limited to older devices — it happens on ALL Android versions.

  • Managed resources (Texture, SpriteBatch, ShaderProgram, BitmapFont, FrameBuffer loaded via libGDX APIs) are automatically reloaded by libGDX on resume. You do not need to manually reload them.
  • Custom non-managed GL resources (raw GL handles created via Gdx.gl.glGenTexture(), Gdx.gl.glCreateProgram(), etc.) must be recreated manually — register an invalidation callback or recreate in resume().
// WRONG — unnecessary manual reloading
@Override
public void resume() {
    texture = new Texture("sprite.png");  // libGDX already reloaded it
}

// RIGHT — only recreate raw GL handles if you have any
@Override
public void resume() {
    if (customGLHandle != 0) {
        customGLHandle = createRawGLResource();  // only for non-managed resources
    }
}

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

File Access

FileTypeMaps toPermission needed
Gdx.files.internal("file")Android assets/ folderNone (read-only, bundled with APK)
Gdx.files.local("file")Context.getFilesDir() (app-internal storage)None (private to app)
Gdx.files.external("file")App-specific external storage (getExternalFilesDir())WRITE_EXTERNAL_STORAGE + runtime permission on API 23+
Gdx.files.absolute("/path")Literal filesystem pathDiscouraged on Android — use local() or external()
// Save game — use local(), not external() (no permission needed)
FileHandle saveFile = Gdx.files.local("savegame.json");
saveFile.writeString(json, false);

// Load game
if (Gdx.files.local("savegame.json").exists()) {
    String json = Gdx.files.local("savegame.json").readString();
}

// Read bundled asset (from android/assets/)
String levelData = Gdx.files.internal("levels/level1.json").readString();

Do NOT use desktop-style paths like "./saves/game.sav" or System.getProperty("user.home") on Android. These don't map to accessible storage.

Input

Back Button

By default, the Android back button exits the Activity. To intercept it:

// In create() or show()
Gdx.input.setCatchKey(Input.Keys.BACK, true);

// In your InputProcessor.keyDown()
@Override
public boolean keyDown(int keycode) {
    if (keycode == Input.Keys.BACK) {
        // show pause menu, go to previous screen, etc.
        return true;
    }
    return false;
}

setCatchBackKey(boolean) is deprecated. Use setCatchKey(Input.Keys.BACK, true) instead.

Touch Input

Touch is the primary input on Android. Multi-touch uses the pointer index (0 = first finger, 1 = second, etc.):

// Polling
if (Gdx.input.isTouched(0)) {
    float x = Gdx.input.getX(0);
    float y = Gdx.input.getY(0);
}

Accelerometer / Gyroscope

Must be enabled in AndroidApplicationConfiguration (accelerometer is enabled by default):

float ax = Gdx.input.getAccelerometerX();  // tilt left/right
float ay = Gdx.input.getAccelerometerY();  // tilt forward/back
float az = Gdx.input.getAccelerometerZ();  // up/down (gravity)

On-Screen Keyboard

// Show/hide soft keyboard
Gdx.input.setOnscreenKeyboardVisible(true);

// Dialog-based text input (shows native Android dialog)
Gdx.input.getTextInput(new Input.TextInputListener() {
    @Override
    public void input(String text) { /* user entered text */ }
    @Override
    public void canceled() { /* user cancelled */ }
}, "Title", "default value", "hint");

Screen Density

Gdx.graphics.getWidth()/getHeight() returns the actual pixel resolution, which varies widely across Android devices. Use getDensity() to convert between density-independent units (dp) and pixels:

float density = Gdx.graphics.getDensity();
// 1.0 = mdpi (160 dpi), 1.5 = hdpi, 2.0 = xhdpi, 3.0 = xxhdpi, 4.0 = xxxhdpi
float pixelSize = 48 * density;  // 48dp → pixels

Safe Insets (Notch / Cutout)

libGDX provides safe inset values directly — no need for a custom platform interface or raw Android DisplayCutout API:

int top = Gdx.graphics.getSafeInsetTop();
int bottom = Gdx.graphics.getSafeInsetBottom();
int left = Gdx.graphics.getSafeInsetLeft();
int right = Gdx.graphics.getSafeInsetRight();

Available since libGDX 1.9.10+. Returns pixels. Use these to offset UI elements away from notches and rounded corners.

Threading

render() runs on the GL thread. All OpenGL calls must happen on this thread.

To run code on the GL thread from another thread (e.g., network callback, Android UI thread):

// From a network thread:
Gdx.app.postRunnable(new Runnable() {
    @Override
    public void run() {
        // Runs on the GL thread next frame — safe to create textures, update game state
        Pixmap pixmap = new Pixmap(downloadedBytes, 0, downloadedBytes.length);
        texture = new Texture(pixmap);
        pixmap.dispose();
    }
});

Never create or modify GL resources from a non-GL thread. This causes silent corruption or crashes.

Gradle / Android Studio

The android module has its own build.gradle with the Android plugin:

android {
    compileSdkVersion 34
    minSdkVersion 19        // libGDX minimum
    targetSdkVersion 34

    defaultConfig {
        applicationId "com.yourpackage.game"
    }
}

dependencies {
    implementation project(":core")
    implementation "com.badlogicgames.gdx:gdx-backend-android:$gdxVersion"
    natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-armeabi-v7a"
    natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-arm64-v8a"
    natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-x86"
    natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-x86_64"
}

Note: The exact dependency syntax depends on the project generator (gdx-liftoff vs older gdx-setup). The natives configuration above is from the standard template — newer generators may use different syntax.

Common Mistakes

  1. Adding manual immersive mode codeconfig.useImmersiveMode = true is all you need. Don't add SYSTEM_UI_FLAG_* listeners or onWindowFocusChanged() overrides.
  2. Thinking GL context loss is only on old devices — It happens on ALL Android versions when the app is paused. Managed resources are auto-reloaded; only raw GL handles need manual recreation.
  3. Manually reloading managed textures in resume() — libGDX handles this. Creating new Texture objects in resume() leaks the originals.
  4. Using Activity lifecycle methods instead of libGDX callbacks — Use create()/render()/pause()/resume()/dispose(), not onStart()/onResume()/onPause().
  5. Missing configChanges in manifest — Without keyboard|keyboardHidden|orientation|screenSize, rotation destroys and recreates the Activity instead of calling resize().
  6. Using Gdx.files.external() without permissions — Needs WRITE_EXTERNAL_STORAGE in manifest AND runtime permission request on API 23+. Prefer Gdx.files.local() for save data.
  7. Using desktop-style file paths on Android"./saves/", System.getProperty("user.home") don't work. Use Gdx.files.local() or Gdx.files.internal().
  8. Creating GL resources off the GL thread — Network callbacks and Android UI callbacks are NOT on the GL thread. Use Gdx.app.postRunnable() to marshal work to the GL thread.
  9. Using deprecated setCatchBackKey() — Use Gdx.input.setCatchKey(Input.Keys.BACK, true) instead.
  10. Saving critical state only in dispose() — On Android, dispose() may not be called if the OS kills the process. Save in pause().
  11. Building a custom platform interface for safe insets — libGDX has Gdx.graphics.getSafeInsetTop() etc. built in (since 1.9.10+). No need for DisplayCutout API directly.

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Gives 0 of the 12 instructions most data backend skills give in ~2.9k tokens

Counted across 258 of the 277 authors here whose files we hold, read 2026-09-06

  • Centralize error handling in one handlerin 38 of 258, across 20 files
  • Select only needed columns in queriesin 36 of 258, across 18 files
  • Check cache before querying the databasein 36 of 258, across 19 files
  • Wrap multi-step writes in transactionsin 36 of 258, across 18 files
  • Retry failed requests with exponential backoffin 36 of 258, across 18 files
  • Batch fetch related records to avoid N+1 queriesin 34 of 258, across 16 files
  • Use resource-based URLs for REST endpointsin 31 of 258, across 13 files
  • Separate business logic into a service layerin 29 of 258, across 17 files
  • Queue background jobs instead of blocking requestsin 29 of 258, across 14 files
  • Abstract data access behind repository interfacesin 25 of 258, across 13 files
  • Log structured JSON with request contextin 15 of 258, across 7 files
  • Use a shared store for rate limitingin 14 of 258, across 6 files

Said here and by no other author read

  • set android:configChanges with orientation and screenSize
  • use libGDX lifecycle callbacks instead of Activity methods
  • call initialize() with configuration in onCreate()
  • save critical game state in pause()
  • recreate raw GL handles in resume()
  • marshal GL work through Gdx.app.postRunnable()

Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.