12
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Callbackから定期的に受け取る位置情報をKotlin Coroutines Flowを使って監視する方法

Last updated at Posted at 2019-09-14

Callbackから定期的に受け取る位置情報を Kotlin Coroutines Flow を使って監視する方法です。

build.gradle
dependencies {
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.1"
}

// AndroidStudio上のFlowの警告を抑止
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
    kotlinOptions {
        freeCompilerArgs = [
            '-Xuse-experimental=kotlinx.coroutines.ExperimentalCoroutinesApi',
            '-Xuse-experimental=kotlinx.coroutines.FlowPreview'
        ]
    }
}

位置情報の取得は FusedLocationProviderClient を使いました。
FusedLocationProviderClient の位置情報はCallback形式で返ってくるため、取得後に Flow に渡しています。

LocationDatasource.kt
class LocationDatasource(private val fusedLocationProviderClient: FusedLocationProviderClient) {

    fun observeLocationUpdate(): Flow<Location> = callbackFlow {
        val request = LocationRequest().also {
            it.interval = 60000
            it.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
        }
        val callback = object : LocationCallback() {
            override fun onLocationResult(locationResult: LocationResult?) {
                super.onLocationResult(locationResult)
                val location = locationResult?.lastLocation ?: return
                offer(Location(lat = location.latitude, lng = location.longitude))
            }
        }
        fusedLocationProviderClient.requestLocationUpdates(request, callback, null)
        awaitClose {
            fusedLolationProviderClient.removeLocationUpdates(callback)
        }
    }
}

callbackFlow で全体を囲い、requestLocationUpdates で位置情報の取得を開始します。ここでは、1分毎に位置情報を取得しています。

利用側で、Corotuinesが破棄されると、 awaitClose が呼ばれるため、 removeLocationUpdates を呼ぶことで位置情報の取得が停止します。

続いて、利用側のコードです。

HogeActionCreator.kt
fun startLocationUpdate() {
    launch(exceptionHandler) {
        val flow = locationRepository.observeLocationUpdate()
        flow.collect {
        	Timber.d("lat : ${it.lat}, lng : ${it.lng}")
        }
    }
}

coroutineScopelaunch 内で collect を呼びます。

ここでは、LocationReopository というRepository経由で位置情報を取得する実装にしています。

LocationReopository.kt
interface LocationRepository {
    fun observeLocationUpdate(): Flow<Location>
}
LocationReopositoryImpl.kt
class LocationRepositoryImpl(
    private val locationDatasource: LocationDatasource
) : LocationRepository {

    override fun observeLocationUpdate(): Flow<Location> {
        return locationDatasource.observeLocationUpdate()
    }
}
AppModule.kt
@Module
class AppModule {
    @Provides
    fun provideFusedLocationProviderClient(context: Context): FusedLocationProviderClient {
        return LocationServices.getFusedLocationProviderClient(context)
    }

    @Provides
    fun provideLocationDatasource(fusedLocationProviderClient: FusedLocationProviderClient): LocationDatasource {
        return LocationDatasource(fusedLocationProviderClient)
    }
}

以上です。
繰り返し呼ばれるCallbackを継続的に監視できるため、これから利用する機会が増えそうです。
awaitClose を使ってシンプルにCallbackを止める仕組みが備わっているのも嬉しいですね。

12
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?