使用 GDAA 创建/编辑/检索数据库文件(Google Drive Api for Android)

Create / Edit / Retrieve DB file with GDAA (Google Drive Api for Android)

有技术的朋友。

有人能帮我解决我的问题吗?我正在尝试使用 GDAA(Google Drive API for Android = https://developers.google.com/drive/android/appfolder)来备份和恢复我的数据库文件。不是 REST API。 我尝试使用他们的演示 类 从这里:https://github.com/googledrive/android-demos/,但没有积极的结果。

我通过身份验证成功并将我的数据库文件保存到 Google 驱动器中的应用程序文件夹中,但我无法编辑或检索此文件。我仍然只创建新文件和新文件。你能帮帮我吗?

我称之为编辑 activity:

public class EditContentsActivity extends BaseDemoActivity {

private static final String TAG = "EditContentsActivity";

@Override
public void onConnected(Bundle connectionHint) {
    super.onConnected(connectionHint);

    final ResultCallback<DriveIdResult> idCallback = new ResultCallback<DriveIdResult>() {
        @Override
        public void onResult(DriveIdResult result) {
            if (!result.getStatus().isSuccess()) {
                Intent intent = new Intent(getBaseContext(), CreateFileInAppFolderActivity.class);
                startActivity(intent);
                return;
            }

            DriveFile file = Drive.DriveApi.getFile(getGoogleApiClient(), result.getDriveId());
            new EditContentsAsyncTask(EditContentsActivity.this).execute(file);
        }
    };
    Drive.DriveApi.fetchDriveId(getGoogleApiClient(), EXISTING_FILE_ID)
            .setResultCallback(idCallback);
}

public class EditContentsAsyncTask extends ApiClientAsyncTask<DriveFile, Void, Boolean> {

    public EditContentsAsyncTask(Context context) {
        super(context);
    }

    @Override
    protected Boolean doInBackgroundConnected(DriveFile... args) {
        DriveFile file = args[0];
        try {
            DriveContentsResult driveContentsResult = file.open(
                    getGoogleApiClient(), DriveFile.MODE_WRITE_ONLY, null).await();
            if (!driveContentsResult.getStatus().isSuccess()) {
                return false;
            }
            DriveContents driveContents = driveContentsResult.getDriveContents();
            OutputStream outputStream = driveContents.getOutputStream();

            String dbpath = "/data/" + "com.myapp" + "/databases/" + DatabaseHelper.DB_NAME;
            FileInputStream fis = new FileInputStream(Environment.getDataDirectory() + dbpath);
            byte[] buffer = new byte[1024];
            int length;
            while ((length = fis.read(buffer)) > 0) {
                outputStream.write(buffer, 0, length);
            }

            com.google.android.gms.common.api.Status status =
                    driveContents.commit(getGoogleApiClient(), null).await();

            outputStream.flush();
            outputStream.close();
            fis.close();

            return status.getStatus().isSuccess();
        } catch (IOException e) {
            Log.e(TAG, "IOException while appending to the output stream", e);
        }
        return false;
    }

    @Override
    protected void onPostExecute(Boolean result) {
        if (!result) {
            showMessage("Error while editing contents");
            return;
        }
        showMessage("Successfully edited contents");
    }
}

如果我得到 "!result.getStatus().isSuccess()" 我想调用 Create Activity:

public class CreateFileInAppFolderActivity extends BaseDemoActivity {

@Override
public void onConnected(Bundle connectionHint) {
    super.onConnected(connectionHint);
    // create new contents resource
    Drive.DriveApi.newDriveContents(getGoogleApiClient()).setResultCallback(driveContentsCallback);
}

final private ResultCallback<DriveContentsResult> driveContentsCallback =
        new ResultCallback<DriveContentsResult>() {
            @Override
            public void onResult(DriveContentsResult result) {
                if (!result.getStatus().isSuccess()) {
                    showMessage("Error while trying to create new file contents");
                    return;
                }

                String mimeType = MimeTypeMap.getSingleton().getExtensionFromMimeType("db");
                MetadataChangeSet changeSet = new MetadataChangeSet.Builder()
                        .setTitle(EXISTING_FILE_ID)
                        .setMimeType(mimeType)
                        .build();
                OutputStream os  = result.getDriveContents().getOutputStream();
               try {
                    String dbpath = "/data/" + "com.myapp" + "/databases/" + DatabaseHelper.DB_NAME;
                    FileInputStream fis = new FileInputStream(Environment.getDataDirectory() + dbpath);
                    byte[] buffer = new byte[1024];
                    int length;
                    while ((length = fis.read(buffer)) > 0) {
                        os.write(buffer, 0, length);
                    }
                   Drive.DriveApi.getAppFolder(getGoogleApiClient())
                           .createFile(getGoogleApiClient(), changeSet, result.getDriveContents())
                           .setResultCallback(fileCallback);

                   os.flush();
                   os.close();
                   fis.close();

                   throw new IOException("");
                } catch (IOException e) {
                    Log.e("IOExceptions=", e.toString());
                   Drive.DriveApi.getAppFolder(getGoogleApiClient()).delete(getGoogleApiClient());
                }

            }
        };

final private ResultCallback<DriveFileResult> fileCallback = new
        ResultCallback<DriveFileResult>() {
            @Override
            public void onResult(DriveFileResult result) {
                if (!result.getStatus().isSuccess()) {
                    showMessage("Error while trying to create the file");
                    return;
                }
                showMessage("Created a file in App Folder: "
                        + result.getDriveFile().getDriveId());
            }
        };

全部扩展此基础演示Activity:

public abstract class BaseDemoActivity extends Activity implements
    GoogleApiClient.ConnectionCallbacks,
    GoogleApiClient.OnConnectionFailedListener {

private static final String TAG = "BaseDriveActivity";

/**
 * DriveId of an existing folder to be used as a parent folder in
 * folder operations samples.
 */
public static final String EXISTING_FOLDER_ID = "0B2EEtIjPUdX6MERsWlYxN3J6RU0";

/**
 * DriveId of an existing file to be used in file operation samples..
 */
public static final String EXISTING_FILE_ID = "0ByfSjdPVs9MZTHBmMVdSeWxaNTg";

/**
 * Extra for account name.
 */
protected static final String EXTRA_ACCOUNT_NAME = "account_name";

/**
 * Request code for auto Google Play Services error resolution.
 */
protected static final int REQUEST_CODE_RESOLUTION = 1;

/**
 * Next available request code.
 */
protected static final int NEXT_AVAILABLE_REQUEST_CODE = 2;

/**
 * Google API client.
 */
private GoogleApiClient mGoogleApiClient;

/**
 * Called when activity gets visible. A connection to Drive services need to
 * be initiated as soon as the activity is visible. Registers
 * {@code ConnectionCallbacks} and {@code OnConnectionFailedListener} on the
 * activities itself.
 */
@Override
protected void onResume() {
    super.onResume();
    if (mGoogleApiClient == null) {
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addApi(Drive.API)
                .addScope(Drive.SCOPE_FILE)
                .addScope(Drive.SCOPE_APPFOLDER) // required for App Folder sample
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .build();
    }
    mGoogleApiClient.connect();
}

/**
 * Handles resolution callbacks.
 */
@Override
protected void onActivityResult(int requestCode, int resultCode,
        Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == REQUEST_CODE_RESOLUTION && resultCode == RESULT_OK) {
        mGoogleApiClient.connect();
    }
}

/**
 * Called when activity gets invisible. Connection to Drive service needs to
 * be disconnected as soon as an activity is invisible.
 */
@Override
protected void onPause() {
    if (mGoogleApiClient != null) {
        mGoogleApiClient.disconnect();
    }
    super.onPause();
}

/**
 * Called when {@code mGoogleApiClient} is connected.
 */
@Override
public void onConnected(Bundle connectionHint) {
    Log.i(TAG, "GoogleApiClient connected");
}

/**
 * Called when {@code mGoogleApiClient} is disconnected.
 */
@Override
public void onConnectionSuspended(int cause) {
    Log.i(TAG, "GoogleApiClient connection suspended");
}

/**
 * Called when {@code mGoogleApiClient} is trying to connect but failed.
 * Handle {@code result.getResolution()} if there is a resolution is
 * available.
 */
@Override
public void onConnectionFailed(ConnectionResult result) {
    Log.i(TAG, "GoogleApiClient connection failed: " + result.toString());
    if (!result.hasResolution()) {
        // show the localized error dialog.
        GooglePlayServicesUtil.getErrorDialog(result.getErrorCode(), this, 0).show();
        return;
    }
    try {
        result.startResolutionForResult(this, REQUEST_CODE_RESOLUTION);
    } catch (SendIntentException e) {
        Log.e(TAG, "Exception while starting resolution activity", e);
    }
}

/**
 * Shows a toast message.
 */
public void showMessage(String message) {
    Toast.makeText(this, message, Toast.LENGTH_LONG).show();
}

/**
 * Getter for the {@code GoogleApiClient}.
 */
public GoogleApiClient getGoogleApiClient() {
  return mGoogleApiClient;
}

检索 Activity:

public class RetrieveContentsActivity extends BaseDemoActivity {

private static final String TAG = "RetrieveContentsActivity";

@Override
public void onConnected(Bundle connectionHint) {
    super.onConnected(connectionHint);
    Drive.DriveApi.fetchDriveId(getGoogleApiClient(), EXISTING_FILE_ID)
            .setResultCallback(idCallback);
}

final private ResultCallback<DriveIdResult> idCallback = new ResultCallback<DriveIdResult>() {
    @Override
    public void onResult(DriveIdResult result) {
        new RetrieveDriveFileContentsAsyncTask(
                RetrieveContentsActivity.this).execute(result.getDriveId());
    }
};

final private class RetrieveDriveFileContentsAsyncTask
        extends ApiClientAsyncTask<DriveId, Boolean, String> {

    public RetrieveDriveFileContentsAsyncTask(Context context) {
        super(context);
    }

    @Override
    protected String doInBackgroundConnected(DriveId... params) {
        String contents = null;
        DriveFile file = Drive.DriveApi.getFile(getGoogleApiClient(), params[0]);
        DriveContentsResult driveContentsResult =
                file.open(getGoogleApiClient(), DriveFile.MODE_READ_ONLY, null).await();
        if (!driveContentsResult.getStatus().isSuccess()) {
            return null;
        }
        DriveContents driveContents = driveContentsResult.getDriveContents();
        BufferedReader reader = new BufferedReader(
                new InputStreamReader(driveContents.getInputStream()));
        StringBuilder builder = new StringBuilder();
        String line;
        try {
            while ((line = reader.readLine()) != null) {
                builder.append(line);
            }
            contents = builder.toString();
        } catch (IOException e) {
            Log.e(TAG, "IOException while reading from the stream", e);
        }

        driveContents.discard(getGoogleApiClient());
        return contents;
    }

    @Override
    protected void onPostExecute(String result) {
        super.onPostExecute(result);
        if (result == null) {
            showMessage("Error while reading from the file");
            return;
        }
        showMessage("File contents: " + result);
    }
}

还有验证码:

public abstract class ApiClientAsyncTask<Params, Progress, Result>
    extends AsyncTask<Params, Progress, Result> {

private GoogleApiClient mClient;

public ApiClientAsyncTask(Context context) {
    GoogleApiClient.Builder builder = new GoogleApiClient.Builder(context)
            .addApi(Drive.API)
            .addScope(Drive.SCOPE_FILE);
    mClient = builder.build();
}

@Override
protected final Result doInBackground(Params... params) {
    Log.d("TAG", "in background");
    final CountDownLatch latch = new CountDownLatch(1);
    mClient.registerConnectionCallbacks(new ConnectionCallbacks() {
        @Override
        public void onConnectionSuspended(int cause) {
        }

        @Override
        public void onConnected(Bundle arg0) {
            latch.countDown();
        }
    });
    mClient.registerConnectionFailedListener(new OnConnectionFailedListener() {
        @Override
        public void onConnectionFailed(ConnectionResult arg0) {
            latch.countDown();
        }
    });
    mClient.connect();
    try {
        latch.await();
    } catch (InterruptedException e) {
        return null;
    }
    if (!mClient.isConnected()) {
        return null;
    }
    try {
        return doInBackgroundConnected(params);
    } finally {
        mClient.disconnect();
    }
}

/**
 * Override this method to perform a computation on a background thread, while the client is
 * connected.
 */
protected abstract Result doInBackgroundConnected(Params... params);

/**
 * Gets the GoogleApliClient owned by this async task.
 */
protected GoogleApiClient getGoogleApiClient() {
    return mClient;
}

请问您知道这个演示的正确方法吗?

不幸的是,我没有时间深入研究上面的所有代码,但我可以(至少)给你一些一般性的指导。

首先,您提到的演示确实有效,我已经对其进行了测试并运行ning。但是由于演示几乎涵盖了任何场景,因此很难追踪您可能的错误。

现在,指针:

  1. 当您创建一个文件时,您会得到一个 DriveId。
  2. 您使用该 DriveId 检索文件
  3. 文件内容为二进制字节数组或流

我已经为 GDAA 整理了一个基本的 CRUD 包装器,您可以找到它 here

GDAA.java class 中,您会找到“createFile()”方法。我想你必须给它你在上面的 'fileCallback' 中收到的 'result.getDriveFile().getDriveId()' (作为 parent)。内容作为标准传入 java.io.File

该方法 returns DriveId(采用字符串形式,因此我可以轻松缓存它),您可以将该 DriveId 传递给 'read()' 方法,该方法将为您返回一个字节数组(流)。将它转储到 java.io.File 就大功告成了(不要忘记 运行 它 off-UI 线程,它们是阻塞方法)。

我建议先使用 Drive 的根目录(而不是应用程序文件夹)对其进行测试,这样您才能真正看到 drive.google.com

中的文件

祝你好运