Search code examples
androidkotlinosmdroid

OSMDroid LocationChange Listener


I'm creating a map and I have a locationOverlay that works fine. However I need to update some variables as the location changes. Do I use a LocationListener with OSMDroid? Or is there something builtin or a method I can override? If I do have to register a locationListener, how do I go about that?

private fun createMap() {
        val ctx = applicationContext
        Configuration.getInstance().load(ctx, PreferenceManager.getDefaultSharedPreferences(ctx))

        map = findViewById<View>(R.id.map) as MapView
        map.setTileSource(TileSourceFactory.DEFAULT_TILE_SOURCE)
        map.getOverlays().add(CopyrightOverlay(this))
        mapController = MapController(map)
        mLocationOverlay = MyLocationNewOverlay(GpsMyLocationProvider(this), map)
        mLocationOverlay.enableMyLocation()
        mLocationOverlay.runOnFirstFix {
            runOnUiThread {
                mapController.zoomTo(14)
                mapController.setCenter(mLocationOverlay.myLocation)
                mapController.animateTo(mLocationOverlay.myLocation)
            }
        }

        map.overlays.add(mLocationOverlay)

    }

Solution

  • I found that your last known location is stored in the LocationOverlay. To access those variables: mLocationOverlay.myLocationProvider.lastKnownLocation.latitude and the same for longitude.

    Now that I knew where to get my location it was as simple as creating coroutines job to run ever second and update the deviceLocation variable.

    I'm sure there might be a better way by registering a listener. It would only fire when the location changes. However with coroutines you can control the interval. Giving the UI a more predictable look as long as the interval isn't too short.

    Make sure you have implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0' in your dependencies

    private fun createMap() {
        val ctx = applicationContext
        Configuration.getInstance().load(ctx, PreferenceManager.getDefaultSharedPreferences(ctx))
    
        map = findViewById<View>(R.id.map) as MapView
        map.setTileSource(TileSourceFactory.DEFAULT_TILE_SOURCE)
        map.getOverlays().add(CopyrightOverlay(this))
        mapController = MapController(map)
        mapController.animateTo(GeoPoint(DEFAULT_GEOPOINT), DEFAULT_ZOOM, 2)
        mLocationOverlay = MyLocationNewOverlay(GpsMyLocationProvider(this), map)
        mLocationOverlay.enableMyLocation()
        mLocationOverlay.runOnFirstFix {
            runOnUiThread {
                mapController.animateTo(mLocationOverlay.myLocation, 14.0, 1000)
                handleNewLocation()
                startLocationUpdates() // <-----Entry Point
            }
        }
        map.overlays.add(mLocationOverlay)
    }
    
    private fun startLocationUpdates() {
        val updateDeviceLocationJob = locationUpdateJob(1000L)
        updateDeviceLocationJob.start()
    }
    
    
    private fun locationUpdateJob(timeInterval: Long): Job {
        return CoroutineScope(Dispatchers.Default).launch {
            while (isActive) {
                handleNewLocation()
                delay(timeInterval)
            }
        }
    }
    
    private fun handleNewLocation() {
            deviceGoePoint = LatLng(mLocationOverlay.myLocationProvider.lastKnownLocation.latitude,
                mLocationOverlay.myLocationProvider.lastKnownLocation.longitude)
        }