Android Kotlin 前台服务在一段时间后停止

2023-11-23

我正在开发用于用户跟踪的前台位置服务。每次位置更新时,该服务都会向 API 发送请求以更新当前位置。问题是,当应用程序置于后台或屏幕被锁定时,服务会在一段时间后停止发送请求(通常在 1 分钟左右,在此期间发送大约 10 个请求)。应用程序恢复后,服务再次开始工作,最小化/锁定屏幕后,场景会重复。

在 - 的里面onStartCommand我尝试返回多个启动选项,但都不起作用。我已经在 Android 10 和 11 上测试了该应用程序。

服务源码:

class LocationService: Service()  {

    @Inject
    lateinit var apiService: ApiService

    private val composite = CompositeDisposable()

    private var locationManager: LocationManager? = null
    private var locationListener: LocationListener? = null

    override fun onBind(p0: Intent?): IBinder? =
        null

    val NOTIFICATION_CHANNEL_ID = "location_tracking"
    val NOTIFICATION_CHANNEL_NAME = "Location tracking"
    val NOTIFICATION_ID = 101

    var isFirstRun = true

    @SuppressLint("MissingPermission")
    override fun onCreate() {
        App.component.inject(this)

        setupLocationListener()

        locationManager = getSystemService(LOCATION_SERVICE) as LocationManager?
        val criteria = Criteria()
        criteria.accuracy = Criteria.ACCURACY_FINE
        val provider = locationManager?.getBestProvider(criteria, true)

        val minTime = 5*1000L
        if(provider != null) locationManager?.requestLocationUpdates(provider, minTime, 0f, locationListener)

        super.onCreate()
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        if (isFirstRun) {
            startForegroundService()
            isFirstRun = false
        } else {
            Timber.d {"Resuming service"}
        }

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

    private fun startForegroundService() {
        val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) createNotificationChannel(notificationManager)

        val notificationBuilder = NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
                .setAutoCancel(false)
                .setOngoing(true)
                .setSmallIcon(R.drawable.ic_notification)
                .setContentTitle(NOTIFICATION_CHANNEL_NAME)
                .setContentIntent(getMainActivityIntent())

        startForeground(NOTIFICATION_ID, notificationBuilder.build())
    }

    private fun getMainActivityIntent()
        = PendingIntent.getActivity(this, 0, Intent(this, MainActivity::class.java)
            .also { it.action = R.id.action_global_navigationScreenFragment.toString() }, FLAG_UPDATE_CURRENT)

    @RequiresApi(Build.VERSION_CODES.O)
    private fun createNotificationChannel(notificationManager: NotificationManager) {
        val channel = NotificationChannel(NOTIFICATION_CHANNEL_ID, NOTIFICATION_CHANNEL_NAME, IMPORTANCE_LOW)
        notificationManager.createNotificationChannel(channel)
    }

    private fun setupLocationListener() {
        locationListener = object: LocationListener {

            override fun onLocationChanged(location: Location) {
                val cords = GeoCoordinatesDTO(location.latitude.toFloat(), location.longitude.toFloat())
                try {
                    composite.add(apiService.mobileUserAccountReportPosition(cords)
                        .subscribeOn(Schedulers.io())
                        .observeOn(AndroidSchedulers.mainThread())
                        .subscribe(
                            {},
                            { t ->
                                if(t is RuntimeException) {
                                    e(t)
                                }
                            }
                        ))
                } catch(e: Exception) {
                    Log.e("GPS", "error: $e")
                }
            }

            override fun onStatusChanged(provider: String, status: Int, extras: Bundle) {}

            override fun onProviderEnabled(provider: String) {}

            override fun onProviderDisabled(provider: String) {}

        }
    }

    override fun onDestroy() {
        try {
            locationManager?.removeUpdates(locationListener)
        } catch(e: DeadObjectException) {}
        super.onDestroy()
    }

}

该服务开始于onStart函数于MainActivity

private fun initializeLocationMonitor() {
    locationService = Intent(this, LocationService::class.java)
    if(!this.isServiceRunning(LocationService::class.java)) {
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            startForegroundService(locationService)
        } else {
            startService(locationService)
        }
        sendBroadcast(locationService)
    }
}

我在清单中拥有以下权限并注册了服务:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

<service
    android:name=".Services.LocationService"
    android:enabled="true"
    android:exported="true"
    tools:ignore="ExportedService,InnerclassSeparator"
    android:foregroundServiceType="location"/>

  1. 保持设备唤醒 -https://developer.android.com/training/scheduling/wakelock
// global service variable
private var wakeLock: PowerManager.WakeLock? = null
...
// initialize before setupLocationListener() is called
wakeLock =
            (getSystemService(Context.POWER_SERVICE) as PowerManager).run {
                newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "LocationService::lock").apply {
                    acquire(10*1000L)  // 10 seconds
                }
            }

显现:

<uses-permission android:name="android.permission.WAKE_LOCK" />
  1. 检查您的应用程序在应用程序设置中是否限制了数据使用和电池服务器。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android Kotlin 前台服务在一段时间后停止 的相关文章

随机推荐