我做了一项活动和一项服务。刚刚获得授权的活动工作正常,但当我尝试在服务中使用相同的帐户列出文件时它不起作用。
这是 mainactivity
public class MainActivity extends Activity {
GoogleAccountCredential mCredential;
private TextView mOutputText;
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 };
/**
* Create the main activity.
* @param savedInstanceState previously saved instance data.
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LinearLayout activityLayout = new LinearLayout(this);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT);
activityLayout.setLayoutParams(lp);
activityLayout.setOrientation(LinearLayout.VERTICAL);
activityLayout.setPadding(16, 16, 16, 16);
ViewGroup.LayoutParams tlp = new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
mOutputText = new TextView(this);
mOutputText.setLayoutParams(tlp);
mOutputText.setPadding(16, 16, 16, 16);
mOutputText.setVerticalScrollBarEnabled(true);
mOutputText.setMovementMethod(new ScrollingMovementMethod());
activityLayout.addView(mOutputText);
mProgress = new ProgressDialog(this);
mProgress.setMessage("Calling Drive API ...");
mOutputText.setText("hi");
setContentView(activityLayout);
// Initialize credentials and service object.
mCredential = GoogleAccountCredential.usingOAuth2(
getApplicationContext(), Arrays.asList(SCOPES))
.setBackOff(new ExponentialBackOff())
.setSelectedAccountName((null));
}
/**
* Called whenever this activity is pushed to the foreground, such as after
* a call to onCreate().
*/
@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 =
PreferenceManager.getDefaultSharedPreferences(this);
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);
if (GooglePlayServicesUtil.isUserRecoverableError(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(
connectionStatusCode,
MainActivity.this,
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("Drive API Android Quickstart")
.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()
.setMaxResults(10)
.execute();
List<File> files = result.getItems();
if (files != null) {
for (File file : files) {
fileInfo.add(String.format("%s (%s)\n",
file.getTitle(), file.getId()));
}
}
return fileInfo;
}
@Override
protected void onPreExecute() {
mOutputText.setText("");
mProgress.show();
}
@Override
protected void onPostExecute(List<String> output) {
mProgress.hide();
if(mCredential.getSelectedAccountName()!=null){
sendBroadcast(new Intent("account").putExtra("account",mCredential.getSelectedAccountName()));
finish();}
}
@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(),
MainActivity.REQUEST_AUTHORIZATION);
} else {
mOutputText.setText("The following error occurred:\n"
+ mLastError.getMessage());
}
} else {
mOutputText.setText("Request cancelled.");
}
}
}
}
这是必需的
服务代码
void initialize(String id){
account=id;
mCredential = GoogleAccountCredential.usingOAuth2(
this, Arrays.asList(SCOPES))
.setBackOff(new ExponentialBackOff())
.setSelectedAccountName(id);
HttpTransport transport = AndroidHttp.newCompatibleTransport();
JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
mService = new com.google.api.services.drive.Drive.Builder(
transport, jsonFactory, mCredential)
.setApplicationName("Drive API Android Quickstart")
.build();
}
public void listRoot(final com.google.api.services.drive.Drive mService, final listReturn listReturn) {
final ArrayList<com.google.api.services.drive.model.File> files = new ArrayList<>();
if (asyncTask != null && asyncTask.getStatus() == AsyncTask.Status.RUNNING)
asyncTask.cancel(true);
asyncTask = new AsyncTask<Void, Integer, Void>() {
Exception e=null;
@Override
public void onProgressUpdate(Integer... v){
if(v!=null && v[0]==1 && e!=null)listReturn.throwError(e);
else listReturn.list(files);
}
@Override
protected Void doInBackground(Void... voids) {
try {
String pg = "";
for (; ; ) {
Drive.Files.List lst = mService
.files()
.list()
.setFields(mFolderFields)
.setMaxResults(100);
if (!pg.equals(""))
lst.setPageToken(pg);
FileList fl;
try {
fl = lst.execute();
} catch (Exception e1) {
fl=null;
e1.printStackTrace();
}
if (fl.size() == 0)
break;
for (com.google.api.services.drive.model.File file : fl.getItems()) {
if (files.contains(file))
continue;
else if (isRoot(file)) {
files.add(file);
}
}
if (pg.equals(fl.getNextPageToken()))
break;
pg = fl.getNextPageToken();
if (pg == null || pg.equals(""))
break;
}
publishProgress(0);
} catch (Exception e) {
this.e=e;
publishProgress(1);
}
return null;
}
}.execute();
}
错误排在第
行fl=lst.execute();
编辑 - 错误日志
com.google.api.client.googleapis.extensions.android.gms.auth.UserRecoverableAuthIOException
12-18 23:35:18.677 12181-12707/com.amaze.filemanager.driveplugin W/System.err: at com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential$RequestHandler.intercept(GoogleAccountCredential.java:284)
12-18 23:35:18.677 12181-12707/com.amaze.filemanager.driveplugin W/System.err: at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:859)
12-18 23:35:18.677 12181-12707/com.amaze.filemanager.driveplugin W/System.err: at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:419)
12-18 23:35:18.677 12181-12707/com.amaze.filemanager.driveplugin W/System.err: at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:352)
12-18 23:35:18.677 12181-12707/com.amaze.filemanager.driveplugin W/System.err: at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:469)
12-18 23:35:18.677 12181-12707/com.amaze.filemanager.driveplugin W/System.err: at com.amaze.filemanager.driveplugin.DriveUtil$2.doInBackground(DriveUtil.java:119)
12-18 23:35:18.677 12181-12707/com.amaze.filemanager.driveplugin W/System.err: at com.amaze.filemanager.driveplugin.DriveUtil$2.doInBackground(DriveUtil.java:97)
12-18 23:35:18.677 12181-12707/com.amaze.filemanager.driveplugin W/System.err: at android.os.AsyncTask$2.call(AsyncTask.java:292)
12-18 23:35:18.677 12181-12707/com.amaze.filemanager.driveplugin W/System.err: at java.util.concurrent.FutureTask.run(FutureTask.java:237)
12-18 23:35:18.677 12181-12707/com.amaze.filemanager.driveplugin W/System.err: at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
12-18 23:35:18.677 12181-12707/com.amaze.filemanager.driveplugin W/System.err: Caused by: com.google.android.gms.auth.UserRecoverableAuthException: NeedPermission
12-18 23:35:18.687 12181-12707/com.amaze.filemanager.driveplugin W/System.err: at com.google.android.gms.auth.GoogleAuthUtil.zza(Unknown Source)
12-18 23:35:18.687 12181-12707/com.amaze.filemanager.driveplugin W/System.err: at com.google.android.gms.auth.GoogleAuthUtil.getToken(Unknown Source)
答案 0 :(得分:0)
此答案是对您的电子邮件的直接反应,指的是RESTDemo Github项目。引用:
我检查了你将活动对象传递给的实现 在rest.java中初始化驱动器api。我处在一种我不能解决的境地 发送一个活动对象到这个类。但我有一个活动要获得 authorization.Is有任何方法重新初始化这些驱动对象 没有使用活动对象,因为我已经获得一次授权?
我不得不承认我没有时间分析你问题中的所有代码,所以我会尝试专注于REST单例类。如你所见:
private static com.google.api.services.drive.Drive mGOOSvc;
...
static void init(Activity ctx){
mGOOSvc = new Drive.Builder(
AndroidHttp.newCompatibleTransport(),
new GsonFactory(),
GoogleAccountCredential.usingOAuth2(
ctx, // or ctx.getApplicationContext(),
Collections.singletonList(DriveScopes.DRIVE)
)
).build();
}
需要GoogleAccountCredential
的活动上下文(除了应用程序上下文之外)。这将是一次性初始化,只要您的应用程序还活着,您就可以使用静态mGOOSvc
。
但是,如果execute()
失败,还需要活动上下文才能解析UserRecoverableAuthIOException
。此异常通过startActivityForResult((((UserRecoverableAuthIOException)ex).getIntent()),...)
以及后续onActivityResult()
解决。此错误可能随时发生,因为授权可以从外部撤消(http://drive.google.com&gt;设置&gt;管理应用&gt; ...&gt;从驱动器断开连接)。
结论是,如果您决定忽略重新发生UserRecoverableAuthIOException
的可能性(您忽略此异常或自己处理),您可以一次性逃脱 - 只需致电 init()
。请注意,这正是REST类所做的,它只调用connect()
方法一次并忽略后续的execute()错误。请记住,REST是一个单例,只要静态mGOOSvc
处于活动状态,您就可以从“活动”或“服务”中解决它。
还有另一种情况需要再次呼叫init()
。这是在REQ_ACCPICK路径here中看到的帐户切换的情况。对于新用户,您的应用肯定需要新的mGOOSvc
(如果尚未授权,则需要新的授权)。
所以,你可以抢夺REST class,然后将其插入你的代码(非ui线程调用)。如果您不处理多个用户,也可以删除.setSelectedAccountName(email)
。
祝你好运