2015-04-24 16 views
7

Sono riuscito a creare un backup del mio database su una scheda SD e ripristinare da lì ma ho capito che lo scopo del mio backup è quello di garantire la sicurezza dei dati e in questo caso se il dispositivo fisico stesso è danneggiato, perso, o combusta spontaneamente, così sarà il backup sulla scheda SD. Quindi, avendo il backup nello stesso posto dell'originale in questo caso, sconfigge francamente lo scopo di avere un backup.Utilizzo di Google Drive per il backup e il ripristino del database SQLite

Quindi ho pensato di utilizzare Google Drive come un luogo più sicuro per conservare il file db, che è gratuito. Ho dato una sbirciatina alla demo di Google quickstart che ho funzionato perfettamente. Ma non ho ancora idea di come ottenere questo risultato per il mio caso.

Ho trovato un codice con cui giocare ma sta ancora utilizzando alcuni metodi obsoleti e finora sono riuscito a eseguirlo solo quando ometto l'area deprecata ma crea solo un file binario vuoto nel mio Google Drive, quindi pensa che l'area deprecata sia dove carica effettivamente il contenuto del backup del DB. Se qualcuno potesse aiutarlo sarebbe molto apprezzato.

Lo lascio qui sotto nel caso in cui qualcuno possa usarlo per spiegare meglio le cose. Ho anche contrassegnato il metodo deprecato di seguito, è vicino alla fine.

public class ExpectoPatronum extends Activity implements ConnectionCallbacks, OnConnectionFailedListener { 

private static final String TAG = "MainActivity"; 
private GoogleApiClient api; 
private boolean mResolvingError = false; 
private DriveFile mfile; 
private static final int DIALOG_ERROR_CODE =100; 
private static final String DATABASE_NAME = "demodb"; 
private static final String GOOGLE_DRIVE_FILE_NAME = "sqlite_db_backup"; 

@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 

    // Create the Drive API instance 
    api = new GoogleApiClient.Builder(this).addApi(Drive.API).addScope(Drive.SCOPE_FILE). 
      addConnectionCallbacks(this).addOnConnectionFailedListener(this).build(); 
} 

@Override 
public void onStart() { 
    super.onStart(); 
    if(!mResolvingError) { 
     api.connect(); // Connect the client to Google Drive 
    } 
} 

@Override 
public void onStop() { 
    super.onStop(); 
    api.disconnect(); // Disconnect the client from Google Drive 
} 

@Override 
public void onConnectionFailed(ConnectionResult result) { 
    Log.v(TAG, "Connection failed"); 
    if(mResolvingError) { // If already in resolution state, just return. 
     return; 
    } else if(result.hasResolution()) { // Error can be resolved by starting an intent with user interaction 
     mResolvingError = true; 
     try { 
      result.startResolutionForResult(this, DIALOG_ERROR_CODE); 
     } catch (SendIntentException e) { 
      e.printStackTrace(); 
     } 
    } else { // Error cannot be resolved. Display Error Dialog stating the reason if possible. 
     ErrorDialogFragment fragment = new ErrorDialogFragment(); 
     Bundle args = new Bundle(); 
     args.putInt("error", result.getErrorCode()); 
     fragment.setArguments(args); 
     fragment.show(getFragmentManager(), "errordialog"); 
    } 
} 

@Override 
public void onActivityResult(int requestCode, int resultCode, Intent data) { 
    if(requestCode == DIALOG_ERROR_CODE) { 
     mResolvingError = false; 
     if(resultCode == RESULT_OK) { // Error was resolved, now connect to the client if not done so. 
      if(!api.isConnecting() && !api.isConnected()) { 
       api.connect(); 
      } 
     } 
    } 
} 

@Override 
public void onConnected(Bundle connectionHint) { 
    Log.v(TAG, "Connected successfully"); 

    /* Connection to Google Drive established. Now request for Contents instance, which can be used to provide file contents. 
     The callback is registered for the same. */ 
    Drive.DriveApi.newDriveContents(api).setResultCallback(contentsCallback); 
} 

final private ResultCallback<DriveApi.DriveContentsResult> contentsCallback = new ResultCallback<DriveApi.DriveContentsResult>() { 

    @Override 
    public void onResult(DriveApi.DriveContentsResult result) { 
     if (!result.getStatus().isSuccess()) { 
      Log.v(TAG, "Error while trying to create new file contents"); 
      return; 
     } 

     String mimeType = MimeTypeMap.getSingleton().getExtensionFromMimeType("db"); 
     MetadataChangeSet changeSet = new MetadataChangeSet.Builder() 
       .setTitle(GOOGLE_DRIVE_FILE_NAME) // Google Drive File name 
       .setMimeType(mimeType) 
       .setStarred(true).build(); 
     // create a file on root folder 
     Drive.DriveApi.getRootFolder(api) 
       .createFile(api, changeSet, result.getDriveContents()) 
       .setResultCallback(fileCallback); 
    } 

}; 

final private ResultCallback<DriveFileResult> fileCallback = new ResultCallback<DriveFileResult>() { 

    @Override 
    public void onResult(DriveFileResult result) { 
     if (!result.getStatus().isSuccess()) { 
      Log.v(TAG, "Error while trying to create the file"); 
      return; 
     } 
     mfile = result.getDriveFile(); 
     mfile.open(api, DriveFile.MODE_WRITE_ONLY, null).setResultCallback(contentsOpenedCallback); 
    } 
}; 

final private ResultCallback<DriveApi.DriveContentsResult> contentsOpenedCallback = new ResultCallback<DriveApi.DriveContentsResult>() { 

    @Override 
    public void onResult(DriveApi.DriveContentsResult result) { 

     if (!result.getStatus().isSuccess()) { 
      Log.v(TAG, "Error opening file"); 
      return; 
     } 

     try { 
      FileInputStream is = new FileInputStream(getDbPath()); 
      BufferedInputStream in = new BufferedInputStream(is); 
      byte[] buffer = new byte[8 * 1024]; 
      DriveContents content = result.getDriveContents(); 
      BufferedOutputStream out = new BufferedOutputStream(content.getOutputStream()); 
      int n = 0; 
      while((n = in.read(buffer)) > 0) { 
       out.write(buffer, 0, n); 
      } 

      in.close(); 
commitAndCloseContents is DEPRECATED -->/**mfile.commitAndCloseContents(api, content).setResultCallback(new ResultCallback<Status>() { 
       @Override 
       public void onResult(Status result) { 
        // Handle the response status 
       } 
      });**/ 
     } catch (FileNotFoundException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
    } 

}; 

private File getDbPath() { 
    return this.getDatabasePath(DATABASE_NAME); 
} 

@Override 
public void onConnectionSuspended(int cause) { 
    // TODO Auto-generated method stub 
    Log.v(TAG, "Connection suspended"); 

} 

public void onDialogDismissed() { 
    mResolvingError = false; 
} 

public static class ErrorDialogFragment extends DialogFragment { 
    public ErrorDialogFragment() {} 

    public Dialog onCreateDialog(Bundle savedInstanceState) { 
     int errorCode = this.getArguments().getInt("error"); 
     return GooglePlayServicesUtil.getErrorDialog(errorCode, this.getActivity(), DIALOG_ERROR_CODE); 
    } 

    public void onDismiss(DialogInterface dialog) { 
     ((ExpectoPatronum) getActivity()).onDialogDismissed(); 
    } 
} 
} 
+0

assicurarsi di aver compreso la differenza tra l'API Unità di riposo e GdaÅ. Per il tuo caso d'uso, gdaa è il modo migliore per andare, quindi dovresti ignorare qualsiasi tutorial di avvio rapido che non sia la gdaa. Per inciso, postare quel numero di codice in una domanda non è molto utile. – pinoyyid

+0

Vedi questo: http://stackoverflow.com/questions/33602812/backup-restore-sqllite-database-to-google-drive-app-folder/39044477#39044477 – Jose19589

risposta

4

Entrambe le API utilizzate per accedere a Google Drive gestiscono un contenuto binario. Quindi l'unica cosa che devi fare è caricare il tuo file DB binario, dargli un tipo MIME corretto e un NOME (titolo).
La selezione dell'API dipende da te, GDAA si comporta come un'entità "locale" con caricamenti/download gestiti da Google Play Services, REST Api è più di basso livello, offrendoti maggiore controllo, ma devi occuparti dei problemi di rete (wifi on/off, ecc.), cioè di solito devi creare un servizio di sincronizzazione per farlo. Con GDAA è fatto per te da GooPlaySvcs. Ma sto divagando.
Posso indirizzarti a questo GitHub demo, abbastanza recente (GooPlaySvcs 7.00. +), Che utilizzo per testare diversi problemi REST/GDAA. MainActivity è un po 'complicato dal fatto che consente di passare da un account Google all'altro, ma se passi attraverso lo these hurdles, puoi utilizzare i wrapper CREST o GDAA di GDAA.

Date un'occhiata a this line. Il buffer byte [] contiene dati JPEG binari e include il tipo mime "image/jpeg" (e un nome basato sul tempo). L'unica cosa che dovete fare se è caricare il file di DB in un byte [] buffer utilizzando un costrutto come questo:

private static final int BUF_SZ = 4096; 

    static byte[] file2Bytes(File file) { 
    if (file != null) try { 
     return is2Bytes(new FileInputStream(file)); 
    } catch (Exception ignore) {} 
    return null; 
    } 

    static byte[] is2Bytes(InputStream is) { 
    byte[] buf = null; 
    BufferedInputStream bufIS = null; 
    if (is != null) try { 
     ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream(); 
     bufIS = new BufferedInputStream(is); 
     buf = new byte[BUF_SZ]; 
     int cnt; 
     while ((cnt = bufIS.read(buf)) >= 0) { 
     byteBuffer.write(buf, 0, cnt); 
     } 
     buf = byteBuffer.size() > 0 ? byteBuffer.toByteArray() : null; 
    } catch (Exception e) {le(e);} 
    finally { 
     try { 
     if (bufIS != null) bufIS.close(); 
     } catch (Exception e) {le(e);} 
    } 
    return buf; 
    } 

non ricordo il tipo MIME per SQLite DB ora, ma sono sicuro che può essere fatto poiché stavo facendo esattamente quello una volta (il codice è andato ora, sfortunatamente). E ricordo che potevo effettivamente accedere e modificare il DB SQLite "up in the cloud" usando alcune app web.

Good Luck

UPDATE:
Dopo che ho scritto lo sproloquio sopra ho guardato la demo si sta parlando. Se lo fai funzionare, il modo più semplice è in realtà di collegare il tuo file DB a destra here, impostare il MIME corretto e sei a posto. Prenditi a prendere.
E per risolvere il problema "deprecato". GDAA è ancora in fase di sviluppo e il quickstart ha più di un anno. Questo è il mondo in cui viviamo :-)

+0

Grazie per il link e le spiegazioni, hanno eliminato alcune delle mie domande. Ho deciso di seguire il tuo suggerimento, semplicemente lavorando sulla rimozione della parte "scatta foto" e sostituendola con qualcos'altro. Ho provato a lavorare sull'altro ma finora ho ancora un binario vuoto. Ci arriverò solo un'altra volta. In questo momento lavorerò solo sul ripristino del db dal file del disco, non avresti alcun suggerimento per quello? – Cytus

+0

Il nucleo su cui dovresti concentrarti è qui: https://github.com/seanpjanson/GDAADemo/blob/master/src/main/java/com/andyscan/gdaademo/GDAA.java#L143. Modifica il metodo in modo che si adatti al tuo ambiente e passa attraverso il controllo del 'buf' (notare che è buf.length). Alla fine, dovresti vedere il file in GooDrive e la sua lunghezza dovrebbe essere la stessa. Prova a scaricare sul desktop un confronto con l'originale dal tuo dispositivo Android. A GDAA non importa quale tipo di file stai spedendo, sposta solo i byte verso l'alto, crea un oggetto e allega i metadati (titolo, mimo, descrizione, ...) – seanpj

+0

@seanpj Link sembra rotto !! Potresti aggiornare per favore! – shadygoneinsane