2015-04-24 31 views
7

Udało mi się utworzyć kopię zapasową bazy danych na karcie SD i odtworzyć z niej, ale zdałem sobie sprawę, że celem mojego tworzenia kopii zapasowej jest zapewnienie bezpieczeństwa danych iw tym celu przypadku, gdy samo fizyczne urządzenie jest uszkodzone, utracone lub spontanicznie się zapala, tak samo jak kopia zapasowa na karcie SD. Tak więc posiadanie kopii zapasowej w tym samym miejscu co oryginał w tym przypadku, zupełnie szczerze pokonuje cel utworzenia kopii zapasowej.Użycie Dysku Google do tworzenia kopii zapasowych i przywracania bazy danych SQLite

Więc pomyślałem o korzystaniu z Dysku Google jako bezpieczniejszego miejsca do przechowywania pliku db, który jest bezpłatny. Zerknąłem na wersję demonstracyjną Google quickstart, w której pracowałem dobrze. Ale nadal nie mam pojęcia, jak to zrobić w moim przypadku.

Znalazłem kod do grania, ale nadal używa on niektórych nieaktualnych metod i do tej pory udało mi się go uruchomić tylko po usunięciu przestarzałego obszaru, ale tworzy tylko pusty plik binarny na moim Dysku Google, więc myślę, że przestarzały obszar to miejsce, w którym faktycznie przesyła zawartość kopii zapasowej bazy danych. Jeśli ktokolwiek mógłby pomóc, byłoby to bardzo cenne.

Zostawię to poniżej na wypadek, gdyby ktoś mógł go użyć, żeby lepiej mi to wyjaśnić. Poza tym zaznaczyłem poniższą metodę, która zbliża się do końca.

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

Upewnij się, że rozumiesz różnicę między API spoczynku napędu i GdaĹ. Dla twojego przypadku użycia, gdaa jest najlepszym sposobem, więc powinieneś zignorować samouczek szybkiego startu, który nie jest gdaa. Na marginesie, umieszczenie tego kodu w pytaniu nie jest zbyt użyteczne. – pinoyyid

+0

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

Odpowiedz

4

Oba interfejsy API używane do uzyskiwania dostępu do usługi Dysk Google z treścią binarną. Jedyne, co musisz zrobić, to wgrać twój binarny plik DB, nadać mu prawidłowy typ MIME i NAME (tytuł).
Wybór API zależy od Ciebie, GDAA zachowuje się jak "lokalny" podmiot z przesyłanymi/pobieranymi plikami obsługiwanymi przez Usługi Google Play, REST Api jest bardziej niskopoziomowy, co zapewnia większą kontrolę, ale musisz zadbać o problemy sieciowe (Wi-Fi wł/wył, itp.), to znaczy zazwyczaj musisz zbudować usługę synchronizacji, aby to zrobić. Z GDAA jest to zrobione przez GooPlaySvcs. Ale dygresję.
Mogę wskazać ci ten GitHub demo, całkiem niedawno (GooPlaySvcs 7.00. +), Używam do testowania różnych problemów REST/GDAA. Funkcja MainActivity jest nieco skomplikowana dzięki temu, że umożliwia przełączanie między różnymi kontami Google, ale jeśli przejdziesz przez these hurdles, możesz użyć opakowań REST lub GDAA CRUD.

Spójrz na this line. Bufor bajtowy [] zawiera binarne dane JPEG i działa z mime typu "image/jpeg" (i nazwą opartą na czasie). Jedyną rzeczą, którą musisz zrobić, jeśli to załadować plik DB do byte [] buffer stosując konstrukcję takiego:

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; 
    } 

nie pamiętam typu MIME dla SQLite DB teraz, ale jestem pewien, że można zrobić, ponieważ robiłem to dokładnie raz (kod nie ma teraz, niestety). I pamiętam, że mogłem faktycznie uzyskać dostęp i modyfikować SQLite DB "w chmurze" za pomocą jakiejś aplikacji internetowej.

Powodzenia

UPDATE:
Po pisałem rant powyżej Spojrzałem na demo mówisz. Jeśli działasz, najprostszym sposobem jest podłączenie pliku DB w prawo here, ustawienie poprawnego MIME i możesz już iść. Wybierz.
Aby rozwiązać problem "przestarzałego". GDAA wciąż jest rozwijany, a szybki start ma ponad rok. To jest świat, w którym żyjemy :-)

+0

Dzięki za link i objaśnienia, zostały rozliczone kilka moich pytań. Postanowiła pójść z twoją sugestią, pracując nad usunięciem części "zrób zdjęcie" i zastąpieniem jej czymś innym. Próbowałem pracować nad drugim, ale do tej pory wciąż otrzymuję pusty plik binarny. Po prostu to zrobię innym razem. W tej chwili po prostu pracuję nad przywróceniem bazy danych z pliku dysku, nie miałbyś żadnych wskazówek na ten temat? – Cytus

+0

Rdzeń, na którym powinieneś się skupić, znajduje się tutaj: https://github.com/seanpjanson/GDAADemo/blob/master/src/main/java/com/andyscan/gdaademo/GDAA.java#L143. Zmodyfikuj metodę tak, aby pasowała do twojego środowiska i sprawdź "buf" (zauważ, że jest to buf.length). Na końcu powinieneś zobaczyć plik w GooDrive, a jego długość powinna być taka sama. Spróbuj pobrać go na pulpit i porównać go z oryginałem z urządzenia z systemem Android. GDAA nie dba o to, jaki plik wysyłasz, po prostu przesuwa bajty w górę, tworzy obiekt i dołącza metadane (tytuł, mim, opis, ...) – seanpj

+0

@seanpj Link wydaje się zepsuty !! Czy możesz zaktualizować? – shadygoneinsane