使用Google Fused Location API切换服务时App崩溃求助
我在App中使用Google Fused Location API,包含两个核心Service:
- BackgroundService:每2分钟追踪一次位置,用于检测用户是否移动50米以识别行程;
- TripStartedService:每10秒追踪一次位置,当用户移动超过50米时启用。
目前服务启动和位置获取均正常,但关闭TripStartedService并重新启动BackgroundService以检测新行程时,App崩溃,抛出如下异常:
FATAL EXCEPTION: main Process: com.com.xxxxx.xxxxxxx, PID: 31551 java.lang.RuntimeException: Unable to stop service com.com.xxxxx.xxxxxxx.services.BackgroundLocationService@74441c6: java.lang.IllegalStateException: GoogleApiClient is not connected yet. at android.app.ActivityThread.handleStopService(ActivityThread.java:3060) at android.app.ActivityThread.-wrap21(ActivityThread.java) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1448) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:148) at android.app.ActivityThread.main(ActivityThread.java:5438) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:762) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:652) Caused by: java.lang.IllegalStateException: GoogleApiClient is not connected yet. at com.google.android.gms.internal.zzaaj.zzb(Unknown Source) at com.google.android.gms.internal.zzaan.zzb(Unknown Source) at com.google.android.gms.internal.zzaal.zzb(Unknown Source) at com.google.android.gms.internal.zzarl.removeLocationUpdates(Unknown Source) at com.xxxxx.xxxxxxx.services.BackgroundLocationService.stopLocationUpdates(BackgroundLocationService.java:103) at com.xxxxx.xxxxxxx.services.BackgroundLocationService.onDestroy(BackgroundLocationService.java:134) at android.app.ActivityThread.handleStopService(ActivityThread.java:3041) at android.app.ActivityThread.-wrap21(ActivityThread.java) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1448) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:148) at android.app.ActivityThread.main(ActivityThread.java:5438) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:762) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:652)
异常明确出现在BackgroundLocationService的onDestroy方法调用stopLocationUpdates()时。
BackgroundService代码
public class BackgroundLocationService extends Service implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener { protected static final String TAG = "BackService"; public static long UPDATE_INTERVAL_IN_MILLISECONDS = 1000*2; public static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS = UPDATE_INTERVAL_IN_MILLISECONDS / 2; public GoogleApiClient mGoogleApiClient; public LocationRequest mLocationRequest; private PendingIntent mPendingIntent; IBinder mBinder = new LocalBinder(); private class LocalBinder extends Binder { public BackgroundLocationService getServerInstance() { return BackgroundLocationService.this; } } @Override public void onCreate() { super.onCreate(); Log.i(TAG, "onCreate()"); Intent mIntentService = new Intent(this, LocationUpdates.class); mPendingIntent = PendingIntent.getService(this, 1, mIntentService, PendingIntent.FLAG_UPDATE_CURRENT); buildGoogleApiClient(); } @Nullable @Override public IBinder onBind(Intent intent) { return mBinder; } @Override public int onStartCommand(Intent intent, int flags, int startId) { super.onStartCommand(intent, flags, startId); if (mGoogleApiClient.isConnected()) { Log.i(TAG + " onStartCmd", "Connected"); return START_STICKY; } if (!mGoogleApiClient.isConnected() || !mGoogleApiClient.isConnecting()) { Log.i(TAG + " onStartCmd", "GoogleApiClient not Connected"); mGoogleApiClient.connect(); } return START_STICKY; } protected synchronized void buildGoogleApiClient() { Log.i(TAG, "Building GoogleApiClient"); mGoogleApiClient = new GoogleApiClient.Builder(this) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .addApi(LocationServices.API) .build(); mGoogleApiClient.connect(); createLocationRequest(); } protected void createLocationRequest() { Log.i(TAG, "createLocationRequest()"); mLocationRequest = new LocationRequest(); mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS); mLocationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS); mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); } protected void startLocationUpdates() { Log.i(TAG, "Started Location Updates"); if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { return; } LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, mPendingIntent); } public void stopLocationUpdates() { Log.i(TAG, "Stopped Location Updates"); LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, mPendingIntent); } @Override public void onConnected(Bundle connectionHint) { Log.i(TAG, "Connected to GoogleApiClient"); startLocationUpdates(); } @Override public void onLocationChanged(Location location) { String message = "Latitude : " + location.getLatitude() + "\n Longitude : " + location.getLongitude() + "\n location Accuracy: " + location.getAccuracy() + "\n speed: " + location.getSpeed(); Log.d(TAG, "onLocationChanged: " + message); } @Override public void onConnectionSuspended(int cause) { Log.i(TAG, "Connection suspended"); mGoogleApiClient.connect(); } @Override public void onConnectionFailed(@NonNull ConnectionResult result) { Log.i(TAG, "Connection failed: ConnectionResult.getErrorCode() = " + result.getErrorCode()); } @Override public void onDestroy() { super.onDestroy(); stopLocationUpdates(); } }
切换服务的逻辑代码
//This Code clock will return true if Trip completed Successfully. if (trip_counts > (TRIP_COMPLETION_CHECK_INTERVAL * NUMBER_OF_LOCATION_FETCH_IN_MINUTE) && trip_counts % NUMBER_OF_LOCATION_FETCH_IN_MINUTE == 0) { float total_distance = database.getTotalDistance(); Log.e("Distance", "calculateTrip: " + total_distance); if (total_distance < ACTIVE_TRIP_MIN_DISTANCE) { Log.d("TRIP STATUS", "calculateTrip: Trip Stopped !!!"); Date date_local = new Date(); SimpleDateFormat sdf_format = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); sdf_format.setTimeZone(TimeZone.getTimeZone("UTC")); Date gmt = new Date(sdf_format.format(date_local)); String utc_time = sdf_format.format(gmt); database.updateTripHistory("", MethodUtils.epochTimeConvert(utc_time), TripStatus.TRIP_COMPLETED); NotificationManager notificationManager = (NotificationManager) activity.getSystemService(NOTIFICATION_SERVICE); NotificationCompat.Builder notification = new NotificationCompat.Builder(activity); notification.setContentTitle("TITLE"); notification.setContentText("\n Trip Completed..."); notification.setSmallIcon(R.drawable.big_marker); notificationManager.notify(4321, notification.build()); activity.stopService(new Intent(activity, TripStartedService.class)); Log.i("Stoped Trip Srvce ", "calculateTrip: "); Log.i("Stoped Trip Srvce ", "================== Started BackGroundService Again: ============ "); activity.startService(new Intent(activity, BackgroundLocationService.class)); Log.i("Started BG Track Srvce", "calculateTrip: "); //Delete extra rows //SELECT _id FROM trip_started order by _id desc limit 1 offset 5-1; } } Log.e("Trip Database Rows Size", "" + trip_counts + "\t \tBackGroundTable Rows : " + back_counts + "\tGPS>>>;: " + Boolean.toString(isGpsEnabled)); activity.stopService(new Intent(activity, BackgroundLocationService.class)); } catch (Exception e) { e.printStackTrace(); }
问题分析与解决方案
问题根源
崩溃的核心原因是:当你调用stopService销毁BackgroundLocationService时,onDestroy方法直接调用了stopLocationUpdates(),但此时mGoogleApiClient可能处于未连接状态(比如连接异步未完成、之前连接已断开),直接调用LocationServices.FusedLocationApi.removeLocationUpdates()就会触发IllegalStateException。
解决方案1:在stopLocationUpdates中添加连接状态检查
修改stopLocationUpdates()方法,先判断mGoogleApiClient的连接状态,仅在已连接时执行移除操作:
public void stopLocationUpdates() { Log.i(TAG, "Stopped Location Updates"); // 先验证GoogleApiClient的有效性和连接状态 if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) { LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, mPendingIntent); } }
解决方案2:完善Service生命周期中的GoogleApiClient管理
在onDestroy中不仅停止位置更新,还要妥善断开GoogleApiClient的连接,避免资源泄漏:
@Override public void onDestroy() { super.onDestroy(); stopLocationUpdates(); // 断开GoogleApiClient连接(如果存在且已连接) if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) { mGoogleApiClient.disconnect(); } }
额外优化:避免重复连接GoogleApiClient
你的buildGoogleApiClient()方法中直接调用了mGoogleApiClient.connect(),而onStartCommand中也有连接逻辑,这可能导致重复连接请求。可以移除buildGoogleApiClient()中的connect()调用,统一由onStartCommand管理连接:
protected synchronized void buildGoogleApiClient() { Log.i(TAG, "Building GoogleApiClient"); mGoogleApiClient = new GoogleApiClient.Builder(this) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .addApi(LocationServices.API) .build(); createLocationRequest(); // 移除这里的mGoogleApiClient.connect(),交给onStartCommand处理 }
通过以上修改,就能避免在GoogleApiClient未连接时执行位置更新移除操作,解决崩溃问题。
内容的提问来源于stack exchange,提问作者user9192300

