"GoogleApiClient is not connected yet" IntentService 错误

"GoogleApiClient is not connected yet" error in IntentService

我正在创建一个应用程序,它使用 IntentService 中的 AlarmManagerGoogleAPIClient 的帮助下每 30 分钟检查一次用户的位置。

onHandleIntent() 在我的服务中触发时,我收到此错误:

FATAL EXCEPTION: IntentService[FindLocationService]
Process: ir.imanirt.remindmeathome, PID: 1382
java.lang.IllegalStateException: GoogleApiClient is not connected yet.
at com.google.android.gms.internal.zzqb.zzd(Unknown Source)
at com.google.android.gms.internal.zzqf.zzd(Unknown Source)
at com.google.android.gms.internal.zzqd.zzd(Unknown Source)
at com.google.android.gms.location.internal.zzd.requestLocationUpdates(Unknown Source)
at ir.imanirt.remindmeathome.FindLocationService.getCurrentLocation(FindLocationService.java:122)
at ir.imanirt.remindmeathome.FindLocationService.onHandleIntent(FindLocationService.java:105)
at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:66)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.os.HandlerThread.run(HandlerThread.java:61)

这是我的FindLocationService.javaclass:

import android.Manifest;
import android.app.AlarmManager;
import android.app.IntentService;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Bundle;
import android.os.SystemClock;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.NotificationCompat;
import android.util.Log;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;

public class FindLocationService extends IntentService {

    private static final String TAG = "FINDLOCATIONSERVICE";
    private static final int SERVICE_REQUEST_CODE = 101;
    private GoogleApiClient mClient;
    private NotificationCompat.Builder mNotificationBuilder;

    public FindLocationService() {
        super(FindLocationService.class.getName());
    }

    public static Intent newIntent(Context context) {
        return new Intent(context, FindLocationService.class);
    }

    public static boolean isServiceAlarmOn(Context context) {
        Intent i = FindLocationService.newIntent(context);
        PendingIntent pendingIntent = PendingIntent
                .getService(context, SERVICE_REQUEST_CODE, i, PendingIntent.FLAG_NO_CREATE);
        return pendingIntent != null;
    }

    public static void setServiceAlarm(Context context, boolean isOn) {
        final int GPS_TIME = 1000 * 60; //every 1 minute (for the sake of testing)

        Intent i = FindLocationService.newIntent(context);
        PendingIntent pendingIntent = PendingIntent.getService(context, SERVICE_REQUEST_CODE, i, 0);

        AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);

        if (isOn) {
            alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME,
                    SystemClock.elapsedRealtime(), GPS_TIME, pendingIntent);
        } else {
            alarmManager.cancel(pendingIntent);
            pendingIntent.cancel();
        }
    }

    @Override
    public void onDestroy() {
        mClient.disconnect();
        super.onDestroy();
    }

    @Override
    public void onCreate() {
        super.onCreate();

        mNotificationBuilder = new NotificationCompat.Builder(this);
        mNotificationBuilder.setSmallIcon(android.R.drawable.star_on);
        mNotificationBuilder.setContentTitle("Got a Location!!");   //set properties for notification

        mClient = new GoogleApiClient.Builder(this)
                .addApi(LocationServices.API)
                .addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
                    @Override
                    public void onConnected(@Nullable Bundle bundle) {
                        Log.d(TAG, "Connected to Google location API");
                    }

                    @Override
                    public void onConnectionSuspended(int i) {

                    }
                })
                .addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() {
                    @Override
                    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
                        Log.d(TAG, "Failed to connect to Google API");
                    }
                })
                .build();

        mClient.connect();
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        getCurrentLocation();
    }

    private void getCurrentLocation() {
        LocationRequest request = new LocationRequest();
        request.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        request.setNumUpdates(1);
        request.setInterval(0);

        if (ActivityCompat.checkSelfPermission(this,
                Manifest.permission.ACCESS_FINE_LOCATION)
                != PackageManager.PERMISSION_GRANTED
                && ActivityCompat.checkSelfPermission(this,
                Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            Log.d(TAG, "Location permission denied.");
            return;
        }

        //I believe this is the line that causes the error:
        LocationServices.FusedLocationApi.requestLocationUpdates(mClient, request, new LocationListener() {
            @Override
            public void onLocationChanged(Location location) {
                Log.d(TAG, "Got a location fix: " + location);

                //Notify user about the new location
                mNotificationBuilder.setContentText("Location is " + location);
                NotificationManager mNotificationManager = (NotificationManager)
                        getSystemService(Context.NOTIFICATION_SERVICE);

                mNotificationManager.notify(1, mNotificationBuilder.build());
            }
        });
    }
}

此外,我的片段中有一个按钮调用 setServiceAlarm 来打开警报管理器。

如错误所示,当 onHandleIntent 启动时,我的 GoogleAPIClient 实例 (mClient) 未连接。我把mClient.connect()放在onHandleIntent里面,还是不行。我不明白为什么?我是否使用了错误的逻辑来编写我的代码?我应该将我的客户端构建器或我的 mClient.connect() 方法放在其他地方吗?

Google 建议在执行任何 GPS 相关 activity 之前检查 GoogleApiClient.isConnected()

https://developers.google.com/android/reference/com/google/android/gms/common/api/GoogleApiClient.html#isConnected()

您还可以添加回调 https://developers.google.com/android/reference/com/google/android/gms/common/api/GoogleApiClient.ConnectionCallbacks

并执行您的操作 onConnected(Bundle connectionHint)

我想我找到了问题; mClient 需要一些时间来连接到 google 服务,因此 getCurrentLocation() 必须在 mClient 连接时执行。感谢@Maxim Berezovsky 的回答,我添加了一个 onConnected(Bundle bundle) 回调来解决这个问题,但这引发了另一个问题:onHandleIntent() 退出速度快于 mClient 连接速度,因此服务在 mClient 偶数连接。为了解决这个问题,我在服务中使用了这段代码:

@Override
    public void onDestroy() {
        if (mClient.isConnected())
            mClient.disconnect();
        super.onDestroy();
    }

这将确保即使服务被终止,mClient 也不会断开连接。

我不确定这种方法是否耗电,但这是目前为止最好的方法。希望对大家有帮助。