我在生产中有一个应用程序,在调用经过身份验证的Cloud Endpoint时会收到大量的强制/关闭。最有说服力的信息是“java.lang.IllegalArgumentException:Service not registered:com.google.android.gms.internal.es@4481e6a8”。逻辑在95%的时间内正常工作。失败的堆栈跟踪如下:
java.lang.RuntimeException:执行时发生错误 doInBackground()在android.os.AsyncTask $ 3.done(AsyncTask.java:200)at at java.util.concurrent.FutureTask中$ Sync.innerSetException(FutureTask.java:273) at java.util.concurrent.FutureTask.setException(FutureTask.java:124) at java.util.concurrent.FutureTask $ Sync.innerRun(FutureTask.java:307) 在java.util.concurrent.FutureTask.run(FutureTask.java:137)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1068) 在 java.util.concurrent.ThreadPoolExecutor中的$ Worker.run(ThreadPoolExecutor.java:561) 在java.lang.Thread.run(Thread.java:1096)引起: java.lang.IllegalArgumentException:服务未注册: com.google.android.gms.internal.es@4481e6a8 at android.app.ActivityThread $ PackageInfo.forgetServiceDispatcher(ActivityThread.java:1074) 在android.app.ContextImpl.unbindService(ContextImpl.java:886)at android.content.ContextWrapper.unbindService(ContextWrapper.java:352) 在com.google.android.gms.auth.GoogleAuthUtil.java.lang.String 为gettoken(android.content.Context,java.lang.String中,java.lang.String中)(未知 来源)at java.util.concurrent.FutureTask $ Sync.innerRun(FutureTask.java:305)at at java.util.concurrent.FutureTask $ Sync.innerRun(FutureTask.java:305)at at java.util.concurrent.FutureTask $ Sync.innerRun(FutureTask.java:305)at at java.util.concurrent.FutureTask $ Sync.innerRun(FutureTask.java:305)at at com.google.android.gms.auth.GoogleAuthUtil.java.lang.String 为gettoken(android.content.Context,java.lang.String中,java.lang.String中)(未知 来源)at java.util.concurrent.FutureTask $ Sync.innerRun(FutureTask.java:305)at at java.util.concurrent.FutureTask $ Sync.innerRun(FutureTask.java:305)at at java.util.concurrent.FutureTask $ Sync.innerRun(FutureTask.java:305)at at java.util.concurrent.FutureTask $ Sync.innerRun(FutureTask.java:305)at at com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential.java.lang.String getToken()(SourceFile:192)at com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential $ RequestHandler.void 拦截(com.google.api.client.http.HttpRequest)(SourceFile:217)at at com.google.api.client.http.HttpRequest.com.google.api.client.http.HttpResponse 执行()(SourceFile:836)at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.com.google.api.client.http.HttpResponse executeUnparsed(boolean)(SourceFile:412)at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.com.google.api.client.http.HttpResponse executeUnparsed()(SourceFile:345)at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.java.lang.Object 执行()(SourceFile:463)at com.jdub.empiretracker.EmpireTrackerActivity $ QueryMarketStats.com.google.api.services.marketendpoint.model.Market doInBackground(com.google.api.services.marketendpoint.model.Market [])(的SourceFile:355) 在 com.jdub.empiretracker.EmpireTrackerActivity $ QueryMarketStats.java.lang.Object doInBackground(java.lang.Object [])(SourceFile:1)at android.os.AsyncTask $ 2.call(AsyncTask.java:185)at java.util.concurrent.FutureTask $ Sync.innerRun(FutureTask.java:305)... 还有4个
我的实施与Google样本非常一致。例如,我的Android活动使用AsyncTask进行调用,如下所示:
private class QueryMarketStats extends AsyncTask<com.google.api.services.marketendpoint.model.Market, com.google.api.services.marketendpoint.model.Market, com.google.api.services.marketendpoint.model.Market> {
/* (non-Javadoc)
* @see android.os.AsyncTask#doInBackground(Params[])
*/
@Override
protected com.google.api.services.marketendpoint.model.Market doInBackground(com.google.api.services.marketendpoint.model.Market...markets) {
com.google.api.services.marketendpoint.model.Market result = null;
try {
result = service.market().latest(state.getServerID()).execute();
}
catch (SSLException e) {
PrimeDataStore();
Log.d("app", e.getMessage(), e);
}
catch (GoogleAuthIOException e) {
Log.d("app", e.getMessage(), e);
}
catch (IOException e) {
Log.d("app", e.getMessage(), e);
}
return result;
}
/* (non-Javadoc)
* @see android.os.AsyncTask#onPostExecute(java.lang.Object)
*/
@Override
protected void onPostExecute(com.google.api.services.marketendpoint.model.Market result) {
// Process result...
}
}
给出错误的行是: result = service.market()。latest(state.getServerID())。execute();
我已经验证了getServerID()的参数返回的值是可以接受的。我的理论是,Google Play服务无法提供仍在验证的帐户。虽然我无法重现,但我相信当应用程序进入睡眠状态时可能会出现此问题。因此我确认了我的onResume()逻辑,如下所示:
@Override
protected void onResume() {
super.onResume();
checkPlayServices();
isInFront = true;
}
还有什么可能导致这种间歇性失败?这是一个已知的问题?
答案 0 :(得分:2)
代替更好的替代方案,我正在捕获异常并触发成功重试。无论间歇性问题导致服务在端点被调用的时间点没有注册,服务的未来调用都将正常工作。
解决方法代码
@Override
protected com.google.api.services.marketendpoint.model.Market doInBackground(com.google.api.services.marketendpoint.model.Market...markets) {
com.google.api.services.marketendpoint.model.Market result = null;
try {
result = service.market().latest(state.getServerID()).execute();
}
catch (SSLException e) {
PrimeDataStore();
Log(e);
}
catch (GoogleAuthIOException e) {
Log(e);
}
catch (IOException e) {
Log(e);
}
catch (IllegalArgumentException e) {
// This caused a lot of intermittent force/closes.
Log(e);
}
return result;
}
@Override
protected void onPostExecute(com.google.api.services.marketendpoint.model.Market result) {
DismissProgressDialogIfPresent();
com.google.api.services.marketendpoint.model.Market m = (com.google.api.services.marketendpoint.model.Market) result;
if( m == null)
{
// Verify the current activity is active
if( isInFront ) {
// Present a retry/cancel dialog
AlertDialog.Builder builder = new AlertDialog.Builder(EmpireTrackerActivity.this);
builder.setMessage("An error was encountered retrieving the latest market data.\n\nPlease verify you are connected to the Internet.");
builder.setPositiveButton("Retry", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
m_ProgressDlg = ProgressDialog.show(EmpireTrackerActivity.this, "Please wait...", "Retrieving data ...", true);
new QueryMarketStats().execute();
}
});
builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
AlertDialog alert = builder.create();
alert.show();
}
return;
}
// Process newly posted data
state.setMarketObj(m);
state.setIsInitialized(true);
state.WriteFile(EmpireTrackerActivity.this);
super.onPostExecute(result);
}
}