For my specific use case, I need to fetch the device's real-time location updates and pass them to a remote server at 15 15-second frequency(or less than 15 seconds). To achieve this, I wrote a foreground service that initializes a FusedLocationProviderClient
with interval
and fastestIntetval
as 15s. I am using an external HandlerThread's looper to invoke requestLocationUpdates
.
对于我的特定用例,我需要获取设备的实时位置更新,并以15到15秒(或不到15秒)的频率将其传递到远程服务器。为了实现这一点,我编写了一个前台服务,它初始化了一个FusedLocationProviderClient,其间隔和fastestIntegval为15s。我正在使用外部HandlerThread的循环器来调用requestLocationUpdates。
When the app is in the foreground, location updates are received in onLocationResult
callback of LocationCallback
and also if I invoke getLastLocation()
then it returns the same location. But whenever the app is minimized (service still running, the foreground notification is there), onLocationResult
does not gets triggered and invoking getLastLocation()
returns null.
当应用程序处于前台时,位置更新会在LocationCallback的onLocationResult回调中接收,如果我调用getLastLocation(),它也会返回相同的位置。但每当应用程序最小化时(服务仍在运行,前台通知在那里),onLocationResult不会被触发,调用getLastLocation()将返回null。
Is this expected behavior from Fused? If not, how can I fix this issue. I am sharing the codes bellow:
这是Fused的预期行为吗?如果没有,我该如何解决此问题。我正在分享以下代码:
private val mLocationRequest =
LocationRequest().apply {
interval = updateFrequency
fastestInterval = updateFrequency
priority = LocationRequest.PRIORITY_HIGH_ACCURACY
}
private val mFusedLocationClient: FusedLocationProviderClient by lazy {
LocationServices.getFusedLocationProviderClient(
this
)
}
private val mLocationCallback: LocationCallback by lazy {
object : LocationCallback() {
override fun onLocationResult(p0: LocationResult?) {
super.onLocationResult(p0)
p0?.lastLocation?.let {
if (System.currentTimeMillis() - (Constants.lastLocationFetchTimestamp
?: 0) > minTimeBlockThreshold && Constants.currentLocation != null
) {
}
}
}
}
}
private lateinit var mServiceHandler: Handler
override fun onCreate() {
super.onCreate()
getLastLocation()
val handlerThread = HandlerThread(LocationUpdatesService::class.java.simpleName)
handlerThread.start()
mServiceHandler = Handler(handlerThread.looper)
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
super.onStartCommand(intent, flags, startId)
return START_NOT_STICKY
}
override fun onBind(p0: Intent): IBinder {
super.onBind(p0)
stopForeground(true)
return mBinder
}
override fun onRebind(intent: Intent?) {
super.onRebind(intent)
stopForeground(true)
}
override fun onUnbind(intent: Intent?): Boolean {
if (!mChangingConfiguration && preferenceManager.requestingLocationUpdates()) {
startForeground(
(applicationContext as ContractorApp).notificationIdForForegroundService,
NotificationUtils.getForegroundServiceNotification(applicationContext)
)
}
return true
}
override fun onDestroy() {
super.onDestroy()
mServiceHandler.removeCallbacksAndMessages(null)
}
fun requestLocationUpdates() {
try {
mFusedLocationClient.removeLocationUpdates(mLocationCallback)
preferenceManager.setRequestingLocationUpdates(true)
startService(Intent(applicationContext, LocationUpdatesService::class.java))
mFusedLocationClient.requestLocationUpdates(
mLocationRequest,
mLocationCallback, mServiceHandler.looper
)
startRecursiveForceLocationFetchCall()
Constants.locationUpdatesRequested = true
} catch (unlikely: SecurityException) {
Utils.reportNonFatals(unlikely)
preferenceManager.setRequestingLocationUpdates(false)
}
}
fun removeLocationUpdates() {
try {
Constants.locationUpdatesRequested = false
mFusedLocationClient.removeLocationUpdates(mLocationCallback)
preferenceManager.setRequestingLocationUpdates(false)
preferenceManager.remove(Constants.ACTIVE_VEHICLE_TYPE)
stopRecursiveForceLocationFetchCall()
stopSelf()
} catch (unlikely: SecurityException) {
Utils.reportNonFatals(unlikely)
preferenceManager.setRequestingLocationUpdates(true)
}
}
fun updateNotificationText() {
(getSystemService(NOTIFICATION_SERVICE) as NotificationManager).notify(
(applicationContext as ContractorApp).notificationIdForForegroundService,
NotificationUtils.getForegroundServiceNotification(applicationContext)
)
}
private fun getLastLocation() {
try {
mFusedLocationClient.lastLocation
?.addOnCompleteListener { task ->
if (task.isSuccessful && task.result != null) {
if (task.result != null) {
Constants.currentLocation = task.result
}
}
}
} catch (unlikely: SecurityException) {
Utils.reportNonFatals(unlikely)
}
}
private fun onNewLocation(location: Location) {
// logic to send location to remote server
}
private var forcePing: Job? = null
private fun startRecursiveForceLocationFetchCall() {
if (forcePing == null) {
forcePing = GlobalScope.launch(Dispatchers.IO){
while (true) {
if (ContextCompat.checkSelfPermission(
this@LocationUpdatesService,
Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED
) {
mFusedLocationClient.lastLocation.addOnSuccessListener { location ->
if (location != null) {
// Use the last known location
val latitude = location.latitude
val longitude = location.longitude
onNewLocation(location)
} else {
Timber.tag("FORCE_PING").d("Last known location is null")
}
}.addOnFailureListener {
Utils.reportNonFatals(it)
}.addOnCanceledListener {
Timber.tag("FORCE_PING").d("Issue")
}
} else {
// No permission
}
delay(TimeUnit.SECONDS.toMillis(15))
}
}
} else {
forcePing?.cancel()
forcePing = null
startRecursiveForceLocationFetchCall()
}
}
private fun stopRecursiveForceLocationFetchCall() {
if (forcePing != null) {
forcePing?.cancel()
forcePing = null
}
}
更多回答
I solved this issue later by myself. This is a case of a foreground service being called from the background. Somehow, during the onUnbind phase when the service was being promoted to the foreground, it used to take some time (1-2.5 seconds), which is why it was requesting background location. Later, I changed the service to be promoted to the foreground whenever it starts and removed the process of stopping and starting it based on unBind, reBind, and unBind.
后来我自己解决了这个问题。这是从后台调用前台服务的情况。不知怎的,在onUnbind阶段,当服务被提升到前台时,它需要一些时间(1-2.5秒),这就是它请求后台位置的原因。后来,我将服务更改为无论何时启动都会升级到前台,并删除了基于unBind、reBind和unBind停止和启动服务的过程。
我是一名优秀的程序员,十分优秀!