【问题标题】:Get Location Update when app is in background当应用程序在后台时获取位置更新
【发布时间】:2018-04-24 11:50:37
【问题描述】:

我正在尝试创建一个服务,该服务在应用程序处于后台时提供位置更新,特别适用于 Android 8 及更高版本,因为他们已经优化了后台服务。我在 stackOverflow 和 Google API 文档上阅读了一些答案,他们提到将 PendingIntent 传递给 onRequestLocationUpdates 将提供位置,即使应用程序在后台。正如doc 中提到的那样。这是我的服务类:

public class LocationMonitoringService extends Service implements
        GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener,
        LocationListener {

    private static final String TAG = LocationMonitoringService.class.getSimpleName();
    GoogleApiClient mLocationClient;
    LocationRequest mLocationRequest = new LocationRequest();


    public static final String ACTION_LOCATION_BROADCAST = LocationMonitoringService.class.getName() + "LocationBroadcast";
    public static final String EXTRA_LATITUDE = "extra_latitude";
    public static final String EXTRA_LONGITUDE = "extra_longitude";

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        mLocationClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();


        mLocationRequest.setInterval(Constants.LOCATION_INTERVAL);
        mLocationRequest.setFastestInterval(Constants.FASTEST_LOCATION_INTERVAL);


        int priority = LocationRequest.PRIORITY_HIGH_ACCURACY; //by default
        //PRIORITY_BALANCED_POWER_ACCURACY, PRIORITY_LOW_POWER, PRIORITY_NO_POWER are the other priority modes


        mLocationRequest.setPriority(priority);
        mLocationClient.connect();

        //Make it stick to the notification panel so it is less prone to get cancelled by the Operating System.
        return START_STICKY;
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    /*
     * LOCATION CALLBACKS
     */
    @Override
    public void onConnected(Bundle dataBundle) {
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            // TODO: Consider calling
            //    ActivityCompat#requestPermissions
            // here to request the missing permissions, and then overriding
            //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
            //                                          int[] grantResults)
            // to handle the case where the user grants the permission. See the documentation
            // for ActivityCompat#requestPermissions for more details.

            Log.d(TAG, "== Error On onConnected() Permission not granted");
            //Permission not granted by user so cancel the further execution.

            return;
        }


        Intent intent = new Intent(this, LocationMonitoringService.class);
        PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        LocationServices.FusedLocationApi.requestLocationUpdates(mLocationClient, mLocationRequest, pendingIntent);


        Log.d(TAG, "Connected to Google API");
    }

    /*
     * Called by Location Services if the connection to the
     * location client drops because of an error.
     */
    @Override
    public void onConnectionSuspended(int i) {
        Log.d(TAG, "Connection suspended");
    }


    //to get the location change
    @Override
    public void onLocationChanged(Location location) {
        Log.d(TAG, "Location changed");


        if (location != null) {
            Log.d(TAG, "== location != null");

            //Send result to activities
            sendMessageToUI(String.valueOf(location.getLatitude()), String.valueOf(location.getLongitude()));
        }

    }


    private void sendMessageToUI(String lat, String lng) {

        Log.d(TAG, "Sending info...");

        Intent intent = new Intent(ACTION_LOCATION_BROADCAST);
        intent.putExtra(EXTRA_LATITUDE, lat);
        intent.putExtra(EXTRA_LONGITUDE, lng);
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);

    }


    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {
        Log.d(TAG, "Failed to connect to Google API");

    }

}

在上面的代码中,当我将 PendingIntent 传递给 requestLocationUpdates 时,它会抛出一个错误 GoogleAPIClient not connected。

以下是我遇到的错误

java.lang.IllegalStateException: GoogleApiClient is not connected yet.
        at com.google.android.gms.internal.zzbcd.zze(Unknown Source)
        at com.google.android.gms.internal.zzbcx.zze(Unknown Source)
        at com.google.android.gms.internal.zzbcp.zze(Unknown Source)
        at com.google.android.gms.internal.zzccb.requestLocationUpdates(Unknown Source)
        at com.locationtracker.LocationMonitoringService.onConnected(LocationMonitoringService.java:93)
        at com.google.android.gms.common.internal.zzac.zzn(Unknown Source)
        at com.google.android.gms.internal.zzbcp.zzm(Unknown Source)
        at com.google.android.gms.internal.zzbcd.zzpY(Unknown Source)
        at com.google.android.gms.internal.zzbcd.onConnected(Unknown Source)
        at com.google.android.gms.internal.zzbcx.onConnected(Unknown Source)
        at com.google.android.gms.internal.zzbbi.onConnected(Unknown Source)
        at com.google.android.gms.common.internal.zzaa.onConnected(Unknown Source)
        at com.google.android.gms.common.internal.zzn.zzrj(Unknown Source)
        at com.google.android.gms.common.internal.zze.zzs(Unknown Source)
        at com.google.android.gms.common.internal.zzi.zzrk(Unknown Source)
        at com.google.android.gms.common.internal.zzh.handleMessage(Unknown Source)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:148)
        at android.app.ActivityThread.main(ActivityThread.java:5461)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

【问题讨论】:

  • 检查您的设备是否安装了 google playservice。

标签: android location fusedlocationproviderapi


【解决方案1】:

我可以看到您已经在onStartCommand() 中实例化了您的GoogleApiClient 实例,并且正如服务生命周期所说,每次启动服务时都会调用onStartCommand()。因此,每次它实例化您的 GoogleApiClient 实例时。 我认为这会在您的代码中造成冲突。让我们考虑一个场景来理解问题。

  1. 您已经启动了一次服务,一秒钟后您又启动了它。因此,它两次都会启动mLocationClient,因为您已经在 onStartCommand() 方法中启动了它。假设第一个实例的值为 mLocationClient1,另一个为 mLocationClient2。(此值仅用于说明简单)。

  2. mLocationClient1 连接成功后,它会触发 onConnected() 方法,在其中您使用了 mLocationClient,它由尚未连接的新值 mLocationClient2 初始化。因此它返回 googleapiclient 未连接的错误。

如果您认为您只启动了一次服务,那么为什么它会多次调用 onStartCommand() 而不是这里的答案。每当您从最近的应用列表中删除您的应用时,都会停止您的服务,但您已经创建了 START_STICKY 服务,因此,操作系统重新启动您的服务并再次调用 onStartCommand() 方法。

所以,我建议您在onCreate() 方法中设置mLocationClient 而不是onStartCommand(),因为onCreate() 方法只有在服务被销毁后第一次创建时才会被调用。

【讨论】:

  • 感谢您的解释。你的解释确实有效。
  • 很高兴 :) @gauravtiwari
【解决方案2】:

我遇到了同样的问题,请尝试在 Android Studio 模拟器中运行您的代码,而不是在其他模拟器中运行。造成这种情况的原因是您需要在设备中安装 Google Play 服务。

【讨论】:

  • 我在 OnePlus 设备上运行它。当我删除待处理的意图并传递上下文时,它的工作正常。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-05
  • 2021-07-06
  • 1970-01-01
  • 2018-07-13
  • 2015-03-11
  • 1970-01-01
相关资源
最近更新 更多