Autore Topic: Sqlite & AsyncTask/Service (task concorrenti)  (Letto 922 volte)

Offline wlf

  • Utente normale
  • ***
  • Post: 373
  • Respect: +8
    • Mostra profilo
  • Dispositivo Android:
    Xperia
Sqlite & AsyncTask/Service (task concorrenti)
« il: 01 Agosto 2017, 09:54:35 CEST »
0
Salve,
ho la necessità di utilizzare Sqlite sia da diverse Activity, sia da AsyncTask che da dei Service. A volte mi capitano delle situazioni che mi viene dato "database already closed" oppure "database is locked ".

Se apro il db nella onCreate() e lo chiudo nella onDestroy() passando da una activity ad un altra la onCreate() di quella successiva è prima della onDestroy() di quella precendente. Facendolo nella onPause() e onResume() mi ritrovo con degli AsyncTask che casomai non sono ancora cessati che vanno a scrivere dopo la onPause(). Idem con i Service. :(

Aprendo il db anche nell'AsyncTask e nei Service mi ritrovo con una re-open; posso controllarlo in fase di apertura con una db.isOpen() ma poi posso aver problemi se il db nel frattempo è già stato chiuso. :(

Ho trovato un interessante soluzione ma non mi convince del tutto. In particolare la initializeInstance() dove andrebbe fatta? Solamente una volta, magari in Application o nella prima activity dell'App oppure sempre prima di ogni getInstance().openDatabase()?

Perché la getInstance() ritorna un Exception, non lo re-inizializza, quindi senza chiamare preventivamente la initializeInstance() il db sarà comunque inaccessibile.

Offline capitancooker

  • Utente junior
  • **
  • Post: 123
  • Marco
  • Respect: +10
    • Mostra profilo
  • Dispositivo Android:
    Nexus 5
  • Sistema operativo:
    macOS High Sierra
Re:Sqlite & AsyncTask/Service (task concorrenti)
« Risposta #1 il: 01 Agosto 2017, 11:33:42 CEST »
0
Io ho adottato questa soluzione che avevo trovato tempo fa in giro, non so quanto ortodossa ma funziona:

Codice (Java): [Seleziona]
public class MyDbManager {

 private static AtomicInteger mOpenCounter = new AtomicInteger();
    private static MyDbHelper dbhelper;
    private static SQLiteDatabase mDb;

    public MyDbManager(Context contex) {
        dbhelper = MyDbHelper.getInstance(contex);
    }


    public static synchronized SQLiteDatabase opendb() {
        if (mOpenCounter.incrementAndGet() == 1) mDb = dbhelper.getWritableDatabase();
        return mDb;
    }

    public static synchronized void closedb() {
        if (mOpenCounter.decrementAndGet() == 0) mDb.close();
    }
}

Istanzio MyDbManager da Application e ogni volta che devo accedere al db chiamo MyDbManager.opendb() e MyDbManager.closedb() quando ho terminato.

Ciao,
Marco

Se sbaglio, correggetemi.

Offline wlf

  • Utente normale
  • ***
  • Post: 373
  • Respect: +8
    • Mostra profilo
  • Dispositivo Android:
    Xperia
Re:Sqlite & AsyncTask/Service (task concorrenti)
« Risposta #2 il: 01 Agosto 2017, 12:31:38 CEST »
0
Istanziare MyDbManager da Application, una sorta di Singleton, personalmente lo trovo pericoloso. Che sicurezza dopo aver pausato l'App anche per alcuni giorni, potresti riprenderla (resume) che il GC ti ha fatto fuori MyDbManager. :(

Per questo trovo leggermente più sicuro l'approccio del link; il tuo è semplificato ma più o meno fa la stessa cosa. ;)

Offline capitancooker

  • Utente junior
  • **
  • Post: 123
  • Marco
  • Respect: +10
    • Mostra profilo
  • Dispositivo Android:
    Nexus 5
  • Sistema operativo:
    macOS High Sierra
Re:Sqlite & AsyncTask/Service (task concorrenti)
« Risposta #3 il: 17 Settembre 2017, 12:33:19 CEST »
0
Alla fine che soluzione hai adottato?
Ciao,
Marco
Se sbaglio, correggetemi.

Offline wlf

  • Utente normale
  • ***
  • Post: 373
  • Respect: +8
    • Mostra profilo
  • Dispositivo Android:
    Xperia
Re:Sqlite & AsyncTask/Service (task concorrenti)
« Risposta #4 il: 18 Settembre 2017, 12:22:27 CEST »
0
Faccio la Initialize() e la open per ogni volta che utilizzo il db dopo di che lo chiudo con la close.

Tenerlo come singleton in application mi piace decisamente di meno.

Offline Ohmnibus

  • Utente senior
  • ****
  • Post: 836
  • Respect: +184
    • Github
    • Google+
    • @ohmnibus
    • Mostra profilo
    • Lords of Knowledge GdR
  • Dispositivo Android:
    Huawei P9 Lite
  • Play Store ID:
    Ohmnibus
  • Sistema operativo:
    Windows 10 x64
Re:Sqlite & AsyncTask/Service (task concorrenti)
« Risposta #5 il: 19 Settembre 2017, 09:30:31 CEST »
0
@wlf: So che è piuttosto oneroso da implementare, ma quello che ti servirebbe per stare sicuro è un Content Provider.

Personalmente nell'ultimo progetto che ho realizzato NON ho usato un Content Provider, ma mi sono limitato ad un singleton di DBManager inizializzato una volta per tutte in una classe derivata di Application.

Il singleton è un metodo sicuro: non può essere fatto fuori dal CG fintanto che l'app non viene terminata.
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 wlf

  • Utente normale
  • ***
  • Post: 373
  • Respect: +8
    • Mostra profilo
  • Dispositivo Android:
    Xperia
Re:Sqlite & AsyncTask/Service (task concorrenti)
« Risposta #6 il: 19 Settembre 2017, 10:47:29 CEST »
0
Innanzi tutto grazie delle tue preziose considerazioni Ohmnibus! ;)

Il singleton è un metodo sicuro: non può essere fatto fuori dal CG fintanto che l'app non viene terminata.

Non pare essere sempre vero. Io stesso utilizzavo un singleton inizializzato dentro ad Application, ma sporadicamente avevo delle NullPointerException. Per questo motivo ho tolto l'inizializzazione in application e tutte le volte che chiamavo il singleton io lo inizializzavo se per caso era a null.

Offline Ohmnibus

  • Utente senior
  • ****
  • Post: 836
  • Respect: +184
    • Github
    • Google+
    • @ohmnibus
    • Mostra profilo
    • Lords of Knowledge GdR
  • Dispositivo Android:
    Huawei P9 Lite
  • Play Store ID:
    Ohmnibus
  • Sistema operativo:
    Windows 10 x64
Re:Sqlite & AsyncTask/Service (task concorrenti)
« Risposta #7 il: 19 Settembre 2017, 12:51:34 CEST »
0
@wlf: E' certo che l'Application può essere vittima di recycle. Ma quando viene ripristinata passa nuovamente per la onCreate ed il singleton viene re-inizializzato correttamente. O sbaglio? Dall'articolo che hai linkato si parla semplicemente di "reset dei valori static", e questo è naturale, ma potrei non aver capito bene.
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 wlf

  • Utente normale
  • ***
  • Post: 373
  • Respect: +8
    • Mostra profilo
  • Dispositivo Android:
    Xperia
Re:Sqlite & AsyncTask/Service (task concorrenti)
« Risposta #8 il: 19 Settembre 2017, 13:42:44 CEST »
0
Io a suo tempo avevo proprio dato per scontato che Application ripassasse per la onCreate e re-inizializzasse il singleton, avevo anche messo un controllo, ma così non accadeva. Nella onCreate di Application inizializzavo nuovamente i valori ma mi beccavo dei NullPointerException. :(

Offline Ohmnibus

  • Utente senior
  • ****
  • Post: 836
  • Respect: +184
    • Github
    • Google+
    • @ohmnibus
    • Mostra profilo
    • Lords of Knowledge GdR
  • Dispositivo Android:
    Huawei P9 Lite
  • Play Store ID:
    Ohmnibus
  • Sistema operativo:
    Windows 10 x64
Re:Sqlite & AsyncTask/Service (task concorrenti)
« Risposta #9 il: 19 Settembre 2017, 14:25:02 CEST »
0
Azz... non lo sapevo... non è comune ma almeno in qualche caso è vero: https://stackoverflow.com/questions/36256400/android-6-auto-restore-not-initializing-app

Citazione
For full-data backup and restore operations, the package is launched with a base class Application instance, not your manifest-declared subclass.
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 wlf

  • Utente normale
  • ***
  • Post: 373
  • Respect: +8
    • Mostra profilo
  • Dispositivo Android:
    Xperia
Re:Sqlite & AsyncTask/Service (task concorrenti)
« Risposta #10 il: 19 Settembre 2017, 15:42:02 CEST »
0
A suo tempo cercai di ovviare al problema cercando di "killare" l'App completamente, in questo modo alla successiva ripartenza il singleton si sarebbe ricreato. Ma non ho trovato una soluzione per riuscire a killare l'App dopo un tot di secondi che non è più operativa.

Tu hai mai fatto qualcosa del genere? Non sarebbe una soluzione, ma un modo per aggirare il problema.

Offline Ohmnibus

  • Utente senior
  • ****
  • Post: 836
  • Respect: +184
    • Github
    • Google+
    • @ohmnibus
    • Mostra profilo
    • Lords of Knowledge GdR
  • Dispositivo Android:
    Huawei P9 Lite
  • Play Store ID:
    Ohmnibus
  • Sistema operativo:
    Windows 10 x64
Re:Sqlite & AsyncTask/Service (task concorrenti)
« Risposta #11 il: 19 Settembre 2017, 16:41:55 CEST »
0
Come ti ho detto inizializzo un singleton all'avvio dell'app. Non mi è mai capitato di vedere NRE (non significa che non ce ne siano) e quindi non mi sono mai posto il problema...
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.