CERCA
PER MODELLO
FullScreen Chatbox! :)

Utente del giorno: 9mm con ben 1 Thanks ricevuti nelle ultime 24 ore
Utente della settimana: elmegio con ben 7 Thanks ricevuti negli ultimi sette giorni
Utente del mese: bluemask con ben 43 Thanks ricevuti nell'ultimo mese

Pagina 1 di 5 123 ... ultimoultimo
Ultima pagina
Visualizzazione dei risultati da 1 a 10 su 49
Discussione:

[ECLIPSE] Copia db sqlite preesistente da 'assets' a /data/data/..

Se questa discussione ti è stata utile, ti preghiamo di lasciare un messaggio di feedback in modo che possa essere preziosa in futuro anche per altri utenti come te!
  1. #1
    Senior Droid L'avatar di frank17next


    Registrato dal
    Jan 2010
    Località
    Campobasso
    Messaggi
    739
    Smartphone
    GNexus, Galaxy Note, GT 10.1

    Ringraziamenti
    16
    Ringraziato 143 volte in 102 Posts
    Predefinito

    [ECLIPSE] Copia db sqlite preesistente da 'assets' a /data/data/..

    Ciao ragazzi,

    vorrei creare un applicazione che utilizzi un db sqlite esistente (già popolato), senza necessità di crearne uno da zero.
    Non ho nessun problema ad utilizzare dall'applicazione il file del db esistente copiandolo 'a mano' in /data/data/package/databases/nomedb, il db è accessibile e riesco a completare qualsiasi query sui dati esistenti.
    La struttura dell'app è molto semplice, ho utilizzato una classe SQLiteAdapter per l'accesso al db:

    codice:
    package mia.applicazione.test;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import android.content.ContentValues;
    import android.content.Context;
    import android.database.Cursor;
    import android.database.sqlite.SQLiteDatabase;
    import android.database.sqlite.SQLiteException;
    import android.database.sqlite.SQLiteOpenHelper;
    import android.database.sqlite.SQLiteDatabase.CursorFactory;
    
    public class SQLiteAdapter  {
     public static String DB_PATH = "/data/data/mia.applicazione.test/databases/";
     public static final String MYDATABASE_NAME = "sqliteAndroid.sqlite";
     public static final String MYDATABASE_TABLE = "ImportFileChiamata";
     public static final int MYDATABASE_VERSION = 1;
     public static final String KEY_CONTENT = "CodiceChiamata";
    
     
     private SQLiteHelper sqLiteHelper;
     private SQLiteDatabase sqLiteDatabase;
    
     private Context context;
     
     public SQLiteAdapter(Context c){
      context = c;
     }
     
     public SQLiteAdapter openToRead() throws android.database.SQLException {
      sqLiteHelper = new SQLiteHelper(context, MYDATABASE_NAME, null, MYDATABASE_VERSION);
      sqLiteDatabase = sqLiteHelper.getReadableDatabase();
      return this; 
     }
     
     public SQLiteAdapter openToWrite() throws android.database.SQLException {
      sqLiteHelper = new SQLiteHelper(context, MYDATABASE_NAME, null, MYDATABASE_VERSION);
      sqLiteDatabase = sqLiteHelper.getWritableDatabase();
      return this; 
     }
     
     public void close(){
      sqLiteHelper.close();
     }
     
     public long insert(String content){
      
      ContentValues contentValues = new ContentValues();
      contentValues.put(KEY_CONTENT, content);
      return sqLiteDatabase.insert(MYDATABASE_TABLE, null, contentValues);
     }
     
     public int deleteAll(){
      return sqLiteDatabase.delete(MYDATABASE_TABLE, null, null);
     }
     
     public String queueAll(){
      String[] columns = new String[]{KEY_CONTENT};
      Cursor cursor = sqLiteDatabase.query(MYDATABASE_TABLE, columns, 
        null, null, null, null, null);
      String result = "";
      
      int index_CONTENT = cursor.getColumnIndex(KEY_CONTENT);
      for(cursor.moveToFirst(); !(cursor.isAfterLast()); cursor.moveToNext()){
       result = result + cursor.getString(index_CONTENT) + "\n";
      }
     
      return result;
     }
     
     public class SQLiteHelper extends SQLiteOpenHelper {
    
      public SQLiteHelper(Context context, String name,
        CursorFactory factory, int version) {
       super(context, name, factory, version);
      }
    
      @Override
      public void onCreate(SQLiteDatabase db) {
          //db.execSQL(SCRIPT_CREATE_DATABASE);
    	  try {
    		  if (checkDataBase()) {
    		 } 
    		 else 
    			{
    				 copyDatabase();
    			}
    		  } catch (IOException e) {
    	 e.printStackTrace();
    	}
      }
    
      @Override
      public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    
      }
      public void copyDatabase() throws IOException {
    	    InputStream assetsDB = context.getAssets().open("dbtest.sqlite");
    	    OutputStream dbOut = new FileOutputStream("/data/data/mia.applicazione.test/databases/sqliteAndroid.sqlite");
    	 
    	    byte[] buffer = new byte[1024];
    	    int length;
    	    while ((length = assetsDB.read(buffer))>0){
    	      dbOut.write(buffer, 0, length);
    	    }
    	 
    	    dbOut.flush();
    	    dbOut.close();
    	    assetsDB.close();
    	}
      
      public boolean checkDataBase(){
    	  SQLiteDatabase checkDB = null;
      	try{
      		String myPath = DB_PATH + MYDATABASE_NAME;
      		checkDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);
      	}catch(SQLiteException e){
      		//database does't exist yet.
      	}
      	if(checkDB != null){
      		checkDB.close();
      	}
      	return checkDB != null ? true : false;
      }
      
     }
     
    }
    e questa invece è l'activity che, attualmente, ha soltanto un pulsante per eseguire una prova di SELECT su una tabella esistente, memorizza il risultato della query in un array di stringhe e visualizza il contenuto dell'array in un TextView sul Layout principale:

    codice:
    package mia.applicazione.test;
    
    import android.app.Activity;
    import android.content.Context;
    import android.os.Bundle;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    import android.widget.TextView;
    
    public class Applicazione1Activity extends Activity {
        /** Called when the activity is first created. */
    	private SQLiteAdapter miodb; 
    	@Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            Context context = getApplicationContext();
            miodb = new SQLiteAdapter(this);
        	Button mioPulsante1 = (Button) findViewById(R.id.button1);
        	final TextView mioTextView1 = (TextView) findViewById(R.id.textView1);
    		mioPulsante1.setOnClickListener(new OnClickListener() {
        		public void onClick(View v){
        		//istruzioni pulsante
        			miodb.openToRead();
        			String contenutoletto = miodb.queueAll();
        			miodb.close();
        			mioTextView1.setText(contenutoletto);
        		}	
        	});
        }
    }
    Di concetto vorrei sfruttare il metodo OnCreate, della classe SQLiteAdapter, per poter eseguire la copia del database preesistente (che nel package, in Eclipse, inserisco sotto 'Assets') nel path predefinito /data/data/miopacchetto/databases, con un piccolo controllo che se già esiste non deve farlo (qualora si disinstalli e si reinstalli l'apk).
    Il problema è la copia del file sqlite già esistente. Nel senso che la copia del file avviene regolarmente, solo che se faccio pull del file destinazione copiato in /data/data/... ottengo un database vuoto, compresivo solo della tabella android_metadata. In pratica durante la copia il db si 'svuota' di tutte le tabelle preesitenti.
    Cosa potrebbe causare questo effetto? Avete qualche suggerimento/intuizione?
    Nexus 6 - 5.0.1 Stock
    Nexus 5 - 5.0.1 Stock + Root
    Galaxy Note 3 GT-N9005 - 4.4.4 Stock + Root
    Galaxy Tab 10.1 Slim P7500 - [JB] CyanogenMod 10 4.1.2 Pershoot (Nightly 20121013)
    ------------------------------------------------------------------------
    https://sites.google.com/site/frank17next/

  2.  
  3. #2
    Senior Droid L'avatar di frank17next


    Registrato dal
    Jan 2010
    Località
    Campobasso
    Messaggi
    739
    Smartphone
    GNexus, Galaxy Note, GT 10.1

    Ringraziamenti
    16
    Ringraziato 143 volte in 102 Posts
    Predefinito

    Ho capito dov'è il problema.
    Nell'activity principale istanzio subito un oggetto di tipo SQLiteAdapter nel contesto dell'applicazione. Fin qui tutto bene.
    Tuttavia, il metodo openToRead() richiama sqLiteHelper.getReadableDatabase(); prima che la copia fisica del file .db avvenga. Per questo, 'getREadableDatabase()' crea subito un database vuoto e la copia fallisce (da logcat ci sono errori di corrupted file all'apertura, perchè il db è aperto in quel momento). Eseguendo la copia del db prima del getReadableDatabase() il problema rientra.
    Nexus 6 - 5.0.1 Stock
    Nexus 5 - 5.0.1 Stock + Root
    Galaxy Note 3 GT-N9005 - 4.4.4 Stock + Root
    Galaxy Tab 10.1 Slim P7500 - [JB] CyanogenMod 10 4.1.2 Pershoot (Nightly 20121013)
    ------------------------------------------------------------------------
    https://sites.google.com/site/frank17next/

  4. #3
    Baby Droid


    Registrato dal
    Apr 2012
    Messaggi
    30

    Ringraziamenti
    3
    Ringraziato 0 volte in 0 Posts
    Predefinito

    Quote Originariamente inviato da frank17next Visualizza il messaggio
    Ho capito dov'è il problema.
    Nell'activity principale istanzio subito un oggetto di tipo SQLiteAdapter nel contesto dell'applicazione. Fin qui tutto bene.
    Tuttavia, il metodo openToRead() richiama sqLiteHelper.getReadableDatabase(); prima che la copia fisica del file .db avvenga. Per questo, 'getREadableDatabase()' crea subito un database vuoto e la copia fallisce (da logcat ci sono errori di corrupted file all'apertura, perchè il db è aperto in quel momento). Eseguendo la copia del db prima del getReadableDatabase() il problema rientra.

    Ciao,

    ti chiedo la cortesia di spiegarmi come faccio a prendere il db a 'manina' come dici tu.
    é un po che ci ravano dietro e non ne esco fuori.
    Io faccio partire la mia applicazione e il db ha questi parametri:

    public static String DATABASE_NAME = "pro.db";
    public static String DATABASE_PATH = "/data/data/it.sys.mob/databases/";

    private static final int SCHEMA_VERSION = 2;


    ho installato aSQLiteManager perché vorrei vedere lo stato del mio db dopo alcuni cambiamenti, ma non riesco a capire dove trovarlo.
    Aiuto please..

  5. #4
    Baby Droid


    Registrato dal
    Apr 2012
    Messaggi
    30

    Ringraziamenti
    3
    Ringraziato 0 volte in 0 Posts
    Predefinito

    Ciao frank17next,

    perché vedo che tu lo metti in assets e poi lo copi.. quindi ci sei arrivato fin li.
    Dimmi come hai fai ti prego..

  6. #5
    Senior Droid L'avatar di frank17next


    Registrato dal
    Jan 2010
    Località
    Campobasso
    Messaggi
    739
    Smartphone
    GNexus, Galaxy Note, GT 10.1

    Ringraziamenti
    16
    Ringraziato 143 volte in 102 Posts
    Predefinito

    Quote Originariamente inviato da Rookye Visualizza il messaggio
    Ciao frank17next,

    perché vedo che tu lo metti in assets e poi lo copi.. quindi ci sei arrivato fin li.
    Dimmi come hai fai ti prego..
    Ciao,
    eheheh... beh si, fino a li ci sono arrivato, poi sono andato anche avanti
    dunque devi verificare che non usi il metodo .getReadableDatabase(); (che normalmente qualsiasi classe sqlitehelper implementa) PRIMA che avvenga la copia fisica dall'assets del progetto eclipse al device. Questo perchè quel metodo, quando non trova fisicamente il file del db sqlite presente, crea un db sqlite vuoto, sicuramente con il nome pro.db (nel tuo caso) e lo apre. Successivamente fallisce la copia da assets perchè vi è una violazione di sovrascrittura di un file aperto.
    Io ho risolto molto semplicemente evitando di eseguire la 'prima' copia del db preesistente da assets direttamente nella nand interna del device ('/data/data/...') poichè ho bisogno di averlo in /sdcard (nel mio caso ha una dimensione di partenza di 6mb e stimo una crescita di 500kb/1mb al mese).

    Le mie dichiarazioni delle variabili per indicare il database sono quindi:
    codice:
    public static String DB_PATH = "/mnt/sdcard/";
    public static final String MYDATABASE_NAME = "androidsqlitedb";
    I metodi @Override OnCreate() e OnUpgrade non li uso. Molto banalmente ad ogni instanza della mia classe sqliteAdapter controllo che il db sia presente nella location indicata. Se è mancante lo prelevo dalla assets se presente non eseguo nulla.
    Questa è la funzione che copia il database:
    codice:
     public void copyDatabase() throws IOException {
    	  if (controlloEsistenzaDb()) {
    	  }else{
    		InputStream assetsDB = context.getAssets().open("androidsqlitedb.s3db");
    		OutputStream dbOut = new FileOutputStream(DB_PATH + "androidsqlitedb");
    	    byte[] buffer = new byte[1024];
    	    int length;
    	    while ((length = assetsDB.read(buffer))>0){
    	      dbOut.write(buffer, 0, length);
    	    }	 
    	    dbOut.flush();
    	    dbOut.close();
    	    assetsDB.close();
    	  }
    	}
    e questa e la funzione che esegue il controllo esistenza file sul device:
    codice:
      public boolean checkDataBase(){
    	 SQLiteDatabase checkDB = null;
    	  	File f = new File( DB_PATH );
    	  	if ( !f.exists() )
    	  		f.mkdir();
      	try{
      		String myPath = DB_PATH + MYDATABASE_NAME;
      		checkDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);
      	}catch(SQLiteException e){
      		//database does't exist yet.
      	}
      	if(checkDB != null){
      		checkDB.close();
      	}
      	return checkDB != null ? true : false;
      }
    Più in generale se ti serve manipolare i file, anche direttamente sul device, puoi usare InputStream e OutputStream, come ad esempio in questo modo (esegue una copia direttamente sul device):

    codice:
      public void copialocale() throws IOException {
    	  	//File f = new File("/data/data/mia.applicazione.test/databases/sqliteAndroid.db");
    	  	//f.delete();
    	  	InputStream assetsDB = new FileInputStream("/data/data/mia.applicazione.test/sqliteAndroid.db");
    	    OutputStream dbOut = new FileOutputStream("/data/data/mia.applicazione.test/databases/sqliteAndroid.db");	    
    	    byte[] buffer = new byte[1024];
    	    int i=0;
    	    while ((i = assetsDB.read(buffer)) != -1) {
    	    	dbOut.write(buffer,0,i);
    	    	dbOut.close();
    	    	assetsDB.close();
    	    }
    	}
    Come vedi, dò in pasto ad un oggetto di tipo InputStream il risultato del metodo .getAssets(); di un oggetto di tipo Contex, che rappresenta il contesto dell'applicazione:

    codice:
    context.getAssets().open('nome file');
    Ultima modifica di frank17next; 12-04-12 alle 00:14
    Nexus 6 - 5.0.1 Stock
    Nexus 5 - 5.0.1 Stock + Root
    Galaxy Note 3 GT-N9005 - 4.4.4 Stock + Root
    Galaxy Tab 10.1 Slim P7500 - [JB] CyanogenMod 10 4.1.2 Pershoot (Nightly 20121013)
    ------------------------------------------------------------------------
    https://sites.google.com/site/frank17next/

  7. #6
    Baby Droid


    Registrato dal
    Apr 2012
    Messaggi
    11

    Ringraziamenti
    1
    Ringraziato 0 volte in 0 Posts
    Predefinito

    Ciao frank17next,
    dopo tante vane ricerche forse finalmente ho trovato quello che mi occorre. Anche io ho un database popolato, da copiare in assets e da qui leggerlo nella mia app. Però sto riscontrando un gran numero di problemi. Le ho provate tutte ma proprio non riesco
    Partendo dal database, come lo crei? cioè, che programmi usi per creare la tabella e successivamente popolarlo?
    Io ho usato SQLite Database Browser e seguendo le indicazioni di alcuni tutorial online ho creato due tabelle "rubrica" e "android_metadata".
    Nel tuo codice, sostituendo a MYDATABASE_TABLE il nome della mia tabella (rubrica) e in KEY_CONTENT il nome di una colonna, mi da errore dicendomi "no such table: rubrica". Sapresti aiutarmi?
    Grazie

  8. #7
    Senior Droid L'avatar di frank17next


    Registrato dal
    Jan 2010
    Località
    Campobasso
    Messaggi
    739
    Smartphone
    GNexus, Galaxy Note, GT 10.1

    Ringraziamenti
    16
    Ringraziato 143 volte in 102 Posts
    Predefinito

    Quote Originariamente inviato da lorenzogiudici5 Visualizza il messaggio
    Ciao frank17next,
    dopo tante vane ricerche forse finalmente ho trovato quello che mi occorre. Anche io ho un database popolato, da copiare in assets e da qui leggerlo nella mia app. Però sto riscontrando un gran numero di problemi. Le ho provate tutte ma proprio non riesco
    Partendo dal database, come lo crei? cioè, che programmi usi per creare la tabella e successivamente popolarlo?
    Io ho usato SQLite Database Browser e seguendo le indicazioni di alcuni tutorial online ho creato due tabelle "rubrica" e "android_metadata".
    Nel tuo codice, sostituendo a MYDATABASE_TABLE il nome della mia tabella (rubrica) e in KEY_CONTENT il nome di una colonna, mi da errore dicendomi "no such table: rubrica". Sapresti aiutarmi?
    Grazie
    Potresti postarmi il tuo codice?
    Esattamente a che punto del codice esegui la copia, a che punto esegui una query (presumibilmente?). E' necessario comprendere se al momento dell'interrogazione sia operativo il tuo db popolato e non quello vuoto che il metodo dell'helper .getREadableDatabase() crea nel caso un db non esista...
    Nexus 6 - 5.0.1 Stock
    Nexus 5 - 5.0.1 Stock + Root
    Galaxy Note 3 GT-N9005 - 4.4.4 Stock + Root
    Galaxy Tab 10.1 Slim P7500 - [JB] CyanogenMod 10 4.1.2 Pershoot (Nightly 20121013)
    ------------------------------------------------------------------------
    https://sites.google.com/site/frank17next/

  9. #8
    Baby Droid


    Registrato dal
    Apr 2012
    Messaggi
    11

    Ringraziamenti
    1
    Ringraziato 0 volte in 0 Posts
    Predefinito

    Ti allego i due file txt con la Classe che gestisce il database e il main, perchè copiare direttamente il codice qui dentro non me lo permette.
    Classe Database.txt Main.txt

    Non ho ben capito il fatto di verificare se il db è già operativo prima che ne faccia una query.
    Grazie

  10. #9
    Senior Droid L'avatar di frank17next


    Registrato dal
    Jan 2010
    Località
    Campobasso
    Messaggi
    739
    Smartphone
    GNexus, Galaxy Note, GT 10.1

    Ringraziamenti
    16
    Ringraziato 143 volte in 102 Posts
    Predefinito

    Quote Originariamente inviato da lorenzogiudici5 Visualizza il messaggio
    Ti allego i due file txt con la Classe che gestisce il database e il main, perchè copiare direttamente il codice qui dentro non me lo permette.
    Classe Database.txt Main.txt

    Non ho ben capito il fatto di verificare se il db è già operativo prima che ne faccia una query.
    Grazie
    Ciao,
    intendo dire che quando nella main richiami openToRead(), di fatto utilizzi il metodo sqLiteHelper.getReadableDatabase(); che -se non trova il database già presente (cioè già copiato sul device) ne crea uno vuoto con soltanto la tabella android_metadata.
    Prova subito a fare la query su quella tabella e vedi se aggiri l'errore table not found.
    Se riesce vuol dire che è quello il caso.
    Ancora: prova a rimuovere dal path del db /databases, copialo direttamente in /data/data/tuaapp/
    Nexus 6 - 5.0.1 Stock
    Nexus 5 - 5.0.1 Stock + Root
    Galaxy Note 3 GT-N9005 - 4.4.4 Stock + Root
    Galaxy Tab 10.1 Slim P7500 - [JB] CyanogenMod 10 4.1.2 Pershoot (Nightly 20121013)
    ------------------------------------------------------------------------
    https://sites.google.com/site/frank17next/

  11. #10
    Baby Droid


    Registrato dal
    Apr 2012
    Messaggi
    11

    Ringraziamenti
    1
    Ringraziato 0 volte in 0 Posts
    Predefinito

    Ho provato a fare entrambe le cose. L'errore table not found pare aggirato, ora però mi da un NullPointerException.
    Idee su quale potrebbe essere il problema a questo punto?

Pagina 1 di 5 123 ... ultimoultimo
Ultima pagina

Tag per questa discussione

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire risposte
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Torna su
Privacy Policy