GoogleServices之GooglePlayService Accessing Google APIS(访
GoogleServices之GooglePlayService Accessing Google APIS( 访问 谷歌APIS) 官方 文档 翻译 AccessingGoogle APIs( 访问 谷歌 APIS) 当你想要连接到一个GoogleplayService库中提供的API,(比如:google,Games,或者drive),你需要创建一个 GoogleApiClient 的
GoogleServices之GooglePlayService Accessing Google APIS(访问谷歌APIS)官方文档翻译
AccessingGoogle APIs(访问谷歌APIS)
当你想要连接到一个GoogleplayService库中提供的API,(比如:google+,Games,或者drive),你需要创建一个GoogleApiClient
的实例。Google
API Client提供了一个公共的入口点给所有的谷歌服务以及在用户设备和每个谷歌服务之间管理网络连接。
这个指南示例你如何使用Google API Client:
1, 连接到一个或者多个Googleplayservice是异步的和失败处理。
2, 执行同步和异步API调用很多Google APIClient
注意:如果你已经有先有的应用使用子类GooglePlayServicesClient
连接到Googleplayservice,你应当尽可能迁移到GoogleApiClient
。
图1.一个插图显示了Google APS客户端是如何给连接和调用许多有效的Google Play services 提供接口,像 Games和Drive
Connecting toREST APIs
如果你想使用GoogleAPI,但不包括Google Play services,你可以适当的RESTAPI连接,但是你必须获取一个 OAuth 2.0的令牌。获取更多信息,请阅读:Authorizing with Google for REST APIs.
开始前,你必须先安装GooglePlay services库(版本号为15或者更高)为你的安卓SDK。如果你还没有准备好,请按照以下说明去做:Set Up Google Play Services SDK.
Start a Connection 开始连接
一旦你的项目引用Google Play services 库,你就可以使用GoogleApiClient.Builder
APIs在你的activity的oncreate方法里创建GoogleApiClient
实例。 GoogleApiClient.Builder
这个类提供的方法允许你指定你想使用的Google
APIs和你想得到的OAuth 2.0作用域。例如:这里是一个GoogleApiClient
使用Google
Drive service连接的实例。
GoogleApiClient mGoogleApiClient=new
GoogleApiClient.Builder(this)
.addApi(Drive.API)
.addScope(Drive.SCOPE_FILE)
.build();
你可以通过追加addApi()
和 addScope()
.添加多个APIS和多个scopes给相同的 GoogleApiClient
。
重点:为了避免客户端在没有安装Android Wear app的设备上连接错误,请使用一个单独的 GoogleApiClient
实例仅仅访问 Wearable
API。获取更多的信息,请看:Access
the Wearable API
在开始连接之前你要调用GoogleApiClient
的connect()
方法,你必须为回调接口 ConnectionCallbacks
and OnConnectionFailedListener
指定一个实现。当连接Google
Play services成功,失败或者暂停时这些接口会接受异步方法connect()
的回调。
例如:这里是一个实现了回调接口并且将他们添加到GoogleAPI客户端的activity
import gms.common.api.*;
import gms.drive.*;
import android.support.v4.app.FragmentActivity;
public classMyActivityextendsFragmentActivity
implements
ConnectionCallbacks,
OnConnectionFailedListener {
private GoogleApiClient mGoogleApiClient;
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
// Create a GoogleApiClient instance
mGoogleApiClient =
new GoogleApiClient.Builder(this)
.addApi(Drive.API)
.addScope(Drive.SCOPE_FILE)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
...
}
@Override
public void onConnected(Bundle connectionHint){
// Connected to Google Play services!
// The good stuff goes here.
}
@Override
public void onConnectionSuspended(int cause){
// The connection has been interrupted.
// Disable any UI components that depend on Google APIs
// until onConnected() is called.
}
@Override
public void onConnectionFailed(ConnectionResult result){
// This callback is important for handling errors that
// may occur while attempting to connect with Google.
//
// More about this in the next div.
...
}
}
定义了回调接口,你将准备调用connect()
. 为了优雅的管理连接的生命周期,你应该调用connect()
. 在activity的onStart()方法(除非你想晚一点连接)然后调用disconnect()
在onStop()方法中。例如:
@Override
protected void onStart(){
super.onStart();
if (!mResolvingError){ // more about this later
mGoogleApiClient.connect();
}
}
@Override
protected void onStop(){
mGoogleApiClient.disconnect();
super.onStop();
}
但是,如果您运行这段代码时,很有可能会失败,应用程序将接收调用onConnectionFailed()并发生SIGN_IN_REQUIRED错误,因为没有指定的用户帐户,下一节将展示如何处理这个错误等等。
Handleconnection failures(处理连接失败)
当你接收回调调用onConnectionFailed()
,你应该调用ConnectionResult
对象提供的 hasResolution()
方法。如果返回true,你可以请求用户立即采取行动通过调用ConnectionResult对象的startResolutionForResult()
方法处理错误。这个 startResolutionForResult()
方法的行为跟startActivityForResult()
比较相似,并启动适当的activity为用户解决错误(比如像一个选择账户的acticity)
如果hasResolution()
返回false,你应该通过错误代码调用 GooglePlayServicesUtil.getErrorDialog()
,它会通过GooglePlayServices适当的错误给你返回一个dialog.
这个对话框 提供了一个简单的错误解释信息,但他也有肯呢过提供一个action去启动一个activity去解决错误(比如当用户需要安装新版本的GoogleplayService)
比如,你应该像这样调用 onConnectionFailed()
public
class MyActivity
extends FragmentActivity
implements
ConnectionCallbacks,
OnConnectionFailedListener {
// Requestcode to use when launching the resolution activity
private staticfinalint REQUEST_RESOLVE_ERROR=1001;
// Uniquetag for the error dialog fragment
private staticfinalString DIALOG_ERROR="dialog_error";
// Bool totrack whether the app is already resolving an error
private boolean mResolvingError=false;
...
@Override
public void onConnectionFailed(ConnectionResult result){
if (mResolvingError){
// Already attempting to resolve an error.
//如果正在解决这个错误,什么也不做
return;
} elseif(result.hasResolution()){
try {
mResolvingError =
true;
result.startResolutionForResult(this, REQUEST_RESOLVE_ERROR);
} catch(SendIntentException e){
// There was an error with theresolution intent. Try again.
mGoogleApiClient.connect();
}
} else{
// Show dialog usingGooglePlayServicesUtil.getErrorDialog()
showErrorDialog(result.getErrorCode());
mResolvingError =
true;
}
}
// The restof this code is all about building the error dialog
/* Creates adialog for an error message */
private void showErrorDialog(int errorCode){
// Create a fragment for the error dialog
ErrorDialogFragment dialogFragment
= new ErrorDialogFragment();
// Pass the error that should be displayed
Bundle args
= new Bundle();
args.putInt(DIALOG_ERROR, errorCode);
dialogFragment.setArguments(args);
dialogFragment.show(getSupportFragmentManager(),"errordialog");
}
/* Calledfrom ErrorDialogFragment when the dialog is dismissed. */
public void onDialogDismissed(){
mResolvingError =
false;
}
/* Afragment to display an error dialog */
public staticclassErrorDialogFragmentextendsDialogFragment{
public ErrorDialogFragment(){}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState){
// Get the error code and retrieve theappropriate dialog
int errorCode
= this.getArguments().getInt(DIALOG_ERROR);
return
GooglePlayServicesUtil.getErrorDialog(errorCode,
this.getActivity(), REQUEST_RESOLVE_ERROR);
}
@Override
public void onDismiss(DialogInterface dialog){
((MainActivity)getActivity()).onDialogDismissed();
}
}
}
一旦用户通过提供的 startResolutionForResult()
orGooglePlayServicesUtil.getErrorDialog()
完成解决,你的activity会在onActivityResult()方法里接受处理结果码RESULT_OK
。你可以继续调用connect()
比如:
@Override
protected void onActivityResult(int requestCode,int
resultCode,Intent data){
if (requestCode== REQUEST_RESOLVE_ERROR){
mResolvingError =
false;
if (resultCode== RESULT_OK){
// Make sure the app is not alreadyconnected or attempting to connect
if (!mGoogleApiClient.isConnecting()&&
!mGoogleApiClient.isConnected()){
mGoogleApiClient.connect();
}
}
}
}
在上面的代码中,你可能注意到布尔变量mResolvingError。他追踪应用状态当用户正在解决错误时避免重复尝试解决相同的问题。例如,当选择用户的对话框正在展现解决SIGN_IN_REQUIRED
这个错误,用户有可能旋转屏幕。就会再次调用OnStart()重新展现你的activity,这个时候再次调用 connect()
。就会有一次调用startResolutionForResult()
返回相同的结果并创建有一个账户选择对话框展现在已存在的对话框前面。
这个布尔值会有效的在activity切换时被保存起来,下一节将做进一步解释。
Maintainstate while resolving an error
解决错误并维护状态
为了避免之前尝试解决错误时又执行 onConnectionFailed()
中的代码,你需要保留一个布尔变量来跟踪你的应用当前是否在解决这个问题。
上面的代码示例,你应该在每次调用 startResolutionForResult()
或者从GooglePlayServicesUtil.getErrorDialog()
得到一个显示的对话框都要设置一个布尔值为true.知道你在onActivityResult()方法中接收到处理结果为 RESULT_OK
时再次将布尔值设置为false.
为保持布尔值在acticity重启时不会变化,应该将布尔值保存在onSaveInstanceState()
:中
private
static final
String STATE_RESOLVING_ERROR =
"resolving_error";
@Override
protected void onSaveInstanceState(Bundle outState){
super.onSaveInstanceState(outState);
outState.putBoolean(STATE_RESOLVING_ERROR, mResolvingError);
}
然后在oncreat()中恢复保存的状态:
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
...
mResolvingError = savedInstanceState
!= null
&& savedInstanceState.getBoolean(STATE_RESOLVING_ERROR,false);
}
现在你可以安全的运行你的应用并连接到googleplayservice.如何使用 GoogleApiClient
去执行读取和写入请求 Google
Play services,下一节讨论:
Accessthe Wearable API(方位穿戴API)
在没有安装Android Wear app的设备上,连接请求包含 Wearable
API 会发生错误,错误码为API_UNAVAILABLE
。如果你的应用除了访问其他的Google
APIs 还要访问Wearable
API ,使用一个单独的GoogleApiClient
实例去访问Wearable
API。这个方法使您在不用搭配穿戴设备上能够访问其他的Google
APIs。
当你使用单独的GoogleApiClient
实例仅仅去访问Wearable
API,你要确定Android Wear
app在设备上是否已经安装。
// Connection failed listener method for a client thatonly
// requestsaccess to the Wearable API
@Override
public void onConnectionFailed(ConnectionResult result){
if (result.getErrorCode()==ConnectionResult.API_UNAVAILABLE){
// The Android Wear app is not installed
}
...
}
Communicate with Google Services
与谷歌服务通信
一旦连接,你的客户端就能使用特定的服务APIS为你的应用授权读写调用。按照特定的API和范围你添加你的 GoogleApiClient
实例。
注意:之前调用特定的谷歌服务,你可能首先需要在谷歌开发者控制台注册你的APP.特定的说明请参考适合你所用的API入门指南。诸如:Google Drive or Google+
当你使用Google API Client,执行读写请求的时候,他立即作为一个PendingResult
对象返回。这是一个表示请求的对象,他还没有交付给谷歌服务。
例如:这是一个从 Google Drive请求读取文件提供的PendingResult
对象,
Query query
= new Query.Builder()
.addFilter(Filters.eq(SearchableField.TITLE,
filename));
PendingResult result
= Drive.DriveApi.query(mGoogleApiClient,
query);
一旦你有了这个 PendingResult
,你可以继续使用同步或者异步请求。
Usingasynchronous calls 使用异步调用
为了使用异步请求,PendingResult
需要调用 setResultCallback()
并提供一个实现ResultCallback
接口的实现类。例如,这是执行异步请求:
private
void loadFile(String filename){
// Create aquery for a specific filename in Drive.
Query query =newQuery.Builder()
.addFilter(Filters.eq(SearchableField.TITLE,
filename))
.build();
// Invokethe query asynchronously with a callback method
Drive.DriveApi.query(mGoogleApiClient, query)
.setResultCallback(newResultCallbackDriveApi.MetadataBufferResult>(){
@Override
public void onResult(DriveApi.MetadataBufferResult
result) {
// Success! Handle the query result.
...
}
});
}
当你的应用在 onResult()
方法中收到一个Result
对象时,他将按照你使用的Api交付相应子类的实例,比如:DriveApi.MetadataBufferResult
.
Usingsynchronous calls 使用同步调用
如果你想要你的代码按照你严格定义的顺序运行,或许因为一个调用的结果是另一个需要的参数,你可以使用 PendingResult
.的 await()
方法进行同步请求。这个阻塞线程会交付一个你使用API的子类实例直到请求完成后返回结果。如:MetadataBufferResult
因为调用await()会阻塞线程知道结果返回,重点是你永远不要在你的UI线程中调用执行。所以你想执行同步请求Googleplayservices,你应该创建一个新的线程,比如使用AsyncTask执行这个请求。例如:这里是如何使用同步请求googlepalyservice访问相同的文件。
private
void loadFile(String filename){
new GetFileTask().execute(filename);
}
private classGetFileTaskextendsAsyncTaskString,Void,Void>
{
protected void doInBackground(String filename){
Query query
= new Query.Builder()
.addFilter(Filters.eq(SearchableField.TITLE,
filename))
.build();
// Invoke the query synchronously
DriveApi.MetadataBufferResult result=
Drive.DriveApi.query(mGoogleApiClient,
query).await();
// Continue doing other stuff synchronously
...
}
}
小提示:你也可以队列阅读请求而不用连接 Google Play services.。例如:不管Google API Client是否连接,执行一个方法从Google Drive读取文件,然后一旦确立了连接,就会执行读取请求并接收结果。然而,当你的Google API Client 没有连接的时候如果你调用他们进行写入请求将会发生错误。