Issue
i want to retrieve the current position and update the position of the user if he moves. I have a mapView within i create the map. Now my question is how can i retieve the user current position and if he moves the position is updated? I use googleApliclient and use Mapview because of the ApiLevel. I can retrieve permissions but sadly i dont know how to retrieve the user location and update this. Also code refinements are welcome.
class MapFragment : Fragment(), OnMapReadyCallback, GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener {
private var mapView: MapView? = null
private var gMap: GoogleMap? = null
private val LOCATION_PERMISSION_REQUEST_CODE = 1234
private lateinit var mapViewModel: MapViewModel
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
mapViewModel =
ViewModelProvider(this).get(MapViewModel::class.java)
val root = inflater.inflate(R.layout.fragment_map, container, false)
mapView = root.findViewById(R.id.mapView) as MapView
if (mapView != null) {
mapView!!.onCreate(null);
mapView!!.onResume();
mapView!!.getMapAsync(this);
checkLocationPermission();
}
checkLocationPermission();
return root
}
override fun onResume() {
super.onResume()
mapView?.onResume()
}
override fun onPause() {
super.onPause()
mapView?.onPause()
}
override fun onStart() {
super.onStart()
mapView?.onStart()
}
override fun onStop() {
super.onStop()
mapView?.onStop()
}
override fun onDestroy() {
super.onDestroy()
mapView?.onDestroy()
}
override fun onLowMemory() {
super.onLowMemory()
mapView?.onLowMemory()
}
override fun onMapReady(googleMap: GoogleMap) {
MapsInitializer.initialize(context)
gMap = googleMap
val coffeys = LatLng(52.075890, 4.309170)
gMap!!.addMarker(MarkerOptions().position(coffeys).title("coffeys"))
gMap!!.moveCamera(CameraUpdateFactory.newLatLngZoom(coffeys, 12f))
}
fun checkLocationPermission(): Boolean {
return if (ContextCompat.checkSelfPermission(
requireActivity(),
Manifest.permission.ACCESS_FINE_LOCATION
)
!= PackageManager.PERMISSION_GRANTED
) {
// Asking user if explanation is needed
if (ActivityCompat.shouldShowRequestPermissionRationale(
requireActivity(),
Manifest.permission.ACCESS_FINE_LOCATION
)
) {
//Prompt the user once explanation has been shown
requestPermissions(
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
LOCATION_PERMISSION_REQUEST_CODE
)
} else {
// No explanation needed, we can request the permission.
requestPermissions(
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
LOCATION_PERMISSION_REQUEST_CODE
)
}
false
} else {
true
}
}
override fun onConnected(p0: Bundle?) {
}
override fun onConnectionSuspended(p0: Int) {
TODO("Not yet implemented")
}
override fun onConnectionFailed(p0: ConnectionResult) {
TODO("Not yet implemented")
}
}
Solution
Use the fused location provider to retrieve the device's last known location.
private lateinit var fusedLocationClient: FusedLocationProviderClient
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// ...
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
}
To request the last known location and handle the response:
fusedLocationClient.lastLocation
.addOnSuccessListener { location : Location? ->
// Got last known location. In some rare situations this can be null.
}
This returns a Task that you can use to get a Location object with the latitude and longitude coordinates of a geographic location.
For more details: https://developer.android.com/training/location/request-updates
Update: Complete implementation
@SuppressLint("MissingPermission")
private fun getDeviceLocation() {
/*
* Get the best and most recent location of the device, which may be null in rare
* cases when a location is not available.
*/
try {
if (locationPermissionGranted) {
val locationResult = fusedLocationProviderClient.lastLocation
locationResult.addOnCompleteListener(requireActivity()) { task ->
if (task.isSuccessful) {
// Set the map's camera position to the current location of the device.
lastKnownLocation = task.result
if (lastKnownLocation != null) {
Timber.d("last known location $lastKnownLocation")
map.moveCamera(
CameraUpdateFactory.newLatLngZoom(
LatLng(
lastKnownLocation!!.latitude,
lastKnownLocation!!.longitude
), DEFAULT_ZOOM.toFloat()
)
)
} else {
Timber.e( "Exception: %s", task.exception)
map.moveCamera(
CameraUpdateFactory
.newLatLngZoom(defaultLocation, DEFAULT_ZOOM.toFloat())
)
map.uiSettings?.isMyLocationButtonEnabled = false
}
}
}
}
} catch (e: SecurityException) {
Timber.e("Exception: %s", e.message)
}
}
Update 2: Location updates
This code is from the official documentation, implemented for an activity. Should work well with fragments as well. Note: I have not tested this.
Call requestLocationUpdates()
, passing it your instance of the locationRequest
object, and a locationCallback
. Define a startLocationUpdates()
method as shown in the following code sample:
override fun onResume() {
super.onResume()
if (requestingLocationUpdates) startLocationUpdates()
}
private fun startLocationUpdates() {
fusedLocationClient.requestLocationUpdates(locationRequest,
locationCallback,
Looper.getMainLooper())
}
The fused location provider invokes the LocationCallback.onLocationResult()
callback method. The incoming argument contains a list Location object containing the location's latitude and longitude. The following snippet shows how to implement the LocationCallback
interface and define the method, then get the timestamp of the location update and display the latitude, longitude and timestamp on your app's user interface:
private lateinit var locationCallback: LocationCallback
// ...
override fun onCreate(savedInstanceState: Bundle?) {
// ...
locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult?) {
locationResult ?: return
for (location in locationResult.locations){
// Update UI with location data
// ...
}
}
}
}
To stop location updates, call removeLocationUpdates()
, passing it a locationCallback
, as shown in the following code sample:
override fun onPause() {
super.onPause()
stopLocationUpdates()
}
private fun stopLocationUpdates() {
fusedLocationClient.removeLocationUpdates(locationCallback)
}
A change to the device's configuration, such as a change in screen orientation or language, can cause the current activity to be destroyed. Your app must therefore store any information it needs to recreate the activity. One way to do this is via an instance state stored in a Bundle object.
The following code sample shows how to use the activity's onSaveInstanceState()
callback to save the instance state:
override fun onSaveInstanceState(outState: Bundle?) {
outState?.putBoolean(REQUESTING_LOCATION_UPDATES_KEY, requestingLocationUpdates)
super.onSaveInstanceState(outState)
}
Define an updateValuesFromBundle()
method to restore the saved values from the previous instance of the activity, if they're available. Call the method from the activity's onCreate()
method, as shown in the following code sample:
override fun onCreate(savedInstanceState: Bundle?) {
// ...
updateValuesFromBundle(savedInstanceState)
}
private fun updateValuesFromBundle(savedInstanceState: Bundle?) {
savedInstanceState ?: return
// Update the value of requestingLocationUpdates from the Bundle.
if (savedInstanceState.keySet().contains(REQUESTING_LOCATION_UPDATES_KEY)) {
requestingLocationUpdates = savedInstanceState.getBoolean(
REQUESTING_LOCATION_UPDATES_KEY)
}
// ...
// Update UI to match restored state
updateUI()
}
For a more persistent storage, you can store the user's preferences in your app's SharedPreferences
. Set the shared preference in your activity's onPause()
method, and retrieve the preference in onResume()
Answered By - Varsha Kulkarni
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.