Android - GoogleApiClient 实例在 IntentService 中的 .connect() 和 onConnected() 之间丢失

Posted

技术标签:

【中文标题】Android - GoogleApiClient 实例在 IntentService 中的 .connect() 和 onConnected() 之间丢失【英文标题】:Android - GoogleApiClient instance lost between .connect() and onConnected() in IntentService 【发布时间】:2015-06-25 21:30:29 【问题描述】:

我正在尝试从由 GPS 启用状态的更改触发的 IntentService 管理开始和停止位置更新(以及其他连接的操作)。问题出现是因为 GoogleApiClient 上的 .connect() 方法异步运行,这导致服务终止。在收到 onConnected() 的回调时,静态全局变量 mGoogleApiClient 已被擦除。对于 removeLocationUpdates() 我得到:

java.lang.NullPointerException: GoogleApiClient must not be null

对于 requestLocationUpdates() 我得到:

java.lang.IllegalStateException: GoogleApiClient is not connected yet.

在 IntentService 的死亡和重生之间保留 GoogleApiClient 实例(request 和 remove 方法的必需参数)的正确方法是什么?或者,如果这是错误的问题,那么完成我想要做的事情的正确方法是什么?

编辑(2015 年 4 月 19 日): 以下是相关的代码部分...

来自我的类​​,它扩展了监听 GPS 事件的 WakefulBroadcastReceiver:

public void onReceive(Context context, Intent intent) 
    // If user enables or disables GPS
    if(intent.getAction().equals(LocationManager.MODE_CHANGED_ACTION) || intent.getAction().equals(LocationManager.PROVIDERS_CHANGED_ACTION)) 
        Intent mIntent = new Intent(context, ActivationIntentService.class);
        mIntent.putExtra("enabled", isGPSEnabled(context));
        startWakefulService(context, mIntent);
    

来自接收从 startWakefulService 传递的意图的 ActivationIntentService 类:

@Override
protected void onHandleIntent(Intent intent) 
    if (intent != null) 
        this.intent = intent;
        if(intent.hasExtra("enabled")) 
            if(intent.getBooleanExtra("enabled", false)) 
                buildGoogleApiClient();
            
            else 
                stopUpdates();
            
        
    


protected synchronized void buildGoogleApiClient() 
    mGoogleApiClient = new GoogleApiClient.Builder(this)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .addApi(LocationServices.API)
            .addApi(ActivityRecognition.API)
            .build();
    mGoogleApiClient.connect();


protected LocationRequest getLocationRequest() 
    LocationRequest mLocationRequest = new LocationRequest();
    mLocationRequest.setInterval(5000);
    mLocationRequest.setFastestInterval(1000);
    mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    return mLocationRequest;


@Override
public void onConnected(Bundle bundle) 
    startLocationUpdates();
    startActivityRecognitionUpdates();
    ActivationReceiver.completeWakefulIntent(intent);


public void stopUpdates() 
    PendingIntent locationPendingIntent = PendingIntent.getService(this, 1, new Intent(this, LocationIntentService.class), PendingIntent.FLAG_UPDATE_CURRENT);
    LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient,locationPendingIntent);
    PendingIntent activityRecognitionPendingIntent = PendingIntent.getService(this, 2, new Intent(this, ActivityRecognitionIntentService.class), PendingIntent.FLAG_UPDATE_CURRENT);
    ActivityRecognition.ActivityRecognitionApi.removeActivityUpdates(mGoogleApiClient,activityRecognitionPendingIntent);


public void startLocationUpdates() 
    PendingIntent locationPendingIntent = PendingIntent.getService(this, 1, new Intent(this, LocationIntentService.class), PendingIntent.FLAG_UPDATE_CURRENT);
    LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, getLocationRequest(), locationPendingIntent);


public void startActivityRecognitionUpdates() 
    PendingIntent activityRecognitionPendingIntent = PendingIntent.getService(this, 2, new Intent(this, ActivityRecognitionIntentService.class), PendingIntent.FLAG_UPDATE_CURRENT);
    ActivityRecognition.ActivityRecognitionApi.requestActivityUpdates(mGoogleApiClient, 5000, activityRecognitionPendingIntent);

【问题讨论】:

你能显示你的代码吗?我刚刚使用 Google Play Services Fused Location API 完成了一个项目。一个关键是,在调用requestLocationUpdates()removeLocationUpdates() 之前,我检查了GoogleApiClient 不为空,并且已连接。 我会添加代码的相关部分以便您看到它。但是,在这个阶段,检查客户端是否为空是没有意义的。在当前的设置中,它将始终为 null,因此我不需要检查它。 【参考方案1】:

我的第一个怀疑是正确的。我试图解决错误的问题。

通过跟踪几乎每个方法调用进行详细调试后,我意识到系统出于某种原因两次广播 GPS 模式更改,因此在第一个 onConnected 回调时已经实例化了第二个 GoogleApiClient(覆盖了第一个实例)从第一个 .connect() 调用中被触发。我的方法使用第二个(未连接的)客户端变量而不是第一个变量来启动或停止更新,这导致抛出异常。由于系统每次用户启用或禁用 GPS 时都会触发两个广播(对我来说似乎有点愚蠢),我在 BroadcastReceiver 中设置了一个标志,以便我可以忽略第二个。问题解决了。

【讨论】:

从那以后我找到了更好的方法。异步连接客户端的唯一原因是防止阻塞 UI 线程。但是,我一开始并没有在 UI 线程上执行此任务,因此没有理由担心这一点。为了让事情变得更简单,我切换到了名为blockingConnect() 的同步方法,最初我什至不知道它存在。此处方法说明:developers.google.com/android/reference/com/google/android/gms/…

以上是关于Android - GoogleApiClient 实例在 IntentService 中的 .connect() 和 onConnected() 之间丢失的主要内容,如果未能解决你的问题,请参考以下文章

GoogleApiClient 无法在 android studio 中连接

没有 GET_ACCOUNTS 权限的 Android 中的 Google Cloud Endpoints + GoogleApiClient

Android - GoogleApiClient 实例在 IntentService 中的 .connect() 和 onConnected() 之间丢失

为 Android 开发实现 GoogleApiClient Builder 时出错

使用 GoogleApiClient 进行 REST API 调用

地理围栏:GoogleApiClient 尚未连接