2016-10-24 4 views
2

Google 앱 작동 방식으로 인해 사용자의 현재 위치를 동기식으로 가져와야합니다. 현재 구현에서는 com.google.android.gms.location.LocationListener을 사용하여 위치 업데이트를 수신합니다. 문제는 첫 번째 호출을 시도하기 전에 서버 쪽 위치를 업데이트해야합니다. 그렇지 않으면 사용자가 잘못된 데이터를 가져옵니다.현재 geolocation을 동 기적으로 검색하는 방법은 무엇입니까?

LocationServices.FusedLocationApi.getLastLocation()은 a) 항상 (어떤 이유로 든) null을 반환하고 b) 사용자가 마지막으로 알려진 위치를 서버 측에 저장하여 마지막으로 알려진 위치를 검색하고 전송하기 때문에 적합하지 않습니다. 서버에 연결하는 것이 중복됩니다. 내가 알고하지 않기 때문에 첫 번째 위치 업데이트 이벤트에 대한 대기

의사

//this is the first call I need to make 
webservice.appStart(AppStartBody body); 
//then I want to retrieve the current location and send it to the server 
webservice.setGeoLocation(getCurrentLocation()); 
//finally, I retrieve the items on the server based on the location 
webservice.getListItems(); 

, 나는 피하려고 가능성, 그것은 발사하고 나는 내 사용자를 유지해야 할 수 있습니다 얼마나 빨리 아무도 대기를 좋아하지 않기 때문에 연령대에 따라 화면을로드하고 차례로 잃어 버릴 수 있습니다.

+0

5 초, 5 초가 걸립니다. 주위를 둘러 볼 방법이 없습니다. 동 기적으로 수신하면 응용 프로그램 (또는 특정 스레드)이 5 초 동안 멈 춥니 다. 비동기 적으로 수신 한 경우 5 초를 사용하여 다른 작업을 수행 할 수 있습니다. 동기식 조작으로 문제가 해결되지는 않습니다. 'getLastLocation() '은 개발자의 테스트 폰에서'null '을 쉽게 반환 할 수 있으며 위치를 요청하는 다른 앱은 없습니다. 페이 스북 (Facebook), 구글 나우 (Google Now) 및 기타 등등이 실행되는 실제 사용자 폰에서는 상황이 더 나아질 수 있지만 물론 이에 의존 할 수는 없습니다. –

+0

_ "... 이미 사용자가 마지막으로 알려진 위치를 서버 측에 저장하므로 마지막으로 알려진 위치를 검색하여 서버로 전송하는 것은 불필요합니다."_ 앱을 실행 한 후 위치가 실제로 변경되지 않은 한 마지막으로. 그렇다면 그것은 중복되지 않습니다. –

+0

까지 내가 이해 한대로, 위치 서비스는 앱을 사용하는 한 마지막으로 알려진 위치 만 반환합니다. 모든 앱이 서비스에서 연결 해제되면 다시 null이 반환되며 이는 드문 경우는 아닙니다. 나는 그 무엇보다 신뢰할 수없는 것에 의지하고 싶지 않다. – TormundThunderfist

답변

0

RXx 관측 가능 범위 내에서 위치를 검색하는 프로세스를 배치하여이 문제를 해결할 수있었습니다. 구체적으로는 Single입니다. Single 개체의 blockingGet 메서드가 호출되어 위치를 동 기적으로 검색합니다. 그런 다음 첫 번째 시도에서 위치를 항상 사용할 수있는 것은 아니기 때문에 try catch 블록 안에 배치하여 재 시도를 수행합니다.

(나는 이것이 오래된 질문이라는 것을 알고 있지만 어쨌든 내가 어떻게했는지 공유 할 수 있도록 답변을 게시 할 예정입니다.) Kotlin과 RxJava를 사용하여 미안하지만 모든 사람들이 내 아이디어와 그것을 원하는 방식으로 구현할 수 있습니다. 최신 Google 위치 API도 사용하고 있습니다.)

// Use an executor to prevent blocking the thread where 
// this method will be called. Also, DO NOT call this on 
// the main thread!!! 
fun tryRetrieveLocationSync(flc: FusedLocationProviderClient, 
      executor: Executor, numOfRetries: Int = 3, 
      retryWaitTime: Long = 500): Location { 

    var location: Location 
    var i = 1 

    while (true) { 
    try { 
     // Place the method call inside a try catch block 
     // because `Single#blockingGet` will throw any exception 
     // that was provided to the `Emitter#onError` as an argument. 

     location = retrieveLocationSync(flc, executor) 
    } catch (e: NoLocationDataException()) { 
     if (i <= numOfRetries) { 
     // The value from the `FusedLocationProviderClient#lastLocation` 
     // task usually becomes available after less than second (tried 
     // and tested!!), but it's really up to you. 

     SystemClock.sleep(retryWaitTime * i) 
     i++ 
     } else { 
     throw e // Give up once all the retries have been used. 
     } 
    } catch (e: Exception) { 
     // Rethrow anything else that was thrown from 
     // the `Single#blockingGet`. 

     throw e 
    } 
    } 

    return location 
} 

private fun retrieveLocationSync(flc: FusedLocationProviderClient, 
      executor: Executor): Location { 

    return Single.create<Location> { emitter -> 
    val task = flc.lastLocation 
    task.addOnCompleteListener(executor, OnCompleteListener { // it -> 
     if (it.isSuccessful) { 
     if (it.result != null) { 
      emitter.onSuccess(it.result) 
     } else { 
      // There is no location data available probably because 
      // the location services has just been enabled, the device 
      // has just been turned on, or no other applications has 
      // requested the device's location. 
      emitter.onError(NoLocationDataException()) 
     } 
     } else { 
     // I haven't encountered any exception here but this is 
     // just to make sure everything's catchable. 
     emitter.onError(it.exception ?: RuntimeException()) 
     } 
    }) 
    }.blockingGet() 
}