Closed riclage closed 4 years ago
I'm not sure if blockingConnect()
is a good idea, as existing code might break if no subscribeOn()
is specified and the calls then block the main thread.
Edit: Sorry, didn't mean to close the issue ;)
I think it makes sense in this case to throw an exception, no? That's what happens with Retrofit for example.
I won't change the behavior for now. Even if I use blockingConnect()
, setResultCallback()
still operates on the main thread then. And await()
can only be used on looper threads. Also, for location updates, the LocationListener
also gives updates on the main thread.
This means I have no way to collect location data in background. As soon as I leave the activity/block the main thread the obserable stops from emitting values
I was kinda able to do it, using a ForegroundService
.
The observable still runs on the Main
thread, but I guess here the main thread is the Service
's thread, so it works even if I leave the activity/application.
Sorry for the noisy code, it's still a bit WIP. Here it is
class LocationUploadService : Service() {
private val destroyEvent = PublishSubject.create<String>()
override fun onBind(intent: Intent): IBinder? {
return Binder()
}
@SuppressLint("MissingPermission", "CheckResult")
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
Logger.d("LocationUploadService", "onStart")
val rxPermission = RealRxPermission.getInstance(applicationContext)
val rxLocation = RxLocation(applicationContext)
val locationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(10000).setFastestInterval(3000)
val fineLocationPermissionEvent: Observable<Permission> =
rxPermission.request(Manifest.permission.ACCESS_FINE_LOCATION).toObservable()
val serviceO = when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.P -> rxPermission.request(Manifest.permission.FOREGROUND_SERVICE).toObservable()
else -> Observable.just(Permission.granted("Foreground service"))
}
val permissionCheckEvent = Observables.combineLatest(
fineLocationPermissionEvent,
serviceO
)
.doOnEach { Logger.d(it) }
.takeUntil(destroyEvent)
.share()
// destroy if refues permissions
permissionCheckEvent.filter { !isAllowed(it) }.takeUntil(destroyEvent).subscribe { this.onDestroy() }
// continue chain if allows permissions
val onPermissionGranted = permissionCheckEvent.filter { isAllowed(it) }.take(1).takeUntil(destroyEvent).share()
// destroy everything after 5
// onPermissionGranted.take(5).takeUntil(destroyEvent).subscribe { this.onDestroy() }
// core: observe notification updates
// create notification and foreground for the service
onPermissionGranted
.observeOn(Schedulers.newThread())
.subscribeOn(Schedulers.newThread())
.doOnNext {
Logger.v("Creating service notification...")
val notificationIntent = Intent(this, DriverActivity::class.java)
notificationIntent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
val notification = MyNotificationHelper(applicationContext).getGPSNotification(
getString(R.string.label_gps_localization_active),
getString(R.string.label_trip_running),
getString(R.string.app_name),
PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT)
)
val foregroundID = 1234
startForeground(foregroundID, notification.build())
}
.doOnNext { Logger.v("Starting to listen to location updates...") }
.switchMap { rxLocation.location().updates(locationRequest) } //listen to location
.takeUntil(destroyEvent)
.subscribe({ sendDataToServer(it) }) { Logger.e(it.localizedMessage) }
return Service.START_NOT_STICKY
}
private fun isAllowed(it: Pair<Permission, Permission>) =
it.first.state().equals(Permission.State.GRANTED) && it.second.state() == Permission.State.GRANTED
override fun onDestroy() {
super.onDestroy()
stopForeground(true)
}
private fun sendDataToServer(location: Location) {
val toUpload = Tracking()
// toUpload.setLatitude(location.latitude)
// toUpload.setLongitude(location.longitude)
// toUpload.setSpeed(location.speed.toDouble())
// toUpload.setPrecision(location.accuracy.toDouble())
// toUpload.setDate(OffsetDateTime.now(ZoneOffset.UTC))
// toUpload.setTrip(currentTripCode)
if (Utils.isNetworkAvailable(applicationContext)) {
try { // upload
Logger.v("Uploading location data to server...")
} catch (e: ApiException) {
Logger.e("Tracking upload error: \n", e)
}
} else {
Logger.v("No internet, doing nothing...")
}
}
internal interface IntentActions {
companion object {
const val GPS_START = "scheduleGPS"
const val GPS_STOP = "notification_exit"
}
}
}
This library is now deprecated and not maintained anymore. Please switch to the CoLocation library.
The GoogleApiClient callback
onConnected()
is always called on the main thread. This is causing the chain to ignore the scheduler specified onsubscribeOn()
.One solution to this is to use
blockingConnect()
instead ofconnect()
.