Android客户端中经过身份验证的Cloud Endpoint间歇性故障

时间:2013-06-09 17:25:50

标签: android google-cloud-endpoints google-play-services

我在生产中有一个应用程序,在调用经过身份验证的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;
}

还有什么可能导致这种间歇性失败?这是一个已知的问题?

1 个答案:

答案 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);
}       

}