Autore Topic: [medio] Backup di un database SQLite su sdcard.  (Letto 974 volte)

Offline Nicola_D

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 1870
  • Respect: +241
    • Github
    • Google+
    • Mostra profilo
  • Dispositivo Android:
    Google Nexus S - Google Nexus 7
  • Sistema operativo:
    Windows 7
[medio] Backup di un database SQLite su sdcard.
« il: 24 Luglio 2012, 23:45:35 CEST »
+2
Livello di difficoltà : medio
Min SDK : 4
Sorgente : ZIP allegato


fonti:

Introduzione

Viste le numerose richieste di informazioni, tutorial e snippet su come effettuare il backup di un database, in modo da averlo disponibile anche su cellulari non rootati e fuori dall'emulatore, mi sono deciso a sperimentare la procedura e a fare un piccolo tutorial per rendere disponibile a tutti questa procedura.

Il "Tutorial" in realtà è molto semplice, in quanto la procedura non richiede particolari skill.
Nel caso in cui si volesse utilizzare una procedura differente, il codice è pronto per essere riadattato.

Contenuto del tutorial e layout

Partendo dai tutorial già citati (che sono abbastanza importanti per capire bene il codice di questo tutorial), vediamo cosa abbiamo a disposizione nel tutorial:

Il tema del tutorial è "Nazioni" ; andremo a creare un database di nazioni contenenti Codice,Nome e descrizione, avendo la possibilità di visualizzarle in una comoda listview, e di farne un backup sulla sd.

Activity composta da view pager con 3 tabs:
 - Aggiunta
 - Visualizzazione
 - Backup
Database SQLite creato da script a runtime


Tralasciando il layout dell'activity (uguale a quello dei tutorial precedenti) e dei tre fragment (molto banale, se vi serve è nel file allegato), passiamo alla parte più importante, cioè la fase di backup:

Per prima cosa, va configurato il manifest per dare il permesso di scrittura su sd:
Codice (XML): [Seleziona]
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
   package="it.anddev.dbBackup"
   android:versionCode="1"
   android:versionName="1.0" >
    <uses-sdk
       android:minSdkVersion="4"
       android:targetSdkVersion="16" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <application
       android:icon="@drawable/ic_launcher"
       android:label="@string/app_name"
       android:theme="@style/AppTheme" >
        <activity
           android:name=".MainActivity"
           android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

E quindi, il "cuore" del backup:
Codice (Java): [Seleziona]
        Button backup;
        private final String _backupFileName = "countries";

        ....

                backup = (Button) view.findViewById(R.id.backup);
                        backup.setOnClickListener(new OnClickListener() {

                                public void onClick(View v) {
                                        if (null != mCountriesDB) {
                                                backupDatabase(mCountriesDB.getDbPath());//mCountriesDb è la classe estesa che permette la gestione del database.
                                        }
                                }
                        });
                return view;
        }

        public void backupDatabase(String dbPath) {
                if (dbPath == null) {
                        Toast.makeText(getActivity(), getString(R.string.msg_db_null), Toast.LENGTH_LONG).show();
                        return;
                }
                try {
                        File sd = Environment.getExternalStorageDirectory();
                        if (sd.canWrite()) {                           
                                File currentDB = new File(dbPath);//path del db su telefono
                                File backupDB = new File(sd, _backupFileName);//file di destinazione

                                FileChannel src = new FileInputStream(currentDB).getChannel();//apriamo un filechannel sul db e sul file di destinazione
                                FileChannel dst = new FileOutputStream(backupDB).getChannel();
                                dst.transferFrom(src, 0, src.size());//trasferiamo il contenuto
                                src.close();
                                dst.close();
                                Toast.makeText(getActivity().getBaseContext(), String.format(getString(R.string.msg_db_location), backupDB.toString()), Toast.LENGTH_LONG).show();

                        } else {
                                Log.e("Permission denied", "Can't write to SD card, add permission");
                        }
                } catch (Exception e) {
                        Toast.makeText(getActivity().getBaseContext(), e.toString(), Toast.LENGTH_LONG).show();
                }
        }

Il metodo è davvero semplice, l'unica cosa di cui avete bisogno è il path del database, che si ottiene con il metodo:
Citazione
SQLiteDatabase.getPath()
Vi verrà restituita una stringa contenente il path completo per arrivare al database, che (vi ricordo) è accessibile solo dalla vostra app, quindi solo voi potete farne il backup.


Verifica e apertura db
Una volta lanciata l'applicazione ed eseguito il backup, vi ritroverete il file al path specificato sul layout (di solito /sdcard/countries oppure /mnt/sdcard/countries , in blu nell'immagine).
Da qui è facile fare un export da interfaccia di eclipse (in verde nell'immagine), da copia file su pc dopo aver montato la memoria come pennetta usb oppure aprire il file direttamente sul telefono.


I possibili miglioramenti o le espansioni sono molte, a partire dalla possibilità di inviare via mail il db (magari come funzionalità di test), allo sharing intent, oppure, cosa ancora più utile, la possibilità di lanciare il backup solo tramite combinazione particolare Utilizzare i Telephony.SECRET_CODE - Android Developers Italia

Ed ora, un paio di screenshot per mostrarvi i risultati:


Piccole aggiunte personali:
- Gestione degli stili in base alla versione android, con Theme di default per versioni < 11 e holo per versioni => 11
- Gestione doppia lingua (italiano/inglese)
- Gestione e visualizzazione degli errori sugli edit text (come da framework)
- Gestione ListView con ViewHolder
LOGCAT: Non sai cos'è? -> Android Debug Bridge | Android Developers
               Dov'è in Eclipse? -> Window -> Open Prospective -> DDMS e guarda in basso!
[Obbligatorio] Logcat, questo sconosciuto! (Gruppo AndDev.it LOGTFO) - Android Developers Italia

Offline tiziano0371

  • Nuovo arrivato
  • *
  • Post: 20
  • Respect: 0
    • Mostra profilo
Re:[medio] Backup di un database SQLite su sdcard.
« Risposta #1 il: 26 Luglio 2012, 14:51:36 CEST »
0
OTTIMO TUTORIAL!!!
visto che ci sei sarebbe interessante completare il tutto con la funzione RECUPERO BACKUP, molto utile nel caso di reset del dispositivo. grazie.

Offline Nicola_D

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 1870
  • Respect: +241
    • Github
    • Google+
    • Mostra profilo
  • Dispositivo Android:
    Google Nexus S - Google Nexus 7
  • Sistema operativo:
    Windows 7
Re:[medio] Backup di un database SQLite su sdcard.
« Risposta #2 il: 26 Luglio 2012, 20:29:12 CEST »
0
OTTIMO TUTORIAL!!!
visto che ci sei sarebbe interessante completare il tutto con la funzione RECUPERO BACKUP, molto utile nel caso di reset del dispositivo. grazie.
non ci avevo pensato, ottima idea... vediamo cosa arrivo a fare, ma la procedura (a naso) è molto semplice, basta invertire i filechannel, aggiungiendo però i permessi di lettura su sd card...
LOGCAT: Non sai cos'è? -> Android Debug Bridge | Android Developers
               Dov'è in Eclipse? -> Window -> Open Prospective -> DDMS e guarda in basso!
[Obbligatorio] Logcat, questo sconosciuto! (Gruppo AndDev.it LOGTFO) - Android Developers Italia