2010-03-05 17 views
7

Ho inserito il campo del mio database nella cartella "assets". E usa il codice da questo blog per copiare il database in "/ data/data/my_packname/databases /", (Questo codice di copia lo eseguo nel metodo onCreate() quando eseguo questa app) quindi uso select * da .. per ottenere dati. Ma mi fa l'eccezione: nessun tavolo del genere.Come utilizzare il mio database SQLite?

Qualcuno mi ha detto che se sto tentando di copiare il file su onCreate() di SQLiteOpenHelper, è troppo tardi. Quindi il codice del file di copia non può copiare il file completo.

Quindi ho bisogno di usare adb o ddms per estrarre il database prima?

Quindi, chiunque può insegnarmi come utilizzare il mio database? Puoi dirmi la configurazione?

risposta

1

Dopo aver copiato il database, è necessario provare a chiudere e riaprire l'oggetto SQLiteDatabase prima di eseguire qualsiasi query su di esso. Ho avuto un problema simile con la copia di un db da un flusso di input e questo è quello che ha risolto per me.

11

Ho usato le istruzioni in quel post del blog e li ho trovati, mentre sulla strada giusta, complicare seriamente il problema estendendo inutilmente lo SQLiteOpenHelper. Ho avuto fortuna molto meglio nel seguente modo:

  1. Creare una classe di utilità che crea il db statica copiandolo nella directory corretta delle attività, ma non ottiene per sé così appeso a seguire la SQLiteOpenHelper formato.

  2. Utilizzando la stessa classe di utilità per aprire il db utilizzando SQLiteDatabase.openDatabase()

Edit: Ecco una versione di questa classe di utilità che ho creato; non è del tutto completo, ma avrai la deriva.

public class DbUtils { 
    private static final String DB_PATH = "/data/data/com.mypackage.myapp/databases/"; 
    private static final String DB_NAME = "my.db"; 

    public static void createDatabaseIfNotExists(Context context) throws IOException { 
     boolean createDb = false; 

     File dbDir = new File(DB_PATH); 
     File dbFile = new File(DB_PATH + DB_NAME); 
     if (!dbDir.exists()) { 
      dbDir.mkdir(); 
      createDb = true; 
     } 
     else if (!dbFile.exists()) { 
      createDb = true; 
     } 
     else { 
      // Check that we have the latest version of the db 
      boolean doUpgrade = false; 

      // Insert your own logic here on whether to upgrade the db; I personally 
      // just store the db version # in a text file, but you can do whatever 
      // you want. I've tried MD5 hashing the db before, but that takes a while. 

      // If we are doing an upgrade, basically we just delete the db then 
      // flip the switch to create a new one 
      if (doUpgrade) { 
       dbFile.delete(); 
       createDb = true; 
      } 
     } 

     if (createDb) { 
      // Open your local db as the input stream 
      InputStream myInput = context.getAssets().open(DB_NAME); 

      // Open the empty db as the output stream 
      OutputStream myOutput = new FileOutputStream(dbFile); 

      // transfer bytes from the inputfile to the outputfile 
      byte[] buffer = new byte[1024]; 
      int length; 
      while ((length = myInput.read(buffer)) > 0) { 
       myOutput.write(buffer, 0, length); 
      } 

      // Close the streams 
      myOutput.flush(); 
      myOutput.close(); 
      myInput.close(); 
     } 
    } 

    public static SQLiteDatabase getStaticDb() { 
     return SQLiteDatabase.openDatabase(DB_PATH + DB_NAME, null, SQLiteDatabase.OPEN_READONLY); 
    } 
} 
+0

Puoi condividere la classe di utilità? Perché non lo capisco: "Non si fa così appeso" Grazie mille – user275788

+0

Ho aggiunto una versione molto ridotta della mia classe di utilità, lasciando solo la carne del codice. (Ad esempio, consiglio vivamente di aggiungere istruzioni Log, ma quelle non sono necessarie per questo codice di esempio). Ad ogni modo, in questa versione del codice, tutto ciò che devi fare è chiamare createDatabaseIfNotExists() all'avvio dell'applicazione, ad esempio se estendi onCreate() in android.app.Application. –

+0

Ricorda inoltre che se le dimensioni del tuo file superano 1MB il read() lancia IoException e i log delle risorse "I dati superano UNCOMPRESSED_DATA_MAX" ...Ho risolto il problema nominando il mio file .jpg in risorse -> aapt non ha provato a comprimerlo – Mikpa

-1

Il modo di creare database da un articolo che hai postato è leggermente differente da quella come si fa negli esempi Android (non voglio dire se è buono o cattivo).

ho imparato come utilizzare i database da SDKs NotePad sample

E 'buon esempio da cui partire, siccome esso copre sia argomento creazione del database e l'accesso al database attraverso ContentProvider (è davvero l'unico buon modo per ottenere i dati dal db, altrimenti si avranno problemi quando si tenta di ottenere dati simultaneamente da molte parti del codice).

Si noti che SQLiteOpenHelper è molto potente e "ti aiuterà" se lo utilizzerai correttamente. Ad esempio memorizza la versione corrente del database (non la versione sqlite ma il numero che si assegna con la versione dello schema del database) e quando si crea una nuova versione dell'applicazione con una nuova struttura del database è possibile aggiornare lo schema corrente alla nuova versione in onUpdate.

+0

Non penso che tu capisca lo scopo del post sul blog; l'esempio di NotePad è per * creare * un database, ma ciò che l'interrogante vuole fare è creare un database nel dispositivo basato su un db sqlite preesistente. –

+0

Lo so, ma l'intervistatore voleva anche sapere come usare i database in Android che non sono coperti dal post. – skyman

0

questa è la mia versione da "Silvio Donnini" Codice :), ora è possibile aggiornare facilmente il database.

private static final String DB_PATH = "/data/data/pakagename/databases/"; 
private static final String DB_NAME = "databaseName";  
private static SQLiteDatabase db; 

public static void createDatabaseIfNotExists(Context context,int version) throws IOException { 
    boolean createDb = false; 

    File dbDir = new File(DB_PATH); 
    File dbFile = new File(DB_PATH + DB_NAME); 
    if (!dbDir.exists()) { 
     dbDir.mkdir(); 
     createDb = true; 
    } 
    else if (!dbFile.exists()) { 
     createDb = true; 
    } 
    else { 
     // Check that we have the latest version of the db  
     db = SQLiteDatabase.openDatabase(DB_PATH + DB_NAME, null, SQLiteDatabase.OPEN_READONLY); 

     if (db.getVersion() != version) { 
      dbFile.delete(); 
      createDb = true; 
     } 

    } 

    if (createDb) { 

     // Open your local db as the input stream 
     InputStream myInput = context.getResources().openRawResource(R.raw.database); 

     // Open the empty db as the output stream 
     OutputStream myOutput = new FileOutputStream(dbFile); 

     // transfer bytes from the inputfile to the outputfile 
     byte[] buffer = new byte[1024]; 
     int length; 
     while ((length = myInput.read(buffer)) > 0) { 
      myOutput.write(buffer, 0, length); 
     } 

     // Close the streams 
     myOutput.flush(); 
     myOutput.close(); 
     myInput.close(); 
     SQLiteDatabase dbwrite = SQLiteDatabase.openDatabase(DB_PATH + DB_NAME, null, SQLiteDatabase.OPEN_READWRITE); 
     dbwrite.setVersion(version); 
     dbwrite.close(); 
     if (db != null) 
      db = SQLiteDatabase.openDatabase(DB_PATH + DB_NAME, null, SQLiteDatabase.OPEN_READONLY); 

    } 
} 

public static SQLiteDatabase getStaticDb() { 
    if (db != null) 
     return db; 

    return SQLiteDatabase.openDatabase(DB_PATH + DB_NAME, null, SQLiteDatabase.OPEN_READONLY); 
} 
0

So che questa è una vecchia questione, ma ho perso un sacco di tempo capire che fuori, con l'aiuto di tutte le risposte.


Il problema è che un dispositivo memorizza un database nella sua cartella di dati/dati /.../ database. Quindi, quando cambi sth sul database (nome, aggiungi la tabella dei metadati Android, la dimensione ..) non farà alcuna differenza a causa del database memorizzato e del metodo che ha verificato il database esistente.


Per ottenere la nuova banca dati, dopo averlo cambiato, è necessario eseguire il programma senza controllare per databses esistenti (ad esempio, invece di dbExist = checkDataBase(); renderlo solo false).

dbExist = checkDataBase(); 

Passa a:

dbExists = false; 

Dopo è stato sollevato il "nuovo" databse è possibile tornare a controllare quelli esistenti.

Speranza che aiuta qualcuno, dina

0

So che questo è un vecchio post, ma per chi ancora arrivare dopo un Google o una ricerca Bing, questa è la soluzione al problema dichiarato:

in createDataBase() c'è il seguente controllo;

this.getReadableDatabase(); 

Questo controlla se c'è già un database con il nome fornito e se non crea un database vuoto in modo che possa essere sovrascritto con quello nella cartella Assets. Sui dispositivi più recenti funziona perfettamente, ma ci sono alcuni dispositivi sui quali questo non funziona. Dispositivi principalmente vecchi. Non so esattamente perché, ma sembra che la funzione getReadableDatabase() non solo recuperi il database ma lo apra. Se quindi si copia il database dalla cartella delle risorse su di esso, ha ancora il puntatore a un database vuoto e si otterrà la tabella non esiste errori.

Quindi, al fine di farlo funzionare su tutti i dispositivi si dovrebbe modificarlo per le seguenti linee:

SQLiteDatabase db = this.getReadableDatabase(); 
if (db.isOpen()){ 
    db.close(); 
} 

Anche se il database viene aperto nel controllo, è chiuso da allora in poi e non daresti altri problemi.

0

Calmati ragazzi, dopo lunghe ricerche finalmente trovato stupido errore per "tale tabella" errore

Controllare nome di database nella cartella Assets se è come "DATABASE_NAME.EXTENSION" poi mettere il nome completo della classe Helper con estensione ha risolto il mio problema.

come dire nel nome delle risorse del database è login.sqlite o login.db qualsiasi cosa. metti DB_NAME = login.sqlite completamente con extention. this tutorial ora funziona perfettamente.

Problemi correlati