2013-04-08 30 views
15

Sono nuovo in Libgdx e sto riscontrando problemi nell'utilizzo di un database sul mio gioco.Utilizzo di un database SQLite in Libgdx

Ho cercato un tutorial su come far funzionare SQLite su entrambe le applicazioni Android e Desktop usando Libgdx ma non ne ho trovato uno facile.

L'ultima volta che ho utilizzato un database in Android, ho creato una classe che si estende da SQLiteOpenHelper.

C'è un modo semplice per fare lo stesso con Libgdx? O almeno, qualcuno può indicarmi un tutorial passo-passo o qualcosa di simile?

EDIT

Ho dimenticato di dire che sto cercando qualcosa che mi permetta di gestire le versioni come SQLiteOpenHelper. In altre parole, voglio ricreare il mio database in Android con l'installazione apk, quando cambio la versione del mio DB sul codice.

SOLUZIONE

seguito @42n4 risposta, sono riuscito come connettersi a SQLite database utilizzando SQLiteOpenHelper su Android Application e JDBC sulle applicazioni desktop.

In primo luogo, ho creato una "classe comune" sia per applicazioni desktop e Android:

//General class that needs to be implemented on Android and Desktop Applications 
public abstract class DataBase { 

    protected static String database_name="recycling_separation"; 
    protected static DataBase instance = null; 
    protected static int version=1; 

    //Runs a sql query like "create". 
    public abstract void execute(String sql); 

    //Identical to execute but returns the number of rows affected (useful for updates) 
    public abstract int executeUpdate(String sql); 

    //Runs a query and returns an Object with all the results of the query. [Result Interface is defined below] 
    public abstract Result query(String sql); 

    public void onCreate(){ 
     //Example of Highscore table code (You should change this for your own DB code creation) 
     execute("CREATE TABLE 'highscores' ('_id' INTEGER PRIMARY KEY NOT NULL , 'name' VARCHAR NOT NULL , 'score' INTEGER NOT NULL);"); 
     execute("INSERT INTO 'highscores'(name,score) values ('Cris',1234)"); 
     //Example of query to get DB data of Highscore table 
     Result q=query("SELECT * FROM 'highscores'"); 
     if (!q.isEmpty()){ 
      q.moveToNext(); 
      System.out.println("Highscore of "+q.getString(q.getColumnIndex("name"))+": "+q.getString(q.getColumnIndex("score"))); 
     } 
    } 

    public void onUpgrade(){ 
     //Example code (You should change this for your own DB code) 
     execute("DROP TABLE IF EXISTS 'highscores';"); 
     onCreate(); 
     System.out.println("DB Upgrade maded because I changed DataBase.version on code"); 
    } 

    //Interface to be implemented on both Android and Desktop Applications 
    public interface Result{ 
     public boolean isEmpty(); 
     public boolean moveToNext(); 
     public int getColumnIndex(String name); 
     public float getFloat(int columnIndex); 
     [...] 
    } 
} 

Poi, ho creato una classe DatabaseDesktop per Desktop Application:

public class DatabaseDesktop extends DataBase{ 
    protected Connection db_connection; 
    protected Statement stmt; 
    protected boolean nodatabase=false; 

    public DatabaseDesktop() { 
     loadDatabase(); 
     if (isNewDatabase()){ 
      onCreate(); 
      upgradeVersion(); 
     } else if (isVersionDifferent()){ 
      onUpgrade(); 
      upgradeVersion(); 
     } 

    } 

    public void execute(String sql){ 
     try { 
      stmt.execute(sql); 
     } catch (SQLException e) { 
      e.printStackTrace(); 
     } 
    } 

    public int executeUpdate(String sql){ 
     try { 
      return stmt.executeUpdate(sql); 
     } catch (SQLException e) { 
      e.printStackTrace(); 
     } 
     return 0; 
    } 

    public Result query(String sql) { 
     try { 
      return new ResultDesktop(stmt.executeQuery(sql)); 
     } catch (SQLException e) { 
      e.printStackTrace(); 
     } 
     return null; 
    } 

    private void loadDatabase(){ 
     File file = new File (database_name+".db"); 
     if(!file.exists()) 
      nodatabase=true; 
     try { 
      Class.forName("org.sqlite.JDBC"); 
      db_connection = DriverManager.getConnection("jdbc:sqlite:"+database_name+".db"); 
      stmt = db_connection.createStatement(); 
     } catch (ClassNotFoundException e) { 
      e.printStackTrace(); 
     } catch (SQLException e) { 
      e.printStackTrace(); 
     } 
    } 

    private void upgradeVersion() { 
     execute("PRAGMA user_version="+version); 
    } 

    private boolean isNewDatabase() { 
     return nodatabase; 
    } 

    private boolean isVersionDifferent(){ 
     Result q=query("PRAGMA user_version"); 
     if (!q.isEmpty()) 
      return (q.getInt(1)!=version); 
     else 
      return true; 
    } 

    public class ResultDesktop implements Result{ 

     ResultSet res; 
     boolean called_is_empty=false; 

     public ResultDesktop(ResultSet res) { 
      this.res = res; 
     } 

     public boolean isEmpty() { 
      try { 
       if (res.getRow()==0){ 
        called_is_empty=true; 
        return !res.next(); 
       } 
       return res.getRow()==0; 
      } catch (SQLException e) { 
       e.printStackTrace(); 
      } 
      return false; 
     } 

     public boolean moveToNext() { 
      try { 
       if (called_is_empty){ 
        called_is_empty=false; 
        return true; 
       } else 
        return res.next(); 
      } catch (SQLException e) { 
       e.printStackTrace(); 
      } 
      return false; 
     } 

     public int getColumnIndex(String name) { 
      try { 
       return res.findColumn(name); 
      } catch (SQLException e) { 
       e.printStackTrace(); 
      } 
      return 0; 
     } 

     public float getFloat(int columnIndex) { 
      try { 
       return res.getFloat(columnIndex); 
      } catch (SQLException e) { 
       e.printStackTrace(); 
      } 
      return 0; 
     } 

     [...] 

    } 

} 

E un DatabaseAndroid per Android Applicazione

public class DatabaseAndroid extends DataBase{ 
    protected SQLiteOpenHelper db_connection; 
    protected SQLiteDatabase stmt; 

    public DatabaseAndroid(Context context) { 
     db_connection = new AndroidDB(context, database_name, null, version); 
     stmt=db_connection.getWritableDatabase(); 
    } 

    public void execute(String sql){ 
     stmt.execSQL(sql); 
    } 

    public int executeUpdate(String sql){ 
     stmt.execSQL(sql); 
     SQLiteStatement tmp = stmt.compileStatement("SELECT CHANGES()"); 
     return (int) tmp.simpleQueryForLong(); 
    } 

    public Result query(String sql) { 
     ResultAndroid result=new ResultAndroid(stmt.rawQuery(sql,null)); 
     return result; 
    } 

    class AndroidDB extends SQLiteOpenHelper { 

     public AndroidDB(Context context, String name, CursorFactory factory, 
       int version) { 
      super(context, name, factory, version); 
     } 

     public void onCreate(SQLiteDatabase db) { 
      stmt=db; 
      DatabaseAndroid.this.onCreate(); 
     } 

     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 
      stmt=db; 
      DatabaseAndroid.this.onUpgrade(); 
     } 

    } 

    public class ResultAndroid implements Result{ 
     Cursor cursor; 

     public ResultAndroid(Cursor cursor) { 
      this.cursor=cursor; 
     } 

     public boolean isEmpty() { 
      return cursor.getCount()==0; 
     } 

     public int getColumnIndex(String name) { 
      return cursor.getColumnIndex(name); 
     } 

     public String[] getColumnNames() { 
      return cursor.getColumnNames(); 
     } 

     public float getFloat(int columnIndex) { 
      return cursor.getFloat(columnIndex); 
     } 

     [...] 

    } 

} 

Infine, I cha nged le principali classi di entrambe le applicazioni Android e desktop:

public class Main extends AndroidApplication { 

    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     initialize(new MyGame(new DatabaseAndroid(this.getBaseContext())), false); 
    } 
} 

public class Main { 

    public static void main(String[] args) { 
     new LwjglApplication(new MyGame(new DatabaseDesktop()), "Example", MyGame.SCREEN_WIDTH, MyGame.SCREEN_HEIGHT,false); 
    } 

} 

Nota che:

Ho fatto una gestione delle versioni come quello che accade in SQLiteOpenHelper utilizzando il PRAGMA user_version. In questo modo, ho appena cambiato la versione della classe DataBase quando ho bisogno di aggiornarlo.

Non ho messo tutti i metodi che ho fatto su Result ma, ho messo quelli che penso siano più importanti. Sono più importanti.

risposta

3

http://marakana.com/techtv/android_bootcamp_screencast_series.html classe 4, Parte 1: Android Bootcamp - statusData, per libgdx: http://code.google.com/p/libgdx-users/wiki/SQLite

EDIT: Devo dire circa due nuovi corsi sui giochi libgdx a Udacity: https://github.com/udacity/ud405

https://github.com/udacity/ud406

+0

Quindi, sia per Android che per Desktop, creo una classe denominata 'StatusData', giusto? In Android, posso usare 'SQLiteOpenHelper' come prima. Ma per quanto riguarda l'applicazione Desktop? Come posso, ad esempio, fare in modo che l'applicazione desktop ricrei il DB quando la versione del DB cambia in "StatusData"? –

+0

Forse aiuterà: http://code.google.com/p/libgdx-users/wiki/SQLite – 42n4

+0

Quindi, per essere chiari, posso usare 'SQLiteOpenHelper' su Android e in Desktop potrei fare lo stesso cosa usando 'JDBC' ed entrambi sono creati in una classe chiamata' StatusData' o qualcosa di simile. Destra? –

6

C'è un'estensione (chiamata gdx-sqlite) che ho scritto che farà la maggior parte del lavoro richiesto. L'ultima versione di questa estensione può essere scaricata da here.Il codice sorgente e read me si trovano a: https://github.com/mrafayaleem/gdx-sqlite

Questa estensione attualmente supporta piattaforme Android e desktop. Inoltre, non vi è alcun supporto per aprire i database che si trovano nella cartella delle risorse dell'app Android. Tuttavia, questa è una funzionalità in sospeso e verrà presto aggiunta.

Seguire le istruzioni in lettura per configurare i progetti per la gestione del database. Di seguito è riportato un codice di esempio:

package com.mrafayaleem.gdxsqlitetest; 

import com.badlogic.gdx.Gdx; 
import com.badlogic.gdx.sql.Database; 
import com.badlogic.gdx.sql.DatabaseCursor; 
import com.badlogic.gdx.sql.DatabaseFactory; 
import com.badlogic.gdx.sql.SQLiteGdxException; 

public class DatabaseTest { 

    Database dbHandler; 

    public static final String TABLE_COMMENTS = "comments"; 
    public static final String COLUMN_ID = "_id"; 
    public static final String COLUMN_COMMENT = "comment"; 

    private static final String DATABASE_NAME = "comments.db"; 
    private static final int DATABASE_VERSION = 1; 

    // Database creation sql statement 
    private static final String DATABASE_CREATE = "create table if not exists " 
      + TABLE_COMMENTS + "(" + COLUMN_ID 
      + " integer primary key autoincrement, " + COLUMN_COMMENT 
      + " text not null);"; 

    public DatabaseTest() { 
     Gdx.app.log("DatabaseTest", "creation started"); 
     dbHandler = DatabaseFactory.getNewDatabase(DATABASE_NAME, 
       DATABASE_VERSION, DATABASE_CREATE, null); 

     dbHandler.setupDatabase(); 
     try { 
      dbHandler.openOrCreateDatabase(); 
      dbHandler.execSQL(DATABASE_CREATE); 
     } catch (SQLiteGdxException e) { 
      e.printStackTrace(); 
     } 

     Gdx.app.log("DatabaseTest", "created successfully"); 

     try { 
      dbHandler 
        .execSQL("INSERT INTO comments ('comment') VALUES ('This is a test comment')"); 
     } catch (SQLiteGdxException e) { 
      e.printStackTrace(); 
     } 

     DatabaseCursor cursor = null; 

     try { 
      cursor = dbHandler.rawQuery("SELECT * FROM comments"); 
     } catch (SQLiteGdxException e) { 
      e.printStackTrace(); 
     } 
     while (cursor.next()) { 
      Gdx.app.log("FromDb", String.valueOf(cursor.getString(1))); 
     } 

     try { 
      dbHandler.closeDatabase(); 
     } catch (SQLiteGdxException e) { 
      e.printStackTrace(); 
     } 
     dbHandler = null; 
     Gdx.app.log("DatabaseTest", "dispose"); 
    } 
} 
Problemi correlati