当前位置: 首页 > 知识库问答 >
问题:

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

松钟展
2023-03-14

我试图创建一个Android应用程序,不断记录设备位置数据实时,而设备屏幕关闭。我的代码在Android6.0和更早的版本中工作正常,但似乎Android7.0+破坏了我的应用程序

我已经实现了一个Android前台服务,它使用wakelock并订阅了Google FusedLocation API。一旦屏幕关闭,onlocationchanged回调就永远不会触发。

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());
    }
}

Android O的代码示例

让应用程序一直在Android上后台运行

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

编辑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,仍然没有运气。

共有1个答案

文国发
2023-03-14

我在过去的一周里一直试图在前台提供定位服务。最后通过在清单中包括这一点来让它工作。

android:foregroundServiceType="location"

希望这能帮助到以后的人!

 类似资料:
  • 屏幕关闭时无法更新位置。 屏幕关闭后如何运行位置跟踪服务? 开启服务 在onLocationChanged方法中,我尝试Log. e(),但在屏幕关闭时不在logcat中显示纬度和经度 屏幕关闭时帮我介绍一下服务管理。谢谢你。

  • 我在android中保持套接字连接有麻烦。 我在应用程序中使用Socket.IO客户端java库。 屏幕打开时保持插座连接。 但是,如果屏幕关闭,套接字会因ping超时而断开连接。 我该如何解决这个问题? 我像这样打开连接。 这是我的服务器端代码 ping间隔为25秒,超时为60秒。 当android屏幕关闭时,客户端不适用于。其他事件正常工作。 服务器与日志断开连接(ping超时)。

  • 我创建了带有X服务器的泊客容器。我用它来进行一些屏幕外的 OpenGL 渲染。这个容器应该在任何系统(运行或不运行X服务器)上运行,如果它存在,它应该使用硬件GPU(所以我不能使用xvfb)。 当我在没有GUI的类似服务器的系统上使用此容器时,一切都可以完美地工作。但是,当我在 Ubuntu 14.04 桌面上运行容器时,每次我在容器中启动 X 服务器时,屏幕都会关闭。 我以 --privilig

  • 关闭屏幕盖时   设定关闭屏幕盖时的动作。 标准 关闭屏幕盖时,显示专用的画面。 进入睡眠模式 让主机进入睡眠模式。 提示 若主机处于锁定状态(POWER(电源)/HOLD(固定)按钮滑至下方),即使已选择[进入睡眠模式],主机仍不会在关闭屏幕盖时进入睡眠模式。 屏幕盖关闭时显示的画面 在屏幕盖关闭时按下L/R按钮,即可变更显示的内容。 同时按下L/R按钮 每次同时按下L/R按钮,可交替显示月历/

  • 注:此间隔=10000;我正在使用wakeLock来防止设备睡眠,如下所示: 另外,我在manifist.xml中的服务如下所示 最后,我将显示前台服务的通知,如下所示: 我也试图通过电池设置手动添加我的应用程序作为受保护的应用程序,但我得到了同样的行为。我测试了一些名为relive的应用程序,它完美地记录了GPS位置。我做错了什么? 更新:以下是我的OnStartCommand代码:

  • 我正在使用heroku和android客户端node.jsweb服务器进行websocket.io通信 我想在服务器信息发送到客户端Android系统时收到它,即使Android系统屏幕关闭 所以我基本上是做一个服务,一个套接字。在侦听器上,线程 也确实应用了部分_唤醒_锁定、前台服务、发送通知、每5秒乒乓一次... 当Android的屏幕打开时,我的系统运行良好。 但是在Android屏幕关闭后