Зацикливание rxLocationManager

Я создал LocationManager для обработки проблем с разрешениями и возврата lastLocation из FusedLocationProviderClient. Он интенсивно использует RxJava, чтобы избежать ада обратного вызова. Вот код:

object LocationManager {

    // using coarse location to not ask for GPS enabling
    // after changing to ACCESS_FINE_LOCATION don't forget to check GPS settings
    private const val LOCATION_PERMISSION = Manifest.permission.ACCESS_COARSE_LOCATION

    private var permissionSubject = AsyncSubject.create<Boolean>()

    fun loadLastLocation(activity: Activity): Observable<Location?> =
            checkPermission(activity).flatMap { hasPermission ->
                // check permission, then request last location
                Log.d("qwerty", "hasPermission=$hasPermission")
                if (hasPermission) requestLastLocation(activity)
                else Observable.error<Location>(Exception("Permission not granted"))
            }

    private fun checkPermission(activity: Activity): Observable<Boolean> =
            if (activity.hasPermission(LOCATION_PERMISSION)) Observable.just(true)
            else requestPermission(activity)

    private fun requestPermission(activity: Activity): Observable<Boolean> = permissionSubject.apply {
        // result will be posted to subject later
        Log.d("qwerty", "requestPermission $LOCATION_PERMISSION")
        ActivityCompat.requestPermissions(activity, arrayOf(LOCATION_PERMISSION), RequestCode.LOCATION_PERMISSION)
    }

    // call this from hosting activity or you can never get lastLocation
    fun onRequestPermissionsResult(requestCode: Int, grantResults: IntArray) {
        if (requestCode == RequestCode.LOCATION_PERMISSION) {
            permissionSubject.apply {
                val granted = grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED
                Log.d("qwerty", "onRequestPermissionsResult=$granted")
                onNext(granted)
                onComplete()
            }
        }
        // skip other request codes
    }

    @SuppressLint("MissingPermission")
    // check ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION before calling this
    private fun requestLastLocation(activity: Activity): Observable<Location?> = PublishSubject.create<Location>().apply {
        Log.d("qwerty", "requestLastLocation")
        LocationServices.getFusedLocationProviderClient(activity).lastLocation
                .addOnSuccessListener { location ->
                    Log.d("qwerty", "lastLocation=$location")
                    onNext(location)
                    onComplete()
                }
                .addOnFailureListener { error ->
                    Log.d("qwerty", "lastLocation error: ${error.message}")
                    onError(error)
                }
    }
}

И фрагмент вызывает LocationManager так:

    LocationManager.loadLastLocation(activity!!)
            .subscribe(
                    { location -> Log.d("qwerty", "fragment got location $location")},
                    { error -> error.printStackTrace() }
            )

Проблема в том, что наблюдаемые застряли в бесконечном цикле, пытаясь получить разрешение. Вот что я получаю в логах, бесконечные времена:

qwerty: requestPermission android.permission.ACCESS_COARSE_LOCATION
qwerty: hasPermission=false
System.err: java.lang.Exception: Permission not granted...
qwerty: onRequestPermissionsResult=false

Может кто-нибудь сказать мне, что не так с этим кодом?

1 ответ

Решение

Насколько я вижу из этого кода, он должен работать правильно. Пожалуйста, проверьте в своем манифесте, что тег содержит то же разрешение, которое вы запрашиваете. И второе, пожалуйста, проверьте, импортирует ли менеджер местоположений, импортируется ли соответствующий класс Manifest (android.Manifest не your.app.package.Manifest).

Другие вопросы по тегам