问题:我正在 Kotlin 中开发一个简单的测试应用程序,其前台位置服务每 5 秒更新一次 GPS 坐标(纬度和经度)。该应用程序有 1 个主要 Activity 和 3 个片段,通过基本导航连接。在第三个片段中,有一个 RecyclerView 应该接收并附加新的位置更新。我成功地通过硬编码按钮将项目添加到列表中,但我不知道如何将新位置更新自动从服务发布到片段。
代码片段:在我的 LocationService 中,我正在使用新位置更新通知,但很难将更新后的位置发送到片段。这是相关代码:
private var locationViewModel = SampleViewModel()
override fun onCreate() {
super.onCreate()
locationClient = DefaultLocationClient(
this,
LocationServices.getFusedLocationProviderClient(applicationContext)
)
locationViewModel = ViewModelProvider(applicationContext)[SampleViewModel::class.java]
//Type mismatch.
Required:
ViewModelStoreOwner
Found:
Context!
}
// In LocationService
private fun updateLocationList(lat: String, lon: String) {
val event = TripEvent(lat, lon)
// Tried using ViewModel here, but can't access application context
//locationViewModel.addTripEvent(event)
}
问题:如何有效地将位置更新从前台服务传递到片段,以便 RecyclerView 自动更新新数据?
我的尝试:我尝试使用共享 ViewModel (SampleViewModel) 来更新列表,但在尝试声明和访问服务中的 ViewModel 时遇到了问题。主要挑战是 ViewModelProvider 无法在服务中工作,因为它无法访问应用程序上下文。
1。将 LocalBroadcastManager 与 BroadcastReceiver 结合使用
//In LocationService
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import android.content.Intent
private fun updateLocationList(lat: String, lon: String) {
val intent = Intent("LOCATION_UPDATE")
intent.putExtra("latitude", lat)
intent.putExtra("longitude", lon)
LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
}
// In your fragment
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import androidx.localbroadcastmanager.content.LocalBroadcastManager
private val locationUpdateReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val lat = intent?.getStringExtra("latitude")
val lon = intent?.getStringExtra("longitude")
lat?.let {
lon?.let {
// Update your RecyclerView adapter here
val event = TripEvent(lat, lon)
// Assuming you have a function in your adapter to add items
myAdapter.addTripEvent(event)
}
}
}
}
override fun onStart() {
super.onStart()
LocalBroadcastManager.getInstance(requireContext())
.registerReceiver(locationUpdateReceiver, IntentFilter("LOCATION_UPDATE"))
}
override fun onStop() {
super.onStop()
LocalBroadcastManager.getInstance(requireContext())
.unregisterReceiver(locationUpdateReceiver)
}
2。如果您更愿意坚持使用 ViewModel,您可以使用带有服务绑定的共享 ViewModel
// In LocationService
import android.os.Binder
class LocationService : Service() {
private val binder = LocalBinder()
inner class LocalBinder : Binder() {
fun getService(): LocationService = this@LocationService
}
override fun onBind(intent: Intent?): IBinder {
return binder
}
private fun updateLocationList(lat: String, lon: String) {
val event = TripEvent(lat, lon)
locationViewModel.addTripEvent(event) // You can use the ViewModel now
}
}
private lateinit var locationService: LocationService
private var bound = false
private val serviceConnection = object : ServiceConnection {
override fun onServiceConnected(className: ComponentName, service: IBinder) {
val binder = service as LocationService.LocalBinder
locationService = binder.getService()
bound = true
}
override fun onServiceDisconnected(arg0: ComponentName) {
bound = false
}
}
override fun onStart() {
super.onStart()
Intent(this, LocationService::class.java).also { intent ->
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE)
}
}
override fun onStop() {
super.onStop()
unbindService(serviceConnection)
bound = false
}