You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Android平台的LibGDX应用中使用SQLite数据库

Hey there! Since you're building an Android game with LibGDX and need SQLite for user authentication, game stats, and timestamp storage—here's a practical, step-by-step solution that aligns with your relational database design:

Core Implementation Approach

LibGDX doesn't include built-in SQLite support, but since you're targeting Android specifically, we can leverage Android's native SQLiteOpenHelper to handle database creation, upgrades, and operations. We'll wrap this in a clean, reusable layer that integrates smoothly with your LibGDX game logic.

Step-by-Step Implementation

1. Create a SQLite Database Helper Class

This class manages database setup and versioning. It will create your user and game stats tables based on your relational design:

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class GameDatabaseHelper extends SQLiteOpenHelper {
    private static final String DATABASE_NAME = "GameDB.db";
    private static final int DATABASE_VERSION = 1;

    // User Table Schema
    private static final String TABLE_USERS = "users";
    private static final String COL_USER_ID = "user_id";
    private static final String COL_USERNAME = "username";
    private static final String COL_PASSWORD = "password"; // *Always encrypt this!*

    // Game Stats Table Schema
    private static final String TABLE_STATS = "game_stats";
    private static final String COL_STAT_ID = "stat_id";
    private static final String COL_USER_FK = "user_id";
    private static final String COL_TIMESTAMP = "timestamp";
    private static final String COL_SCORE = "score";

    public GameDatabaseHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        // Create Users Table
        String createUsersTable = String.format(
            "CREATE TABLE %s (%s INTEGER PRIMARY KEY AUTOINCREMENT, %s TEXT UNIQUE NOT NULL, %s TEXT NOT NULL)",
            TABLE_USERS, COL_USER_ID, COL_USERNAME, COL_PASSWORD
        );
        db.execSQL(createUsersTable);

        // Create Game Stats Table (with foreign key to users)
        String createStatsTable = String.format(
            "CREATE TABLE %s (%s INTEGER PRIMARY KEY AUTOINCREMENT, %s INTEGER NOT NULL, %s INTEGER NOT NULL, %s INTEGER NOT NULL, FOREIGN KEY(%s) REFERENCES %s(%s))",
            TABLE_STATS, COL_STAT_ID, COL_USER_FK, COL_TIMESTAMP, COL_SCORE, COL_USER_FK, TABLE_USERS, COL_USER_ID
        );
        db.execSQL(createStatsTable);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // *Important: In production, add data migration logic instead of dropping tables!*
        db.execSQL("DROP TABLE IF EXISTS " + TABLE_STATS);
        db.execSQL("DROP TABLE IF EXISTS " + TABLE_USERS);
        onCreate(db);
    }
}

Critical Note: Never store plain-text passwords. Use a hashing algorithm like SHA-256 (or stronger) to encrypt passwords before saving them.

2. Integrate the Database with LibGDX

LibGDX's core logic is platform-agnostic, so we'll pass the database helper from your Android launcher to your game's main class:

// AndroidLauncher.java (Android-specific entry point)
import android.os.Bundle;
import com.badlogic.gdx.backends.android.AndroidApplication;
import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration;

public class AndroidLauncher extends AndroidApplication {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        AndroidApplicationConfiguration config = new AndroidApplicationConfiguration();
        
        // Initialize the database helper
        GameDatabaseHelper dbHelper = new GameDatabaseHelper(this);
        
        // Pass it to your LibGDX game instance
        initialize(new MyGame(dbHelper), config);
    }
}

Then in your main game class:

// MyGame.java (LibGDX core game class)
import com.badlogic.gdx.Game;

public class MyGame extends Game {
    private GameDataManager dataManager;

    public MyGame(GameDatabaseHelper dbHelper) {
        dataManager = new GameDataManager(dbHelper);
    }

    @Override
    public void create() {
        // Use dataManager for all database operations in your game screens
    }

    @Override
    public void dispose() {
        super.dispose();
        dataManager.close(); // Clean up database resources
    }
}

3. Build a Data Access Layer (DAO)

Wrap all database operations in a GameDataManager class to keep your game logic clean and decoupled:

import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteConstraintException;
import android.content.ContentValues;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

public class GameDataManager {
    private SQLiteDatabase db;
    private GameDatabaseHelper dbHelper;

    public GameDataManager(GameDatabaseHelper helper) {
        dbHelper = helper;
        db = helper.getWritableDatabase();
    }

    // Register a new user
    public boolean registerUser(String username, String password) {
        String encryptedPassword = encryptPassword(password);
        ContentValues values = new ContentValues();
        values.put(GameDatabaseHelper.COL_USERNAME, username);
        values.put(GameDatabaseHelper.COL_PASSWORD, encryptedPassword);

        try {
            long insertId = db.insert(GameDatabaseHelper.TABLE_USERS, null, values);
            return insertId != -1; // Return true if insertion succeeded
        } catch (SQLiteConstraintException e) {
            return false; // Username already exists
        }
    }

    // Validate user login
    public boolean loginUser(String username, String password) {
        String encryptedPassword = encryptPassword(password);
        String[] projection = {GameDatabaseHelper.COL_USER_ID};
        String selection = String.format("%s = ? AND %s = ?",
            GameDatabaseHelper.COL_USERNAME, GameDatabaseHelper.COL_PASSWORD);
        String[] selectionArgs = {username, encryptedPassword};

        Cursor cursor = db.query(
            GameDatabaseHelper.TABLE_USERS,
            projection,
            selection,
            selectionArgs,
            null, null, null
        );

        boolean isValid = cursor.getCount() > 0;
        cursor.close();
        return isValid;
    }

    // Save game statistics for a user
    public long saveGameStat(int userId, long timestamp, int score) {
        ContentValues values = new ContentValues();
        values.put(GameDatabaseHelper.COL_USER_FK, userId);
        values.put(GameDatabaseHelper.COL_TIMESTAMP, timestamp);
        values.put(GameDatabaseHelper.COL_SCORE, score);

        return db.insert(GameDatabaseHelper.TABLE_STATS, null, values);
    }

    // Fetch all game stats for a user
    public List<GameStat> getUserStats(int userId) {
        List<GameStat> stats = new ArrayList<>();
        String selection = GameDatabaseHelper.COL_USER_FK + " = ?";
        String[] selectionArgs = {String.valueOf(userId)};
        String sortOrder = GameDatabaseHelper.COL_TIMESTAMP + " DESC";

        Cursor cursor = db.query(
            GameDatabaseHelper.TABLE_STATS,
            null,
            selection,
            selectionArgs,
            null, null, sortOrder
        );

        if (cursor.moveToFirst()) {
            do {
                int statId = cursor.getInt(cursor.getColumnIndexOrThrow(GameDatabaseHelper.COL_STAT_ID));
                long timestamp = cursor.getLong(cursor.getColumnIndexOrThrow(GameDatabaseHelper.COL_TIMESTAMP));
                int score = cursor.getInt(cursor.getColumnIndexOrThrow(GameDatabaseHelper.COL_SCORE));
                stats.add(new GameStat(statId, userId, timestamp, score));
            } while (cursor.moveToNext());
        }
        cursor.close();
        return stats;
    }

    // Password encryption helper (use a stronger method like Argon2 in production)
    private String encryptPassword(String password) {
        try {
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            byte[] hash = digest.digest(password.getBytes(StandardCharsets.UTF_8));
            StringBuilder hexBuilder = new StringBuilder();
            for (byte b : hash) {
                String hex = Integer.toHexString(0xff & b);
                if (hex.length() == 1) hexBuilder.append('0');
                hexBuilder.append(hex);
            }
            return hexBuilder.toString();
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("Password encryption failed", e);
        }
    }

    // Clean up database resources
    public void close() {
        dbHelper.close();
    }
}

// Game Stat data model
class GameStat {
    private int statId;
    private int userId;
    private long timestamp;
    private int score;

    public GameStat(int statId, int userId, long timestamp, int score) {
        this.statId = statId;
        this.userId = userId;
        this.timestamp = timestamp;
        this.score = score;
    }

    // Add getters as needed for your game logic
}
Key Best Practices
  • Thread Safety: Never run database operations on the UI thread—use AsyncTask, Kotlin Coroutines, or a background thread pool to avoid ANRs (Application Not Responding) errors.
  • Data Migration: For future database updates, replace the table-dropping logic in onUpgrade with proper data migration (e.g., altering tables instead of recreating them) to preserve user data.
  • Database Encryption: For sensitive data, consider using SQLCipher to encrypt the entire database file, preventing unauthorized access if the device is rooted.
  • Resource Management: Always close Cursor and SQLiteDatabase instances when done to avoid memory leaks.

内容的提问来源于stack exchange,提问作者Shahzeb Manjlai

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 07:52:12