Android:为什么关闭屏幕后 60 秒 GPS 会停止?

问题描述 投票:0回答:1

我创建了一个应用程序,它使用 LocationManager requestUpdateLocations 每秒检索位置。

一开始,在不使用前台服务的情况下,当我关闭屏幕时,位置更新立即停止。

然后我设置了一个前台服务,它实现了 LocationListener 和 GpsStatus.Listener。 我在 MainActivity 中使用 startForegroundService 启动此服务,并在通知栏中创建通知。 (我还请求 ACCESS_BACKGROUND_LOCATION 权限,该权限已被授予,并且工作正常) 现在,当我关闭屏幕时,我在 onLocationChanged 中完美记录了背景位置但仅记录了 60 秒60 秒后,我系统地收到事件 GpsStatus.GPS_EVENT_STOPPED 并且我没有更多位置更新。

因为Android 宣布对后台位置检索的限制,我尝试每 35 秒而不是每秒检索一次位置。但在持续 60 秒后,当我预计后台至少有 30 分钟的位置更新时,我仍然得到 GpsStatus.GPS_EVENT_STOPPED。 最重要的是,我预计位置更新不会再发生,但 GPS 不会完全停止,因此它可以在 1 小时后恢复(Android 说:“您每小时会收到几个位置”)

有谁知道为什么GPS在后台运行60秒后系统关闭? 当我收到 GPS_EVENT_STOPPED 事件时,有办法重新启动 GPS 吗? (我尝试调用locationManager.removeUpdates(myListener)和locationManager.removeGpsStatusListener(myListener),然后调用requestLocationUpdates和addGpsStatusListener,但无事可做,GPS不会重新启动...) 是否需要进行任何配置来防止 GPS 停止? 我是否必须将后台的服务“连接”到我的活动,以便 GPS 不会神奇地停止?

注意:我总是在真实设备上测试,而不是在模拟器上。

这是我的 MyService 课程:

class MyService: Service(), LocationListener, GpsStatus.Listener {
    private var myTime: Long? = null
    private var locationManager: LocationManager? = null

    fun startGps() {
        locationManager?.removeUpdates(this)
        locationManager?.removeGpsStatusListener(this)

        locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager

        locationManager?.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 0f, this)
        locationManager?.addGpsStatusListener(this)
    }

    override fun onCreate() {
        startGps()
        super.onCreate()
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        val pendingIntent: PendingIntent =
            Intent(this, MainActivity::class.java).let { notificationIntent ->
                PendingIntent.getActivity(this, 0, notificationIntent, 0)
            }

        val channelId = createNotificationChannel("my_service_speed", "My Speed Background Service")

        val notification: Notification = Notification.Builder(this, channelId)
            .setContentTitle("notification_title")
            .setContentText("notification_message")
            .setSmallIcon(R.drawable.ic_speed_icon_24)
            .setContentIntent(pendingIntent)
            .setTicker("ticker_text")
            .build()

        // Notification ID cannot be 0.
        startForeground(111555, notification)

        return super.onStartCommand(intent, flags, startId)
    }

    private fun createNotificationChannel(channelId: String, channelName: String): String{
        val chan = NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_NONE)
        chan.lightColor = Color.BLUE
        chan.lockscreenVisibility = Notification.VISIBILITY_PRIVATE
        val service = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        service.createNotificationChannel(chan)
        return channelId
    }

    override fun onBind(p0: Intent?): IBinder? {
        return null
    }

    override fun onLocationChanged(location: Location) {
        if (location.hasSpeed()) {
            var tTime = System.currentTimeMillis()
            if (myTime == null) {
                myTime = tTime
            } else {
                tTime = System.currentTimeMillis()
            }

            var bdSpeed = BigDecimal(location.speed * 3.6)
            bdSpeed = bdSpeed.setScale(1, BigDecimal.ROUND_DOWN)
            val speed: Double = bdSpeed.toDouble()
            println("New Speed:  ----> $speed Km/h  at second ${(tTime - myTime!!) / 1000}s")
        }
    }

    override fun onGpsStatusChanged(event: Int) {
        when (event) {
            GpsStatus.GPS_EVENT_SATELLITE_STATUS -> {
                val gs = locationManager?.getGpsStatus(null)
                var gpsSatsInFix = 0

                gs?.let {
                    val iterator: Iterator<GpsSatellite> = gs.satellites.iterator()
                    while (iterator.hasNext()) {
                        val gpssatellite = iterator.next()
                        if (gpssatellite.usedInFix()) {
                            gpsSatsInFix++
                        }
                    }
                }

                println("GPS_EVENT_SATELLITE_STATUS  -->   Satellites used: $gpsSatsInFix / ${gs!!.satellites.count()} available")
            }

            GpsStatus.GPS_EVENT_FIRST_FIX -> {
                println("GPS_EVENT_FIRST_FIX   --->   Satellites search ...")
            }
            GpsStatus.GPS_EVENT_STOPPED -> {
                println("GPS_EVENT_STOPPED   --->   GAME OVER ...")
            }
        }
    }
}

我的 MainActivity 类:

class MainActivity : AppCompatActivity() {

    // ... 

    override fun onCreate(savedInstanceState: Bundle?) {
        // ...

        val mIntent = Intent(this, MyService::class.java)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            startForegroundService(mIntent)
        }
        
        // ...
    }
    
    // ...
    
}
android background gps location
1个回答
0
投票

根据 Android 官方文档,系统会尽力节省电量,其中之一就是 GPS 在一定时间(60 秒)后关闭

如果后台位置访问对于您的应用至关重要,请记住,Android 通过在运行 Android 8.0(API 级别 26)及更高版本的设备上设置后台位置限制来延长设备电池寿命。在这些版本的 Android 上,如果您的应用程序在后台运行,则它每小时只能接收几次位置更新。了解有关后台位置限制的更多信息。

这里有官方页面的链接

如果您想了解有关限制的更多详细信息,我建议您阅读以下文章

© www.soinside.com 2019 - 2024. All rights reserved.