Autore Topic: inserire dati in db prima di avviare app  (Letto 379 volte)

Offline brax

  • Nuovo arrivato
  • *
  • Post: 11
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    OnePlus 3T
  • Sistema operativo:
    Win 10
inserire dati in db prima di avviare app
« il: 05 Luglio 2017, 21:01:24 CEST »
0
Ciao, scusate per il titolo ma non saprei esattamente cosa scrivere. Il mio quesito non riguarda codice direttamente ma è più sul procedimento.
In pratica ho un app con un proprio database di dati che vengono mostrati all'utenti. E' tutto in locale, niente cloud ecc.
Al momento ho nella mia classe database_helper il metodo insert data per inserire dati però in realtà a me serve che quando l'app parta, il db sia già pieno. Inoltre durante i vari upgrade che farò all'app in futuro avrò bisogno di cambiare i dati contenuti nel db aggiungendo delle righe.
Qual'è il modo corretto per farlo considerando che ogni row è composta di 3 campi?


Le mie idee:

1) - creare un file .db sqlite "a mano" come file resource  e caricarlo ad ogni avvio dell'app
2) un file txt o csv e poi copiare i file nel db solo la prima volta che l'app viene avviata (cioè quando viene creato il db in locale) e quando il csv viene modificato (cioè faccio l'update dell'app)

Un'altra domanda leggermente diversa. L'app funziona in modo che ad ogni swipe mostra un dato preso da una riga scelta a random (il funzionamento è visivamente simile a Tinder ecc). Considerato che in tutto avrò circa 600 (max 1000 forse in futuro) righe nella tabella, mi conviene estrarre tutto con un'unica query all'avvio, memorizzare in un array (o un altro csv temporaneo?) e da questo prelevare ad ogni swipe, oppure mi conviene fare una query unica per ogni swipe?

grazie!

B.

edit: aggiunto dettagli
« Ultima modifica: 06 Luglio 2017, 05:29:38 CEST da brax »

Offline Ohmnibus

  • Utente senior
  • ****
  • Post: 750
  • Respect: +158
    • Github
    • Google+
    • @ohmnibus
    • Mostra profilo
    • Lords of Knowledge GdR
  • Dispositivo Android:
    Huawei P9 Lite
  • Play Store ID:
    Ohmnibus
  • Sistema operativo:
    Windows 7 x64
Re:inserire dati in db prima di avviare app
« Risposta #1 il: 06 Luglio 2017, 09:54:41 CEST »
0
Se fai il DB a mano tieni conto che ogni volta che lo sostituisci al vecchio cancelli tutte le eventuali modifiche apportate, quindi è una soluzione percorribile solo se il tuo DB è in sola lettura.

In alternativa puoi usare 2 DB, uno in sola lettura ed un altro dove fare le modifiche.

Non esiste una soluzione corretta. Probabilmente la prima è più facile da implementare (e più veloce in termini di esecuzione), ma ha i limiti che ho appena descritto.

Per quanto riguarda la domanda 2, io farei una query all'avvio e poi utilizzerei il Cursor per scorrere tra i vari elementi (come in un CursorAdapter). Nel caso i dati cambino, ricorda di aggiornare il Cursor
Ohmnibus
Le mie app su Play Store

È stata trovata una soluzione al tuo problema? Evidenzia il post più utile premendo . È un ottimo modo per ringraziare chi ti ha aiutato.

Offline brax

  • Nuovo arrivato
  • *
  • Post: 11
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    OnePlus 3T
  • Sistema operativo:
    Win 10
Re:inserire dati in db prima di avviare app
« Risposta #2 il: 06 Luglio 2017, 11:08:47 CEST »
0
ciao e grazie,

si, il db sara sempre solo in lettura. Ok quindi ricapitolando:

1) creo il mio db con i dati esternamente e lo metto fra gli assets
2) ad ogni startup dell'app faccio una query da cui tiro fuori tutti i dati dalla tabella e li metto nel mio cursor.
3) quando gli update dell'app saranno pronti (cioe ci saranno nuovi dati nel db) mi bastera aggiornare il mio file db e quando un'utente scarica l'update, il vecchio file .db verra sovrascritto da quello nuovo (questo succede in automatico giusto?)

una volta che ho il mio cursor contenente tutte le mie rows, posso sceglierne una a caso ad ogni swipe giusto? ho visto degli esempi con rand ma non ho capito se si possa specificare il seed ecc. Non vorrei che ogni volta che l'app si avvia i rand fossero sempre nello stesso ordine.

grazie!!

B.

Offline Ohmnibus

  • Utente senior
  • ****
  • Post: 750
  • Respect: +158
    • Github
    • Google+
    • @ohmnibus
    • Mostra profilo
    • Lords of Knowledge GdR
  • Dispositivo Android:
    Huawei P9 Lite
  • Play Store ID:
    Ohmnibus
  • Sistema operativo:
    Windows 7 x64
Re:inserire dati in db prima di avviare app
« Risposta #3 il: 06 Luglio 2017, 11:19:30 CEST »
0
Il procedimento è giusto, ma non viene fatto in automatico.

Devi copiare il DB dagli asset alla cartella contenente i DB prima di utilizzarlo.

Qui è indicato come procedere: https://blog.reigndesign.com/blog/using-your-own-sqlite-database-in-android-applications/
O anche qui: https://stackoverflow.com/questions/9109438/how-to-use-an-existing-database-with-an-android-application

Quando i dati sono aggiornati, aumenti la database version e fai l'override di onUpgrade, dove cancelli il vecchio DB ed invochi onCreate per copiare quello nuovo.

Se servono altri dettagli chiedi pure
Ohmnibus
Le mie app su Play Store

È stata trovata una soluzione al tuo problema? Evidenzia il post più utile premendo . È un ottimo modo per ringraziare chi ti ha aiutato.

Offline brax

  • Nuovo arrivato
  • *
  • Post: 11
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    OnePlus 3T
  • Sistema operativo:
    Win 10
Re:inserire dati in db prima di avviare app
« Risposta #4 il: 06 Luglio 2017, 12:25:32 CEST »
0
grazie, ho sbagliato terminologia (automaticamente era riferito al fatto che mi basta solo sostituire il fil db vecchio con quello nuovo), si avevo gia visto l'articolo per usare db esterni, ma non ho proceduto perche volevo capire prima quale fosse il modus operandi migliore o piu comune :)

adesso pero mi hai confuso con le ultime due righe :D ieri sera mentre smanettavo e facevo tentativi mi sono scontrato con il fatto del dover riscrivere il db.
(Per chiarezza quando dico "db esterno" mi riferisco a quello che creo io esternamente, "db locale" a quello dentro l'app in cui copiare quello esterno)

In particolare:
- il db locale dev'essere aggiornato SOLO quando quello esterno viene aggiornato. Non avrebbe senso che ogni volta che apro l'app copio lo stesso file .db nello stesso db locale. Il problema che avevo ieri notte era il "come" capire se il db esterno fosse stato aggiornato (cioe diverso, con piu righe - ne verranno sempre e solo aggiunte, mai tolte - ) rispetto a quello locale e se lo fosse, ri-eseguirne la copia in quello locale

- sono un po' confuso con l'upgrade..avevo capito che viene triggerato quando cambia il db locale, cioe specificando la versione ma non riesco a immaginare bene il flow dell'operazione. Correggimi se sbaglio:

1) la mia app e pubblicata, ha il suo db esterno che alla prima esecuzione (e solo in quella) e stato copiato nel db interno, version = 1
2) quando rilascio l'update con il nuovo db esterno (che avra le stesse row del vecchio piu altre row nuove) devo settare la versione = 2 (cioe hardcoded?) cosi:

Codice: [Seleziona]
public DatabaseHandler(Context context) {
        super(context, DATABASE_NAME, null, 2);
        this.context = context;
    }


e lui automaticamente mi chiama il onUpgrade (che cancella il db locale vecchio e richiama onCreate per copiare il nuovo db esterno).

e giusto questo percorso? Inoltre, nel onUpgrade al momento ho solo un drop table. devo fare anche drop database oppure basta cambiare la versione e automaticamente viene "sovrascritto"?

grazie!!!

B.

ps: scusa ma ho la tastiera senza lettere accentate :/

Offline Ohmnibus

  • Utente senior
  • ****
  • Post: 750
  • Respect: +158
    • Github
    • Google+
    • @ohmnibus
    • Mostra profilo
    • Lords of Knowledge GdR
  • Dispositivo Android:
    Huawei P9 Lite
  • Play Store ID:
    Ohmnibus
  • Sistema operativo:
    Windows 7 x64
Re:inserire dati in db prima di avviare app
« Risposta #5 il: 06 Luglio 2017, 13:05:53 CEST »
+1
Facciamo un passo indietro: ti ho dato un consiglio che solo ora mi accorgo essere sbagliato.

Da quello che leggo non è possibile far affidamento sulla onUpgrade perché a quel punto il DB è già in uso e non può essere cancellato.

Fai riferimento a questa risposta su StackOverflow per gestire il versionamento del database: https://stackoverflow.com/questions/11601573/db-file-in-assets-folder-will-it-be-updated/11601770#11601770

In pratica:
- Se il database esiste, leggi la versione
-- Se la versione è inferiore alla corrente, cancella il DB
- Se il database non esiste, lo crei, e salvi nelle SharedPreferences la versione
Ohmnibus
Le mie app su Play Store

È stata trovata una soluzione al tuo problema? Evidenzia il post più utile premendo . È un ottimo modo per ringraziare chi ti ha aiutato.

Offline brax

  • Nuovo arrivato
  • *
  • Post: 11
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    OnePlus 3T
  • Sistema operativo:
    Win 10
Re:inserire dati in db prima di avviare app
« Risposta #6 il: 06 Luglio 2017, 14:31:24 CEST »
0
ok grazie..credo di aver capito in generale ma ho ancora un dubbio sulla SharedPreferences di cui non avevo mai sentito parlare.

dunque:
- app parte per la prima volta, crea il db locale copiando dal db esterno, salva la version (1) nelle SP
- app parte per la seconda volta. Devo fare il confronto di versione (se e uguale ignora e usa il db locale, altrimenti aggiorna il db). Ma su cosa lo faccio il confronto? Al momento la versione del db in uso e scritta solo nelle SP. Dove prendo il secondo valore per fare il confronto? Devo, ogni volta che rilascio una nuova versione del file db esterno, modificare la variabile
Codice: [Seleziona]
private static final int DATABASE_VERSION = 1; ?

Offline Ohmnibus

  • Utente senior
  • ****
  • Post: 750
  • Respect: +158
    • Github
    • Google+
    • @ohmnibus
    • Mostra profilo
    • Lords of Knowledge GdR
  • Dispositivo Android:
    Huawei P9 Lite
  • Play Store ID:
    Ohmnibus
  • Sistema operativo:
    Windows 7 x64
Re:inserire dati in db prima di avviare app
« Risposta #7 il: 06 Luglio 2017, 14:44:41 CEST »
0
Citazione
Devo, ogni volta che rilascio una nuova versione del file db esterno, modificare la variabile DATABASE_VERSION?

Esattamente.

In pratica confronti il contenuto delle SharedPreference con DATABASE_VERSION. Chiaramente questo valore sarà sempre lo stesso finché l'utente non installerà una versione aggiornata con un Db aggiornato. A quel punto avrai aumentato DATABASE_VERSION a 2, e quindi parte la procedura di aggiornamento del DB.
Ohmnibus
Le mie app su Play Store

È stata trovata una soluzione al tuo problema? Evidenzia il post più utile premendo . È un ottimo modo per ringraziare chi ti ha aiutato.

Offline brax

  • Nuovo arrivato
  • *
  • Post: 11
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    OnePlus 3T
  • Sistema operativo:
    Win 10
Re:inserire dati in db prima di avviare app
« Risposta #8 il: 06 Luglio 2017, 15:07:41 CEST »
0
ottimo!

solo altre due domande relative ai db..dove lo metto il file db esterno? in quale cartella? e soprattutto (ci ho perso le ore ieri sera senza capire come si faccia davvero): come recupero i path relativi dei file nelle cartelle (tipo il mio file db esterno)? in giro ho letto almeno 5-6 risposte tutte diverse, a domande sui path  :D

grazie!! ho capito piu cose qui oggi che in una settimana di tutorial XD

Offline brax

  • Nuovo arrivato
  • *
  • Post: 11
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    OnePlus 3T
  • Sistema operativo:
    Win 10
Re:inserire dati in db prima di avviare app
« Risposta #9 il: 07 Luglio 2017, 18:48:43 CEST »
0
ok ho trisolto il discorso del path..a quanto pare funziona ma ho un'errore quando cerco di prelevare i dati.

Codice: [Seleziona]
public class DatabaseHandler extends SQLiteOpenHelper {
   
    private static final String DATABASE_NAME = "TIS_DB.db";
    private static final int DATABASE_VERSION = 1;
    private static final String TABLE_NAME = "table1";
    private static final String COL_0 = "Id";
    private static final String COL_1 = "one";
    private static final String COL_2 = "two";
    private final Context context;
   
    public DatabaseHandler(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
        this.context = context;
    }
   
    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " (" + COL_0 + " INTEGER PRIMARY KEY, " + COL_1 + " TEXT, " + COL_2 + " TEXT" + ")");
        db.execSQL("CREATE TABLE IF NOT EXISTS Fav (" + COL_0 + " INTEGER PRIMARY KEY, " + COL_1 + " TEXT, " + COL_2 + " TEXT" + ")");

        insertData();
    }
   
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
        onCreate(db);
    }
   
    private boolean insertData() {
        SQLiteDatabase db = this.getWritableDatabase();
   
        AssetManager mgr = this.context.getAssets();
        FileReader csv = null;
        String [] files = null;
   
        try {
            files = mgr.list("csv");
        } catch (IOException e) {
            e.printStackTrace();
        }
   
        try {
            csv = new FileReader(files[0]);
        } catch (IOException e) {
            e.printStackTrace();
        }
   
        BufferedReader buffer = new BufferedReader(csv);
        String line = "";
        String columns = "Id, one, two";
        String str1 = "INSERT INTO " + TABLE_NAME + " (" + columns + ") VALUES (";
        String str2 = ");";
   
        db.beginTransaction();
   
        try {
            while ((line = buffer.readLine()) != null) {
                StringBuilder sb = new StringBuilder(str1);
                String[] str = line.split(",");
                sb.append("'" + str[0] + "',");
                sb.append(str[1] + "',");
                sb.append(str[2] + "'");
                sb.append(str2);
                db.execSQL(sb.toString());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        db.setTransactionSuccessful();
        db.endTransaction();
       
        return true;
    }
   
    public Cursor getData() {
        SQLiteDatabase db = this.getWritableDatabase();
        String query = "SELECT * FROM " + TABLE_NAME;
        Cursor data = db.rawQuery(query, null);
        return data;
    }


l'errore di tipo getDatabased called recursively

Codice: [Seleziona]
FATAL EXCEPTION: main
                                                                                  Process: italian.said.fran.theitaliansaid, PID: 23803
                                                                                  java.lang.RuntimeException: Unable to start activity ComponentInfo{italian.said.fran.theitaliansaid/italian.said.fran.theitaliansaid.FavActivity}: java.lang.IllegalStateException: getDatabase called recursively
                                                                                      at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2728)
                                                                                      at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2814)
                                                                                      at android.app.ActivityThread.-wrap12(ActivityThread.java)
                                                                                      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1527)
                                                                                      at android.os.Handler.dispatchMessage(Handler.java:102)
                                                                                      at android.os.Looper.loop(Looper.java:154)
                                                                                      at android.app.ActivityThread.main(ActivityThread.java:6290)
                                                                                      at java.lang.reflect.Method.invoke(Native Method)
                                                                                      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
                                                                                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
                                                                                   Caused by: java.lang.IllegalStateException: getDatabase called recursively
                                                                                      at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:203)
                                                                                      at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:163)
                                                                                      at italian.said.fran.theitaliansaid.DatabaseHandler.insertData(DatabaseHandler.java:72)
                                                                                      at italian.said.fran.theitaliansaid.DatabaseHandler.onCreate(DatabaseHandler.java:46)
                                                                                      at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:251)
                                                                                      at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:163)
                                                                                      at italian.said.fran.theitaliansaid.DatabaseHandler.getFav(DatabaseHandler.java:150)
                                                                                      at italian.said.fran.theitaliansaid.FavActivity.onCreate(FavActivity.java:28)
                                                                                      at android.app.Activity.performCreate(Activity.java:6760)
                                                                                      at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1134)
                                                                                      at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2681)
                                                                                      at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2814) 
                                                                                      at android.app.ActivityThread.-wrap12(ActivityThread.java) 
                                                                                      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1527) 
                                                                                      at android.os.Handler.dispatchMessage(Handler.java:102) 
                                                                                      at android.os.Looper.loop(Looper.java:154) 
                                                                                      at android.app.ActivityThread.main(ActivityThread.java:6290) 
                                                                                      at java.lang.reflect.Method.invoke(Native Method)

Offline Ohmnibus

  • Utente senior
  • ****
  • Post: 750
  • Respect: +158
    • Github
    • Google+
    • @ohmnibus
    • Mostra profilo
    • Lords of Knowledge GdR
  • Dispositivo Android:
    Huawei P9 Lite
  • Play Store ID:
    Ohmnibus
  • Sistema operativo:
    Windows 7 x64
Re:inserire dati in db prima di avviare app
« Risposta #10 il: 08 Luglio 2017, 12:56:10 CEST »
+1
Cambia

Codice (Java): [Seleziona]
    private boolean insertData() {
        SQLiteDatabase db = this.getWritableDatabase();
   
        AssetManager mgr = this.context.getAssets();


in

Codice (Java): [Seleziona]
    private boolean insertData(SQLiteDatabase db) {
   
        AssetManager mgr = this.context.getAssets();

e nella onCreate chiami

Codice (Java): [Seleziona]
        insertData(db);
Ohmnibus
Le mie app su Play Store

È stata trovata una soluzione al tuo problema? Evidenzia il post più utile premendo . È un ottimo modo per ringraziare chi ti ha aiutato.