我正在创建一个应用程序,使用IntentService
中的AlarmManager
在GoogleAPIClient
的帮助下每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.java类:
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相关活动之前检查GoogleApiClient.isConnected()
。
https://developers.google.com/android/reference/com/google/android/gms/common/api/GoogleApiClient.html与()
还可以添加回调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也不会断开连接。
我不确定这种方法是否耗电,但这是目前为止我得到的最好的方法。