【问题标题】:Read from sqlite db in Drive and write it to local db - Android从 Drive 中的 sqlite db 读取并将其写入本地 db - Android
【发布时间】:2015-09-02 09:25:39
【问题描述】:

我正在开发一个需要将 sqlite 数据库备份到 Google Drive 的应用程序(我已完成)。现在我想将该数据库恢复到我的应用程序中,并在运行时从 SD 卡加载它。

我正在使用 GitHub 上的 android-demo/RetrieveContentsActivity 从 Google Drive 读取数据库的内容,并且我正在使用以下代码将其写回我的数据库中

ListView onItemClickListener

               Drive.DriveApi
                    .getFile(api,
                            mResultsAdapter.getItem(position).getDriveId())
                    .openContents(api, DriveFile.MODE_READ_ONLY, null)
                    .setResultCallback(contentsOpenedCallback);

ResultCallBack

final private ResultCallback<ContentsResult> contentsOpenedCallback = new ResultCallback<ContentsResult>() {
    @Override
    public void onResult(ContentsResult result) {
        if (!result.getStatus().isSuccess()) {
            return;
        }

        if (GetFileFromDrive(result)) {
            Toast.makeText(getApplicationContext(), "File restored",
                    Toast.LENGTH_LONG).show();
        }
    }
};

GetFileFromDrive

private boolean GetFileFromDrive(ContentsResult result) {
    Contents contents = result.getContents();
    InputStream mInput = contents.getInputStream();
    OutputStream mOutput;
    boolean restoreSuccess = false;

    try {
        mOutput = new FileOutputStream(getDatabasePath(DB_NAME));
        byte[] mBuffer = new byte[1024];
        int mLength;
        while ((mLength = mInput.read(mBuffer)) > 0) {
            mOutput.write(mBuffer, 0, mLength);
        }

        mOutput.flush();

        mInput.close();
        mOutput.close();
        restoreSuccess = true;
    } catch (FileNotFoundException e) {
        // TODO: Log exception
        Log.e("error_filenotfound", "" + e.getLocalizedMessage());
    } catch (IOException e) {
        // TODO: Log Exception
        Log.e("error_io", "" + e.getLocalizedMessage());
    }

    return restoreSuccess;
}

问题是它删除了我的 sqlite 中已经存在的数据并完全清空了我的 sqlite。我试图在谷歌上找到这个问题,但没有一个能帮助我。

这个人 - Google Drive Android api - Downloading db file from drive - 正在尝试做同样的事情,但他说他用 open 替换了 openContents。我试过了,但它给出了The method open(GoogleApiClient, int, null) is undefined for the type DriveFile的错误。

任何形式的帮助将不胜感激,请。我已经坚持了将近一个星期了,我很生气。

【问题讨论】:

  • 哇。提出问题的负面影响。也没有关于我应该做什么的反馈。
  • 他们在 Google Play Service v 7.x 中更改了 Drive API。如果您仍在使用 openContents() 而不是 open(),那么您必须使用旧版本。当前是7.8.0

标签: android sqlite google-drive-api google-drive-android-api


【解决方案1】:

假设您已将数据库下载到云端硬盘。 现在,我们如何在您的应用程序中获取它: 此示例包含带有 GUI 的 FragmentActivity。但是,您可以轻松地将其调整为静默下载。

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

        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addApi(Drive.API)
                .addScope(Drive.SCOPE_FILE)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .build();
        mGoogleApiClient.connect();
    }

@Override
    protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
        switch (requestCode) {
            case REQUEST_CODE_SUCCESS:
                // Called after a file is saved to Drive.
                if (resultCode == RESULT_OK) {
                    finish();
                } else {
                    finish();
                }
                break;
            case REQUEST_CODE_OPENER:
                if (resultCode == RESULT_OK){
                    //Toast.makeText(this, R.string.pref_data_drive_import_success, Toast.LENGTH_LONG).show();
                    DriveId driveId = data.getParcelableExtra(
                            OpenFileActivityBuilder.EXTRA_RESPONSE_DRIVE_ID);

                    DriveFile file = driveId.asDriveFile();

                    processDriveFile(file);
                } else {
                    Toast.makeText(this, R.string.pref_data_drive_import_error, Toast.LENGTH_LONG).show();
                    finish();
                }
                break;
        }
    }

@Override
    public void onConnectionFailed(@NonNull ConnectionResult result) {
        // Called whenever the API client fails to connect.
        Log.i(TAG, "GoogleApiClient connection failed: " + result.toString());

        if (!result.hasResolution()){
            GoogleApiAvailability.getInstance().getErrorDialog(this, result.getErrorCode(), 0).show();
            return;
        }

        try {
            result.startResolutionForResult(this, REQUEST_CODE_RESOLUTION);
            finish();
        } catch (IntentSender.SendIntentException e){
            Log.e(TAG, "Exception while starting resolution activity", e);
        }
    }

    @Override
    public void onConnected(Bundle connectionHint) {
        Log.i(TAG, "API client connected.");

        IntentSender intentSender = Drive.DriveApi
                .newOpenFileActivityBuilder()
                //.setMimeType(new String[] { "application/x-sqlite3" })
                .build(mGoogleApiClient);
        try {
            startIntentSenderForResult(
                    intentSender, REQUEST_CODE_OPENER, null, 0, 0, 0);
        } catch (IntentSender.SendIntentException e) {
            Log.w(TAG, "Unable to send intent", e);
        }

    }

@Override
    public void onConnectionSuspended(int cause) {
        Log.i(TAG, "GoogleApiClient connection suspended");
    }

现在,我们会检查所选文件是否是我们的数据库并替换它

private void processDriveFile(DriveFile file){
        Log.i(TAG, "processDriveFile started");
        file.open(mGoogleApiClient, DriveFile.MODE_READ_ONLY, null)
                .setResultCallback(new ResultCallback<DriveApi.DriveContentsResult>() {
            @Override
            public void onResult(@NonNull DriveApi.DriveContentsResult driveContentsResult) {
                if (!driveContentsResult.getStatus().isSuccess()){
                    Log.i(TAG, "Failed to create new contents.");
                    Toast.makeText(getApplicationContext(), "Import DB error", Toast.LENGTH_LONG).show();
                    finish();
                    return;
                }

                Log.i(TAG, "New contents created.");

                DriveContents driveContents = driveContentsResult.getDriveContents();

                InputStream inputStream = driveContents.getInputStream();

                String dbDir = context.getDatabasePath("oldDbName.db").getParent();
                String newFileName = "newDbName.db";

                Log.i(TAG, "dbDir = " + dbDir);

                // Deletion previous versions of new DB file from drive
                File file = new File(dbDir + "/" + newFileName);
                if (file.exists()){
                    Log.i(TAG, "newDbName.db EXISTS");
                    if (file.delete()){
                        Log.i(TAG, "newDbName.db DELETING old file....");
                    } else {
                        Log.i(TAG, "newDbName.db Something went wrong with deleting");
                        Toast.makeText(getApplicationContext(), "Import DB error", Toast.LENGTH_LONG).show();
                        finish();
                    }
                }

                try {
                    OutputStream output = new FileOutputStream(file);
                    try {
                        try {
                            byte[] buffer = new byte[4 * 1024]; // or other buffer size
                            int read;

                            while ((read = inputStream.read(buffer)) != -1) {
                                output.write(buffer, 0, read);
                            }
                            output.flush();
                        } finally {
                            output.close();
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        Toast.makeText(getApplicationContext(), "Import DB error", Toast.LENGTH_LONG).show();
                        finish();
                    }
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                    Toast.makeText(getApplicationContext(), "Import DB error", Toast.LENGTH_LONG).show();
                    finish();
                } finally {
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                        Toast.makeText(getApplicationContext(), "Import DB error", Toast.LENGTH_LONG).show();
                        finish();
                    }
                }

                // Check if file really match our DB
                // Connection it to custom SqliteOpenHelper
                ImportDBManager importDBManager = new ImportDBManager(context);
                importDBManager.open();
                // We have some System table in DB with 1 row in it for this goal
                // So, we check if there is data in it
                List<DataModelSystem> dataModelSystem = importDBManager.getSystemSingleRow(1);
                importDBManager.close();
                if (dataModelSystem.size() > 0){
                    Log.i(TAG, "DB MATCH!");
                    String mainDbName = context.getDatabasePath(DatabaseHelper.DB_NAME).toString();
                    String newDbName = context.getDatabasePath(ImportDatabaseHelper.DB_NAME).toString();
                    File oldDbFile = new File(mainDbName);
                    File newDbFile = new File(newDbName);

                    if (newDbFile.exists()){
                        Log.i(TAG, "newDbName.db EXISTS");
                        if (oldDbFile.delete()){
                            Log.i(TAG, "newDbName.db DELETING old file....");
                            try {
                                copyFile(newDbFile, oldDbFile);
                                Log.i(TAG, "success! New database");
                                Toast.makeText(getApplicationContext(), "Import OK!!!!1", Toast.LENGTH_LONG).show();
                            } catch (IOException e) {
                                Toast.makeText(getApplicationContext(), "Import DB error", Toast.LENGTH_LONG).show();
                                Log.i(TAG, "fail! old database will remain");
                                e.printStackTrace();
                                finish();
                            }
                        } else {
                            Log.i(TAG, "newDbName.db Something went wrong with deleting");
                            Toast.makeText(getApplicationContext(), "Import DB error", Toast.LENGTH_LONG).show();
                            finish();
                        }
                    }
                } else {
                    Log.i(TAG, "db not Match!");
                    Toast.makeText(getApplicationContext(),"Import DB error", Toast.LENGTH_LONG).show();
                    finish();
                }
            }
        });
        finish();
    }

    // Replacing old file
    private static void copyFile(File src, File dst) throws IOException {
        Log.i(TAG, "src = " + src.getAbsolutePath());
        Log.i(TAG, "dst = " + dst.getAbsolutePath());
        FileInputStream var2 = new FileInputStream(src);
        FileOutputStream var3 = new FileOutputStream(dst);
        byte[] var4 = new byte[1024];

        int var5;
        while((var5 = var2.read(var4)) > 0) {
            var3.write(var4, 0, var5);
        }

        var2.close();
        var3.close();
    }

100% 正常工作

【讨论】:

    【解决方案2】:

    没有人会运行和调试您的代码。以下几点可以提供帮助:

    1/ 假设您的应用上传了您的 DB 文件(GooDrive 不关心它是 DB 还是其他任何东西 - 只是一个字节流)。记录/保存它的 DriveId - 它应该看起来像“DriveId:CAES........

    2/ 检查 GooDrive (drive.google.com) 中的文件是否具有您期望的大小。您还可以使用第三方 SQLite Web 应用检查驱动器中 DB 文件的状态(确保使用正确的 MIME 类型创建/上传它)。

    3/ 在您的 Android 应用中,将您保存的 DriveId 传递给此方法:

      private static GoogleApiClient mGAC;
      ...
      /*******************************************************************
       * get file contents
       * @param dId  file driveId
       */
      static void read(DriveId dId) {
        byte[] buf = null;
        if (mGAC != null && mGAC.isConnected() && dId != null) {
          DriveFile df = Drive.DriveApi.getFile(mGAC, dId);
          df.open(mGAC, DriveFile.MODE_READ_ONLY, null)
                                   .setResultCallback(new ResultCallback<DriveContentsResult>() {
            @Override
            public void onResult(DriveContentsResult rslt) {
              if ((rslt != null) && rslt.getStatus().isSuccess()) {
                DriveContents cont = rslt.getDriveContents();
                byte[] buf = UT.is2Bytes(cont.getInputStream());
                int size = buf.length;
                cont.discard(mGAC);    // or cont.commit();  they are equiv if READONLY
              }
            }
          });
        }
      }
    

    4/ 检查您下载的字节缓冲区的大小/状态/内容。您也可以将其写回数据库文件。

    这些步骤应该让您更接近解决您的错误。

    祝你好运

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-02-18
      • 2017-06-24
      • 1970-01-01
      • 2013-02-07
      • 2010-10-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多