位置情報の取得で、LocationManagerが将来的に廃止されるため、FusedLocationProviderClientに切り替えたました。
その際、HiltとLiveDataを使用してどこでも位置情報の変更を受信出来るようにしたので、それを説明したいと思います。
条件
- permissionに位置情報を追加
- permissionの許可を取得済み
- Hiltを導入済み
ModuleにFusedLocationProviderClientを定義
@Module
@InstallIn(SingletonComponent::class)
class AppModule {
@Provides
@Singleton
fun provideFusedLocationProviderClient(@ApplicationContext context: Context): FusedLocationProviderClient {
return LocationServices.getFusedLocationProviderClient(context)
}
}
Repositoryを作成する
FusedLocationProviderClientをInjectする。
LocationCallbackで位置情報に変化があった場合、Listenerに通知します。
@Singleton
class LocationRepository @Inject constructor(
@ApplicationContext private val context: Context,
private val fusedLocationProviderClient: FusedLocationProviderClient
) {
interface OnLocationListener {
fun onLocationChanged(location: Location)
fun onProviderChanged(isEnable: Boolean)
}
private var onLocationListener: OnLocationListener? = null
private val locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
onLocationListener?.onLocationChanged(locationResult.lastLocation)
}
}
fun start(onListener: OnLocationListener) {
onLocationListener = onListener
if (ActivityCompat.checkSelfPermission(
context,
Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(
context,
Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
return
}
val locationRequest = LocationRequest.create()
locationRequest.apply {
interval = TimeUnit.SECONDS.toMillis(5)
priority = LocationRequest.PRIORITY_HIGH_ACCURACY
}
fusedLocationProviderClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper())
}
fun stop() {
fusedLocationProviderClient.removeLocationUpdates(locationCallback)
onLocationListener = null
}
}
LiveDataを作成する
LocationRepositoryをInjectします。
LiveDataを作成するときにLocationRepositoryにListenerを渡します。
Listenerに変更があった場合、LiveDataのvalueに入れて通知します。
class LocationLiveData @Inject constructor(
private val locationRepository: LocationRepository
) : LiveData<Location>() {
private val onLocationListener = object : LocationRepository.OnLocationListener {
override fun onLocationChanged(location: Location) {
value = location
}
override fun onProviderChanged(isEnable: Boolean) {
}
}
override fun onInactive() {
super.onInactive()
stop()
}
fun start() {
locationRepository.start(onLocationListener)
}
fun stop() {
locationRepository.stop()
}
}
LocationLiveDataをモジュールに登録する
@Module
@InstallIn(SingletonComponent::class)
class AppModule {
@Provides
@Singleton
fun provideFusedLocationProviderClient(@ApplicationContext context: Context): FusedLocationProviderClient {
return LocationServices.getFusedLocationProviderClient(context)
}
@Provides
@Singleton
fun provideLocationLiveData(locationRepository: LocationRepository): LocationLiveData {
return LocationLiveData(locationRepository)
}
}
- LocationLiveDataを使用する
ViewModelでLocationLiveDataをInjectすることで、位置情報が変わったらActivity/Fragmentで取得することが可能です。
class MainViewModel @Inject constructor(
val locationLiveData: LocationLiveData
) {
fun start() {
locationLiveData.start()
}
}
viewModel.locationLiveData.observe(this) {
// it = Location
}
Hiltに関しては、自分の過去記事にありますので、よろしければそちらを参照してください。
LiveDataを使うことで、同じような位置情報を取得するコードを書かなくて済むようになりますので、よければ参考にしてください。