繁体   English   中英

屏幕关闭时,前台服务未在 Android 7.0+ 中接收位置更新

[英]Foreground service not receiving location updates in Android 7.0+ when screen is off

我正在尝试创建一个 Android 应用程序,该应用程序在设备屏幕关闭时实时连续记录设备位置数据。 我的代码在 Android 6.0 及更早版本上正常工作,但似乎 Android 7.0+ 破坏了我的应用程序。

我已经实现了一个使用唤醒锁并订阅 Google FusedLocation API 的 Android 前台服务。 一旦屏幕关闭, onLocationChanged回调就不会被触发。

有没有人看到这个问题的解决方案? 我已尝试通过 Android 设备设置为我的应用以及 Google 服务框架和融合位置禁用电池优化。

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

    private static final String TAG = ForegroundLocationService.class.getSimpleName();

    // the notification id for the foreground notification
    public static final int GPS_NOTIFICATION = 1;

    // the interval in seconds that gps updates are requested
    private static final int UPDATE_INTERVAL_IN_SECONDS = 15;

    // is this service currently running in the foreground?
    private boolean isForeground = false;

    // the google api client
    private GoogleApiClient googleApiClient;

    // the wakelock used to keep the app alive while the screen is off
    private PowerManager.WakeLock wakeLock;

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

        // create google api client
        googleApiClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();

        // get a wakelock from the power manager
        final PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
        wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        if (!isForeground) {

            Log.v(TAG, "Starting the " + this.getClass().getSimpleName());

            startForeground(ForegroundLocationService.GPS_NOTIFICATION,
                    notifyUserThatLocationServiceStarted());
            isForeground = true;

            // connect to google api client
            googleApiClient.connect();

            // acquire wakelock
            wakeLock.acquire();
        }

        return START_REDELIVER_INTENT;
    }

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

    @Override
    public void onDestroy() {

        Log.v(TAG, "Stopping the " + this.getClass().getSimpleName());

        stopForeground(true);
        isForeground = false;

        // disconnect from google api client
        googleApiClient.disconnect();

        // release wakelock if it is held
        if (null != wakeLock && wakeLock.isHeld()) {
            wakeLock.release();
        }

        super.onDestroy();
    }

    private LocationRequest getLocationRequest() {

        LocationRequest locationRequest = LocationRequest.create();

        // we always want the highest accuracy
        locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);

        // we want to make sure that we get an updated location at the specified interval
        locationRequest.setInterval(TimeUnit.SECONDS.toMillis(0));

        // this sets the fastest interval that the app can receive updates from other apps accessing
        // the location service. for example, if Google Maps is running in the background
        // we can update our location from what it sees every five seconds
        locationRequest.setFastestInterval(TimeUnit.SECONDS.toMillis(0));
        locationRequest.setMaxWaitTime(TimeUnit.SECONDS.toMillis(UPDATE_INTERVAL_IN_SECONDS));

        return locationRequest;
    }

    private Notification notifyUserThatLocationServiceStarted() {

        // pop up a notification that the location service is running
        Intent notificationIntent = new Intent(this, NotificationActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
                notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT);

        final Notification.Builder builder = new Notification.Builder(this)
                .setSmallIcon(R.drawable.ic_launcher_foreground)
                .setContentTitle(getString(R.string.foreground_location_service))
                .setContentText(getString(R.string.service_is_running))
                .setContentIntent(pendingIntent)
                .setWhen(System.currentTimeMillis());

        final Notification notification;
        if (Build.VERSION.SDK_INT < 16) {
            notification = builder.getNotification();
        } else {
            notification = builder.build();
        }

        return notification;
    }

    @Override
    public void onConnected(@Nullable Bundle bundle) {

        try {

            // request location updates from the fused location provider
            LocationServices.FusedLocationApi.requestLocationUpdates(
                    googleApiClient, getLocationRequest(), this);

        } catch (SecurityException securityException) {
            Log.e(TAG, "Exception while requesting location updates", securityException);
        }
    }

    @Override
    public void onConnectionSuspended(int i) {
        Log.i(TAG, "Google API Client suspended.");
    }

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

    @Override
    public void onLocationChanged(Location location) {
        Log.e(TAG, "onLocationChanged: " + location.toString());
    }
}

我在此处包含了用于测试的完整代码示例: https : //github.com/joshuajwitter/ForegroundLocationService

FitBit 似乎有同样的问题,这里是讨论

以下是我已经看过的资源:

Android O 的代码示例

让应用始终在 Android 的后台运行

Android,在屏幕关闭时获取位置

后台位置限制

深度睡眠(打瞌睡)时前台服务中的位置更新不一致

前台服务未在 Android O 中的 Doze 模式下接收位置更新

编辑 2018.01.30:我也尝试在自己的进程中运行 ForegroundLocationService:

<service
    android:name="foregroundlocation.stackoverflowexample.com.foregroundlocation.ForegroundLocationService"
    android:enabled="true"
    android:stopWithTask="false"
    android:process=":ForegroundLocationService"
    android:exported="false" >
</service>

以及更新我的代码以使用FusedLocationProviderClient ,仍然没有运气。

过去一周我一直试图在前台获取位置服务。 最终通过在清单中包含它来使其工作。

android:foregroundServiceType="location"

我希望这可以帮助将来的人!

我遇到了同样的问题,我找到了一个可行的解决方案。 为了收听位置更新,您不应调用此方法:

public Task<Void> requestLocationUpdates (LocationRequest request, 
LocationCallback callback, Looper looper)

您应该使用挂起的意图而不是回调,即您应该调用该方法:

public Task<Void> requestLocationUpdates (LocationRequest request, 
PendingIntent callbackIntent)

查看链接以了解更多信息: https : //developers.google.com/android/reference/com/google/android/gms/location/FusedLocationProviderClient.html#requestLocationUpdates(com.google.android.gms.location.LocationRequest, android .app.PendingIntent)

LocationServices.FusedLocationApi 已弃用。

我只是按如下方式重构了我的应用程序。 希望它有帮助:

这就是我在服务的 onCreate-Method 中调用的内容:

public void start(Context ctx) {
        FusedLocationProviderClient client = LocationServices
                .getFusedLocationProviderClient(ctx);
        //Define quality of service:
        LocationRequest request = LocationRequest.create();
        request.setInterval(1000); //Every second
        request.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        if (locCallback != null) {
            client.removeLocationUpdates(locCallback);
        }
        locCallback = createNewLocationCallback();
        client.requestLocationUpdates(request, locCallback, null);
}

这是创建回调的方法:

private LocationCallback createNewLocationCallback() {
    LocationCallback locationCallback = new LocationCallback() {
        @Override
        public void onLocationResult(LocationResult result) {
            Location loc = result.getLastLocation();
            // Do something with the location (may be null!)
        }
    };
    return locationCallback;
}

猜猜看,我也发现某处作为示例,但没有保留参考。

我自己没有奥利奥。 但一些测试人员证实,它有效。

为了将服务保持在前台,我只是在我的服务的 onCreate 方法中调用“startForeground”。

我在运行 7.0 和 8.0 的模拟设备上遇到过这个问题,并且始终在屏幕关闭 (cmd+P) 时没有触发位置回调。 我终于能够接触到真正的 7.0 设备(Galaxy S7),但我无法复制该问题。 对不起,如果我浪费了任何人的时间,显然这是一个模拟器问题。

一种解决方案可能是这样的:

检查是否在 2 分钟内未收到位置停止/重新开始整个开始位置更新。 虽然前台服务必须解决问题

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM