2015-04-24 15 views
7

Tôi đã tạo bản sao lưu cơ sở dữ liệu trên thẻ SD và khôi phục từ đó nhưng nhận ra rằng mục đích của bản sao lưu của tôi là đảm bảo sự an toàn của dữ liệu và trong trường hợp nếu bản thân thiết bị vật lý bị hư hỏng, bị mất hoặc tự động cháy thì sao lưu trên thẻ SD. Vì vậy, có bản sao lưu trong cùng một vị trí như bản gốc trong trường hợp này, khá thẳng thắn đánh bại mục đích của việc có một bản sao lưu.Sử dụng Google Drive để sao lưu và khôi phục Cơ sở dữ liệu SQLite

Vì vậy, tôi đã nghĩ đến việc sử dụng Google Drive như một nơi an toàn hơn để giữ tệp db, điều đó và hoàn toàn miễn phí. Tôi đã xem qua bản giới thiệu quickstart của Google mà tôi đã làm việc tốt. Nhưng tôi vẫn không có ý tưởng làm thế nào để có được điều này được thực hiện cho trường hợp của tôi.

Tôi đã tìm thấy một số mã để fiddle nhưng nó vẫn sử dụng một số phương pháp không được chấp nhận và cho đến nay tôi chỉ quản lý để chạy khi bỏ qua khu vực không dùng nữa nhưng nó chỉ tạo tệp nhị phân trống trong Google Drive của tôi nghĩ rằng khu vực không dùng nữa là nơi nó thực sự tải lên nội dung sao lưu DB. Nếu bất cứ ai có thể giúp đỡ điều đó sẽ được đánh giá cao.

Tôi sẽ để nó xuống dưới đây trong trường hợp bất kỳ ai cũng có thể sử dụng nó để giải thích mọi thứ cho tôi tốt hơn. Tôi cũng đã đánh dấu phương pháp không được chấp nhận bên dưới, nó gần kết thúc.

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

Đảm bảo bạn hiểu sự khác biệt giữa API còn lại Drive và GDAA. Đối với trường hợp sử dụng của bạn, gdaa là cách tốt nhất để đi, vì vậy bạn nên bỏ qua bất kỳ hướng dẫn bắt đầu nhanh nào không phải là gdaa. Ngoài ra, việc đăng nhiều mã vào một câu hỏi không phải là rất hữu ích. – pinoyyid

+0

Xem điều này: http://stackoverflow.com/questions/33602812/backup-restore-sqllite-database-to-google-drive-app-folder/39044477#39044477 – Jose19589

Trả lời

4

Cả hai API được sử dụng để truy cập Google Drive đối phó với nội dung nhị phân. Vì vậy, điều duy nhất bạn phải làm là tải lên tệp DB nhị phân của bạn, cung cấp cho nó một loại MIME thích hợp và một NAME (tiêu đề).
Việc chọn API phụ thuộc vào bạn, GDAA hoạt động như một thực thể 'cục bộ' với các tải lên/tải xuống do Dịch vụ Google Play xử lý, REST Api cấp thấp hơn, giúp bạn kiểm soát nhiều hơn, nhưng bạn phải chăm sóc các vấn đề về mạng (bật/tắt wifi, v.v.), tức là bạn thường phải xây dựng một dịch vụ đồng bộ để thực hiện điều đó. Với GDAA, nó được thực hiện cho bạn bởi GooPlaySvcs. Nhưng tôi lạc đề.
Tôi có thể chỉ cho bạn điều này GitHub demo, khá gần đây (GooPlaySvcs 7.00. +), Tôi sử dụng để kiểm tra các vấn đề REST/GDAA khác nhau. MainActivity hơi phức tạp bởi thực tế là nó cho phép chuyển đổi giữa các tài khoản Google khác nhau, nhưng nếu bạn vượt qua these hurdles, bạn có thể sử dụng trình bao bọc REST hoặc GDAA CRUD.

Hãy xem this line. Bộ đệm byte [] chứa dữ liệu JPEG nhị phân và nó đi với loại mime "image/jpeg" (và tên dựa trên thời gian). Điều duy nhất bạn phải làm gì nếu là tải tập tin DB của bạn thành một byte [] buffer sử dụng một cấu trúc như thế này:

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

Tôi không nhớ kiểu MIME cho SQLite DB bây giờ, nhưng tôi chắc chắn nó có thể được thực hiện kể từ khi tôi đã làm chính xác một lần (mã đã biến mất ngay bây giờ, thật không may). Và tôi nhớ rằng tôi thực sự có thể truy cập và sửa đổi DB SQLite trong đám mây 'bằng cách sử dụng một số ứng dụng web.

Good Luck

UPDATE:
Sau khi tôi đã viết rant trên tôi nhìn vào bản demo bạn đang nói về. Nếu bạn có nó làm việc, cách dễ nhất là thực sự để cắm tập tin DB của bạn ngay here, thiết lập MIME chính xác và bạn tốt để đi. Đưa bạn đi.
Và để giải quyết vấn đề 'không dùng nữa' của bạn. GDAA vẫn đang được phát triển và khởi động nhanh hơn một tuổi. Đó là thế giới chúng ta sống ở :-)

+0

Cảm ơn bạn đã liên kết và giải thích, họ đã xóa lên một vài câu hỏi của tôi. Quyết định đi với đề xuất của bạn, chỉ cần làm việc trên loại bỏ phần "chụp ảnh" và thay thế nó bằng cái gì khác. Tôi đã thử làm việc trên một cái khác nhưng cho đến nay vẫn nhận được một nhị phân trống. Tôi sẽ chỉ đến đó một thời gian khác. Ngay bây giờ tôi sẽ chỉ làm việc trên khôi phục lại db từ tập tin ổ đĩa, bạn sẽ không xảy ra để có bất kỳ con trỏ cho rằng bạn sẽ? – Cytus

+0

Cốt lõi bạn nên tập trung ở đây là: https://github.com/seanpjanson/GDAADemo/blob/master/src/main/java/com/andyscan/gdaademo/GDAA.java#L143. Sửa đổi phương thức để nó phù hợp với môi trường của bạn và bước qua việc kiểm tra 'buf' (thông báo là buf.length). Cuối cùng, bạn sẽ thấy tệp trong GooDrive và chiều dài của nó cũng giống nhau. Hãy thử tải nó xuống máy tính để bàn của bạn so sánh nó với bản gốc từ thiết bị Android của bạn. GDAA không quan tâm bạn đang sử dụng loại tệp nào, nó chỉ di chuyển các byte lên, tạo đối tượng và đính kèm siêu dữ liệu (tiêu đề, mô tả, mô tả, ...) – seanpj

+0

@seanpj Link dường như bị hỏng !! Bạn có thể vui lòng cập nhật! – shadygoneinsane

Các vấn đề liên quan