![](/img/trans.png)
[英]Choose Account Screen for Google Drive API keeps repeating. Tried every other solution on here
[英]Infinite “Choose an account” loop when using Google Drive API
我正在嘗試設置一個Android應用,該應用可以使用Google Drive REST API概述中的指南來操縱存儲在我的Google Drive個人帳戶中的文件。
我遵循了示例代碼,以允許用戶連接到該帳戶,但是無論選擇帳戶名還是按下取消按鈕,“選擇帳戶”對話框都會反復出現。
我認為問題在於,即使在從帳戶選擇器對話框中選擇了帳戶名稱之后,在測試mCredential.getSelectedAccountName()
時, refreshResults()
方法仍會返回null。 但是不知道為什么會這樣或如何解決。 如果有經驗的人可以建議我,我將不勝感激。 謝謝。
我的代碼如下:
import android.accounts.AccountManager;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.AsyncTask;
import android.preference.PreferenceManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
import com.google.api.client.extensions.android.http.AndroidHttp;
import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential;
import com.google.api.client.googleapis.extensions.android.gms.auth.GooglePlayServicesAvailabilityIOException;
import com.google.api.client.googleapis.extensions.android.gms.auth.UserRecoverableAuthIOException;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.client.util.ExponentialBackOff;
import com.google.api.services.drive.DriveScopes;
import com.google.api.services.drive.model.File;
import com.google.api.services.drive.model.FileList;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class HomeActivity extends AppCompatActivity{
GoogleAccountCredential mCredential;
ProgressDialog mProgress;
static final int REQUEST_ACCOUNT_PICKER = 1000;
static final int REQUEST_AUTHORIZATION = 1001;
static final int REQUEST_GOOGLE_PLAY_SERVICES = 1002;
private static final String PREF_ACCOUNT_NAME = "accountName";
private static final String[] SCOPES = { DriveScopes.DRIVE_METADATA_READONLY };
public TextView mOutputText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Initialize credentials and service object.
SharedPreferences settings = getPreferences(Context.MODE_PRIVATE);
mCredential = GoogleAccountCredential.usingOAuth2(
getApplicationContext(), Arrays.asList(SCOPES))
.setBackOff(new ExponentialBackOff())
.setSelectedAccountName(settings.getString(PREF_ACCOUNT_NAME, null));
mProgress = new ProgressDialog(this);
mProgress.setMessage("Calling Drive API ...");
setContentView(R.layout.activity_home);
mOutputText = (TextView) findViewById(R.id.textStatus);
@Override
protected void onResume() {
super.onResume();
if (isGooglePlayServicesAvailable()) {
refreshResults();
} else {
mOutputText.setText("Google Play Services required: " +
"after installing, close and relaunch this app.");
}
}
/**
* Called when an activity launched here (specifically, AccountPicker
* and authorization) exits, giving you the requestCode you started it with,
* the resultCode it returned, and any additional data from it.
* @param requestCode code indicating which activity result is incoming.
* @param resultCode code indicating the result of the incoming
* activity result.
* @param data Intent (containing result data) returned by incoming
* activity result.
*/
@Override
protected void onActivityResult(
int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch(requestCode) {
case REQUEST_GOOGLE_PLAY_SERVICES:
if (resultCode != RESULT_OK) {
isGooglePlayServicesAvailable();
}
break;
case REQUEST_ACCOUNT_PICKER:
if (resultCode == RESULT_OK && data != null &&
data.getExtras() != null) {
String accountName =
data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
if (accountName != null) {
mCredential.setSelectedAccountName(accountName);
SharedPreferences settings =
getPreferences(Context.MODE_PRIVATE);
SharedPreferences.Editor editor = settings.edit();
editor.putString(PREF_ACCOUNT_NAME, accountName);
editor.apply();
}
} else if (resultCode == RESULT_CANCELED) {
mOutputText.setText("Account unspecified.");
}
break;
case REQUEST_AUTHORIZATION:
if (resultCode != RESULT_OK) {
chooseAccount();
}
break;
}
super.onActivityResult(requestCode, resultCode, data);
}
/**
* Attempt to get a set of data from the Drive API to display. If the
* email address isn't known yet, then call chooseAccount() method so the
* user can pick an account.
*/
private void refreshResults() {
if (mCredential.getSelectedAccountName() == null) {
chooseAccount();
} else {
if (isDeviceOnline()) {
new MakeRequestTask(mCredential).execute();
} else {
mOutputText.setText("No network connection available.");
}
}
}
/**
* Starts an activity in Google Play Services so the user can pick an
* account.
*/
private void chooseAccount() {
startActivityForResult(
mCredential.newChooseAccountIntent(), REQUEST_ACCOUNT_PICKER);
}
/**
* Checks whether the device currently has a network connection.
* @return true if the device has a network connection, false otherwise.
*/
private boolean isDeviceOnline() {
ConnectivityManager connMgr =
(ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
return (networkInfo != null && networkInfo.isConnected());
}
/**
* Check that Google Play services APK is installed and up to date. Will
* launch an error dialog for the user to update Google Play Services if
* possible.
* @return true if Google Play Services is available and up to
* date on this device; false otherwise.
*/
private boolean isGooglePlayServicesAvailable() {
final int connectionStatusCode =
//GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(this);
if (GoogleApiAvailability.getInstance().isUserResolvableError(connectionStatusCode)) {
showGooglePlayServicesAvailabilityErrorDialog(connectionStatusCode);
return false;
} else if (connectionStatusCode != ConnectionResult.SUCCESS ) {
return false;
}
return true;
}
/**
* Display an error dialog showing that Google Play Services is missing
* or out of date.
* @param connectionStatusCode code describing the presence (or lack of)
* Google Play Services on this device.
*/
void showGooglePlayServicesAvailabilityErrorDialog(
final int connectionStatusCode) {
//Dialog dialog = GooglePlayServicesUtil.getErrorDialog(
Dialog dialog = GoogleApiAvailability.getInstance().getErrorDialog(
HomeActivity.this,
connectionStatusCode,
REQUEST_GOOGLE_PLAY_SERVICES);
dialog.show();
}
/**
* An asynchronous task that handles the Drive API call.
* Placing the API calls in their own task ensures the UI stays responsive.
*/
private class MakeRequestTask extends AsyncTask<Void, Void, List<String>> {
private com.google.api.services.drive.Drive mService = null;
private Exception mLastError = null;
public MakeRequestTask(GoogleAccountCredential credential) {
HttpTransport transport = AndroidHttp.newCompatibleTransport();
JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
mService = new com.google.api.services.drive.Drive.Builder(
transport, jsonFactory, credential)
.setApplicationName("Media Vault")
.build();
}
/**
* Background task to call Drive API.
* @param params no parameters needed for this task.
*/
@Override
protected List<String> doInBackground(Void... params) {
try {
return getDataFromApi();
} catch (Exception e) {
mLastError = e;
cancel(true);
return null;
}
}
/**
* Fetch a list of up to 10 file names and IDs.
* @return List of Strings describing files, or an empty list if no files
* found.
* @throws IOException
*/
private List<String> getDataFromApi() throws IOException {
// Get a list of up to 10 files.
List<String> fileInfo = new ArrayList<String>();
FileList result = mService.files().list()
.setPageSize(10)
.setFields("nextPageToken, items(id, name)")
.execute();
List<File> files = result.getFiles();
if (files != null) {
for (File file : files) {
fileInfo.add(String.format("%s (%s)\n",
file.getName(), file.getId()));
}
}
return fileInfo;
}
@Override
protected void onPreExecute() {
mOutputText.setText("");
mProgress.show();
}
@Override
protected void onPostExecute(List<String> output) {
mProgress.hide();
if (output == null || output.size() == 0) {
mOutputText.setText("No results returned.");
} else {
output.add(0, "Data retrieved using the Drive API:");
mOutputText.setText(TextUtils.join("\n", output));
}
}
@Override
protected void onCancelled() {
mProgress.hide();
if (mLastError != null) {
if (mLastError instanceof GooglePlayServicesAvailabilityIOException) {
showGooglePlayServicesAvailabilityErrorDialog(
((GooglePlayServicesAvailabilityIOException) mLastError)
.getConnectionStatusCode());
} else if (mLastError instanceof UserRecoverableAuthIOException) {
startActivityForResult(
((UserRecoverableAuthIOException) mLastError).getIntent(),
HomeActivity.REQUEST_AUTHORIZATION);
} else {
mOutputText.setText("The following error occurred:\n"
+ mLastError.getMessage());
}
} else {
mOutputText.setText("Request cancelled.");
}
}
}
}
我遇到了完全相同的問題,在我的情況下,循環是由於我沒有為我的應用程序創建憑據而導致的。
有關詳細信息,請參見以下網址 : https : //developers.google.com/drive/android/get-started
您必須針對調試和生產環境都檢索SHA-1密鑰,然后按照指南中的說明將其添加到Google Developers Console的憑據中。
添加這些憑據后,循環立即停止。
我能想到的一件事是,如果未檢索到PREF_ACCOUNT_NAME
則setSelectedAccountName
的值將默認為null
,因此這可能會導致問題。
我可以看到的唯一區別是實例化了mCredential
。 嘗試檢查Android的授權請求 (使用GoogleApiClient
而不是GoogleAccountCredential
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.