I am developing a tracking application which tracks the path taken by user and plots a polyline on that
I am trying to add marker at certain position while tracking but the marker is not showing on the map
I have added the marker in onMapReady method but still it is not visible on the map
My source code
class MapsActivity : AppCompatActivity(), OnMapReadyCallback {
private var lastKnownLocation: Location? = null
private var locationPermissionGranted: Boolean = false
private lateinit var placesClient: PlacesClient
private lateinit var mMap: GoogleMap
private lateinit var binding: ActivityMapsBinding
private lateinit var fusedLocationProviderClient: FusedLocationProviderClient
private val PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION = 121
private val REQUEST_CODE_ACTIVITY_RECOGNITION: Int = 0
val polylineOptions = PolylineOptions()
private val mapsActivityViewModel: MapsActivityViewModel by viewModels {
MapsActivityViewModelFactory(getTrackingRepository())
}
private fun getTrackingApplicationInstance() = application as TrackingApplication
private fun getTrackingRepository() = getTrackingApplicationInstance().trackingRepository
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMapsBinding.inflate(layoutInflater)
setContentView(binding.root)
val mapFragment = supportFragmentManager
.findFragmentById(R.id.map) as SupportMapFragment
mapFragment.getMapAsync(this)
Places.initialize(applicationContext, getString(R.string.maps_api_key))
placesClient = Places.createClient(this)
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this)
val isActivityRecognitionPermissionFree = Build.VERSION.SDK_INT < Build.VERSION_CODES.Q
val isActivityRecognitionPermissionGranted = EasyPermissions.hasPermissions(
this,
Manifest.permission.ACTIVITY_RECOGNITION
)
mapsActivityViewModel.lastTrackingEntity.observe(this) { lastTrackingEntity ->
lastTrackingEntity ?: return#observe
addLocationToRoute(lastTrackingEntity)
}
if (isActivityRecognitionPermissionFree || isActivityRecognitionPermissionGranted) {
setupLocationChangeListener()
} else {
EasyPermissions.requestPermissions(
host = this,
rationale = "For showing your step counts and calculate the average pace.",
requestCode = REQUEST_CODE_ACTIVITY_RECOGNITION,
perms = *arrayOf(Manifest.permission.ACTIVITY_RECOGNITION)
)
}
}
private fun addLocationToRoute(lastTrackingEntity: TrackingEntity) {
mMap.clear()
val newLatLng = lastTrackingEntity.asLatLng()
polylineOptions.points.add(newLatLng)
mMap.addPolyline(polylineOptions)
}
override fun onMapReady(googleMap: GoogleMap) {
mMap = googleMap
getLocationPermission()
updateLocationUI()
getDeviceLocation()
mMap.addMarker(
MarkerOptions().position(LatLng(16.667421, 74.819688))
.title("Marker in Sydney")
.icon(
BitmapDescriptorFactory
.defaultMarker(BitmapDescriptorFactory.HUE_GREEN)
)
)
}
val locationcallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
super.onLocationResult(locationResult)
locationResult.locations.forEach {
val trackingEntity =
TrackingEntity(Calendar.getInstance().timeInMillis, it.latitude, it.longitude)
mapsActivityViewModel.insert(trackingEntity)
}
}
}
private fun setupLocationChangeListener() {
if (EasyPermissions.hasPermissions(this, Manifest.permission.ACCESS_FINE_LOCATION)) {
val locationRequest = com.google.android.gms.location.LocationRequest()
locationRequest.priority =
com.google.android.gms.location.LocationRequest.PRIORITY_HIGH_ACCURACY
locationRequest.interval = 5000 // 5000ms (5s)
if (ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
return
}
fusedLocationProviderClient.requestLocationUpdates(
locationRequest,
locationcallback,
Looper.getMainLooper()
)
} else {
getLocationPermission()
}
}
#SuppressLint("MissingPermission")
private fun updateLocationUI() {
try {
if (locationPermissionGranted) {
mMap.isMyLocationEnabled = true
mMap.uiSettings.isMyLocationButtonEnabled = true
} else {
mMap.isMyLocationEnabled = false
mMap.uiSettings.isMyLocationButtonEnabled = false
lastKnownLocation = null
getLocationPermission()
}
} catch (e: SecurityException) {
Log.e("Exception: %s", e.message, e)
}
}
#SuppressLint("MissingPermission")
private fun getDeviceLocation() {
try {
if (locationPermissionGranted) {
val locationResult = fusedLocationProviderClient.lastLocation
locationResult.addOnCompleteListener(this) { task ->
if (task.isSuccessful) {
lastKnownLocation = task.result
if (lastKnownLocation != null) {
mMap.moveCamera(
CameraUpdateFactory.newLatLngZoom(
LatLng(
lastKnownLocation!!.latitude,
lastKnownLocation!!.longitude
), 18.0F
)
)
}
} else {
val sydney = LatLng(-34.0, 151.0)
Log.d(TAG, "Current location is null. Using defaults.")
Log.e(TAG, "Exception: %s", task.exception)
mMap.moveCamera(
CameraUpdateFactory
.newLatLngZoom(sydney, 18.0F)
)
mMap.uiSettings.isMyLocationButtonEnabled = false
}
}
}
} catch (e: SecurityException) {
Log.e("Exception: %s", e.message, e)
}
}
private fun getLocationPermission() {
if (ContextCompat.checkSelfPermission(
this.applicationContext,
Manifest.permission.ACCESS_FINE_LOCATION
)
== PackageManager.PERMISSION_GRANTED
) {
locationPermissionGranted = true
} else {
ActivityCompat.requestPermissions(
this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION
)
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
locationPermissionGranted = false
when (requestCode) {
PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION -> {
if (grantResults.isNotEmpty() &&
grantResults[0] == PackageManager.PERMISSION_GRANTED
) {
locationPermissionGranted = true
}
}
}
updateLocationUI()
}
}
Related
In my app my geofence does not update my firebase database when I enter the area. I made sure my code for updating the database works so that is not the problem. Also, when I enter the geofence my activity crashes. I’m going to add all my code for getting my location, the geofence and my broadcast.
Maps activity
class PricklyMapsActivity : AppCompatActivity(), OnMapReadyCallback {
lateinit var toggle: ActionBarDrawerToggle
//location
private lateinit var fusedLocatonClient: FusedLocationProviderClient
private lateinit var myLatlng: LatLng
private lateinit var currentLocation: Location
private val permissionId = 5
//Map
private lateinit var map: GoogleMap
private lateinit var binding: ActivityPricklyMapsBinding
//Goefence
private var gadgetQ = android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q
private lateinit var geoClient: GeofencingClient
var geofenceList: MutableList<Geofence> = mutableListOf()
//firebase
private lateinit var database: DatabaseReference
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityPricklyMapsBinding.inflate(layoutInflater)
setContentView(binding.root)
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
val mapFragment = supportFragmentManager
.findFragmentById(R.id.map) as SupportMapFragment
mapFragment.getMapAsync(this)
fusedLocatonClient = LocationServices.getFusedLocationProviderClient(this)
//drawer create and in actions
val drawerLayout: DrawerLayout = findViewById(R.id.draweLayout)
val navWiew: NavigationView = findViewById(R.id.nav_view)
toggle = ActionBarDrawerToggle(this#PricklyMapsActivity, drawerLayout, R.string.open, R.string.close)
drawerLayout.addDrawerListener(toggle)
toggle.syncState()
supportActionBar?.setDisplayHomeAsUpEnabled(true)
navWiew.setNavigationItemSelectedListener {
when (it.itemId){
R.id.Home -> showActivityHome()
R.id.Map -> Toast.makeText(applicationContext, "Alredy at the Map", Toast.LENGTH_SHORT).show()
}
true
}
//drawer create end
//Geofence
geoClient = LocationServices.getGeofencingClient(this)
//add geofences here
val latatude = -26.694340
val longatude = 27.083960
val radius = 10f
geofenceList.add(Geofence.Builder()
.setRequestId("Toets")
.setCircularRegion(latatude,longatude,radius)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER)
.build())
}
override fun onDestroy() {
super.onDestroy()
removeGeofence()
}
override fun onMapReady(googleMap: GoogleMap) {
map = googleMap
getCurrentLocation()
val placeName = arrayOf<String>("Texas")
val lataltude = arrayOf<Double>(-26.694340)
val longatude = arrayOf<Double>(27.083960)
for (i in 0..placeName.size-1){
val x = placeName[i]
val y = lataltude[i]
val z = longatude[i]
addCircle(x, y, z)
}
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if(toggle.onOptionsItemSelected(item)){
return true
}
return super.onOptionsItemSelected(item)
}
//go to the home activity
private fun showActivityHome(){
val intent1 = Intent(this#PricklyMapsActivity, MainActivity::class.java)
startActivity(intent1)
}
private fun addCircle(Name: String, latatude: Double, longatude: Double){
val radius = 10.00
val latLng = LatLng(latatude,longatude)
map.addCircle(
CircleOptions()
.radius(radius)
.center(latLng)
.strokeColor(Color.argb(150,173,216,230))
.fillColor(Color.argb(100, 173, 216, 230))
)
}
//Geofence pending intent
private val geofenceIntent: PendingIntent by lazy {
val intent = Intent(this, GeofenceBrodcastReceiver::class.java)
intent.action = ACTION_GEOFENCE_EVENT
PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT)
}
companion object{
internal const val ACTION_GEOFENCE_EVENT =
"PricklyMapsActivity.pricklypear.action.ACTION_GEOFENCE_EVENT"
}
//Specifies the geofence
private fun seekGeofencing(): GeofencingRequest {
return GeofencingRequest.Builder().apply {
setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER)
addGeofences(geofenceList)
}.build()
}
//adds the geofence or geofences
#SuppressLint("MissingPermission")
private fun addGeofence(){
if (ActivityCompat.checkSelfPermission(this,
android.Manifest.permission.ACCESS_FINE_LOCATION
) != PERMISSION_GRANTED){
return
}
geoClient?.addGeofences(seekGeofencing(), geofenceIntent)?.run {
addOnSuccessListener {
Toast.makeText(this#PricklyMapsActivity, "Geofence(s) added", Toast.LENGTH_LONG).show()
}
addOnFailureListener {
Toast.makeText(this#PricklyMapsActivity, "Failed to add geofence(s)", Toast.LENGTH_LONG).show()
}
}
}
//Removing geofences
private fun removeGeofence(){
geoClient?.removeGeofences(geofenceIntent)?.run {
addOnSuccessListener {
Toast.makeText(this#PricklyMapsActivity, "Geofences removed", Toast.LENGTH_SHORT).show()
}
addOnFailureListener {
Toast.makeText(this#PricklyMapsActivity, "Failed to remove geofences", Toast.LENGTH_SHORT).show()
}
}
}
//From here and down it is getting location and permition
#SuppressLint("MissingPermission", "NewApi")
private fun getCurrentLocation(){
if (checkPermission()){
if (isLocationEnabled()){
map.isMyLocationEnabled = true
fusedLocatonClient.lastLocation.addOnCompleteListener(this){ task ->
val location: Location?=task.result
if (location==null){
Toast.makeText(this,
"Location may still be turning on pleas wate a while",
Toast.LENGTH_SHORT).show()
}else {
currentLocation = location
myLatlng = LatLng(location.latitude, location.longitude)
map.animateCamera(CameraUpdateFactory.newLatLngZoom(myLatlng, 18f))
addGeofence()
}
Looper.myLooper()
}
}else{
//open settings if location is not enabled
Toast.makeText(this, "Pleas turn on location", Toast.LENGTH_SHORT).show()
val intent = Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)
startActivity(intent)
}
}else{
//requests permition if permition is not granted
requestPermissions()
}
}
//Checker for if the laocation is enabled return boolean
private fun isLocationEnabled(): Boolean{
val locationManager: LocationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
return locationManager
.isProviderEnabled(LocationManager.GPS_PROVIDER) || locationManager
.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
}
//Checker for if the location permission is enabled return boolean
#TargetApi(29)
private fun checkPermission(): Boolean{
if (ActivityCompat.checkSelfPermission(this,
android.Manifest.permission.ACCESS_COARSE_LOCATION) ==
PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this,
android.Manifest.permission.ACCESS_FINE_LOCATION) ==
PERMISSION_GRANTED){
if (gadgetQ){
if (ActivityCompat.checkSelfPermission(this,
android.Manifest.permission.ACCESS_BACKGROUND_LOCATION) ==
PERMISSION_GRANTED) {
return true
}
}else {
return true
}
}
return false
}
private fun requestPermissions(){
ActivityCompat.requestPermissions(this,
arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION,
android.Manifest.permission.ACCESS_COARSE_LOCATION), permissionId
//android.Manifest.permission.ACCESS_BACKGROUND_LOCATION), permissionId
)
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == permissionId){
if (grantResults.isNotEmpty() && grantResults[0] == PERMISSION_GRANTED){
getCurrentLocation()
}else{
Toast.makeText(this, "location is not granted", Toast.LENGTH_SHORT).show()
}
}
}
}
Brodcast receiver Class
class GeofenceBrodcastReceiver: BroadcastReceiver() {
private lateinit var database: DatabaseReference
override fun onReceive(context: Context?, intent: Intent?) {
val geofencingEvent = GeofencingEvent.fromIntent(intent!!)
val geofencingTransition = geofencingEvent!!.geofenceTransition
if (geofencingTransition == Geofence.GEOFENCE_TRANSITION_ENTER) {
database = FirebaseDatabase.getInstance().getReference("Texas")
database.child("Count").get().addOnSuccessListener {
if (it.exists()) {
var number = it.getValue(Long::class.java)
if (number is Long){
number += 1
val post =mapOf<String, Long>("Count" to number)
database.updateChildren(post)
}
} else {
Log.e(TAG, "Invalid type transition")
}
}.addOnFailureListener {
Log.e(TAG, "Invalid type transition")
}
}
}
}
At the pending intent I tried changing the type, but it did not work. I have looked every ware and as far as I can tell there is no problem with my code, and it should work so if someone can help me it would be much appreciated.
This code belongs to a fragment which shows the user's current location.After getting location when I want to go back to previous fragment App crashes.Logcat says error is happening here :
"val geocoder = Geocoder(requireContext(), Locale.getDefault())"
If anyone could assist me, I would greatly appreciate it
class LocationFragment : DialogFragment(), OnMapReadyCallback {
lateinit var binding: FragmentLocationBinding
private lateinit var map: GoogleMap
private val REQUEST_LOCATION_PERMISSION = 1
var lat: Double = 0.0
var long: Double = 0.0
private lateinit var fusedLocationProviderClient: FusedLocationProviderClient
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentLocationBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val policy = StrictMode.ThreadPolicy.Builder().permitAll().build()
StrictMode.setThreadPolicy(policy)
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(requireContext())
enableMyLocation()
binding.apply {
prgBar.visibility=View.VISIBLE
btnSaveLocation.setOnClickListener {
dismiss()
}
val mapFragment = childFragmentManager
.findFragmentById(R.id.map) as SupportMapFragment
mapFragment.getMapAsync(this#LocationFragment)
}
}
override fun onStart() {
super.onStart()
val dialog: Dialog? = dialog
if (dialog != null) {
dialog.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
//dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
}
}
override fun onMapReady(p0: GoogleMap) {
map = p0
}
private fun isPermissionGranted(): Boolean {
return ContextCompat.checkSelfPermission(
requireContext(),
Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED
}
#SuppressLint("VisibleForTests")
private fun checkDeviceLocationSettings(resolve: Boolean = true) {
val locationRequest = LocationRequest.create().apply {
priority = LocationRequest.PRIORITY_LOW_POWER
}
val requestBuilder = LocationSettingsRequest.Builder().addLocationRequest(locationRequest)
val settingsClient = LocationServices.getSettingsClient(requireActivity())
val locationSettingsResponseTask =
settingsClient.checkLocationSettings(requestBuilder.build())
locationSettingsResponseTask.addOnFailureListener { exception ->
if (exception is ResolvableApiException && resolve) {
try {
exception.startResolutionForResult(
requireActivity(),
REQUEST_TURN_DEVICE_LOCATION_ON
)
} catch (sendEx: IntentSender.SendIntentException) {
Log.d(TAG, "Error getting location settings resolution: " + sendEx.message)
}
} else {
Snackbar.make(
binding.root,
R.string.location_required_error, Snackbar.LENGTH_INDEFINITE
).setAction(android.R.string.ok) {
checkDeviceLocationSettings()
}.show()
}
}
}
#TargetApi(Build.VERSION_CODES.Q)
private fun requestQPermission() {
val hasForegroundPermission = ActivityCompat.checkSelfPermission(
requireContext(),
Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED
if (hasForegroundPermission) {
val hasBackgroundPermission = ActivityCompat.checkSelfPermission(
requireContext(),
Manifest.permission.ACCESS_BACKGROUND_LOCATION
) == PackageManager.PERMISSION_GRANTED
if (hasBackgroundPermission) {
checkDeviceLocationSettings()
} else {
ActivityCompat.requestPermissions(
requireActivity(),
arrayOf(Manifest.permission.ACCESS_BACKGROUND_LOCATION),
REQUEST_CODE_BACKGROUND
)
}
}
}
private fun enableMyLocation() {
if (isPermissionGranted()) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
checkDeviceLocationSettings()
} else {
requestQPermission()
}
updateLocation()
} else {
ActivityCompat.requestPermissions(
context as Activity,
arrayOf<String>(Manifest.permission.ACCESS_FINE_LOCATION),
REQUEST_LOCATION_PERMISSION
)
}
}
private fun updateLocation() {
if (ActivityCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission
(requireContext(), Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED
) {
return
}
fusedLocationProviderClient.requestLocationUpdates(
locationRequest(), locationCallback,
Looper.myLooper()
)
}
private fun locationRequest(): LocationRequest {
return LocationRequest.Builder(Priority.PRIORITY_HIGH_ACCURACY, 3000)
.setWaitForAccurateLocation(false)
.setMinUpdateIntervalMillis(5000)
.setMaxUpdateDelayMillis(5000)
.build()
}
private var locationCallback = object : LocationCallback() {
override fun onLocationResult(p0: LocationResult) {
val location: Location? = p0.lastLocation
if (location != null) {
updateAddressUI(location)
}
}
}
#SuppressLint("MissingPermission")
fun updateAddressUI(location: Location) {
map.isMyLocationEnabled = true
val addressList: ArrayList<Address>
val geocoder = Geocoder(requireContext(), Locale.getDefault()) //Getting error here
addressList = geocoder.getFromLocation(
location.latitude,
location.longitude,
1
) as ArrayList<Address>
lat = addressList[0].latitude
long = addressList[0].longitude
binding.prgBar.visibility=View.INVISIBLE
Toast.makeText(requireContext(), "$lat \n $long", Toast.LENGTH_SHORT).show()
val latLng = LatLng(lat, long)
val markerOptions = MarkerOptions().position(latLng).title("I am here!")
map.animateCamera(CameraUpdateFactory.newLatLng(latLng))
map.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, 15f))
map.addMarker(markerOptions)?.setIcon(bitmapFromVector(requireContext(),R.drawable.baseline_emoji_people_24))
}
private fun bitmapFromVector(context: Context, vectorResId: Int): BitmapDescriptor? {
val vectorDrawable = ContextCompat.getDrawable(context, vectorResId)
vectorDrawable!!.setBounds(0, 0, vectorDrawable.intrinsicWidth, vectorDrawable.intrinsicHeight)
val bitmap = Bitmap.createBitmap(vectorDrawable.intrinsicWidth, vectorDrawable.intrinsicHeight, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
vectorDrawable.draw(canvas)
return BitmapDescriptorFactory.fromBitmap(bitmap)
}
override fun onResume() {
super.onResume()
enableMyLocation()
}
}
I used 'requireActivity' instead of 'requireContext' but didn't work
As you said, beacuse the crash happens when you go back to the previous fragment, probably the locationCallback getting called when the current fragment is detached from the activity. Inside the updateAddressUI you are getting the context in that momment when your view is detached.
If is ok with your logic you can keep the context reference inside the callBack object and work with this.
Try to change the locationCallback to and pass the context to the updateAddressUI function.
private var locationCallback = object : LocationCallback() {
val context = requireContext()
override fun onLocationResult(p0: LocationResult) {
val location: Location? = p0.lastLocation
if (location != null) {
updateAddressUI(location, context)
}
}
}
Change also the updateAddressUI function like this.
#SuppressLint("MissingPermission")
fun updateAddressUI(location: Location, context: Context) {
map.isMyLocationEnabled = true
val addressList: ArrayList<Address>
val geocoder = Geocoder(context, Locale.getDefault()) //Getting error here
addressList = geocoder.getFromLocation(
location.latitude,
location.longitude,
1
) as ArrayList<Address>
lat = addressList[0].latitude
long = addressList[0].longitude
binding.prgBar.visibility=View.INVISIBLE
Toast.makeText(context, "$lat \n $long", Toast.LENGTH_SHORT).show()
val latLng = LatLng(lat, long)
val markerOptions = MarkerOptions().position(latLng).title("I am here!")
map.animateCamera(CameraUpdateFactory.newLatLng(latLng))
map.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, 15f))
map.addMarker(markerOptions)?.setIcon(bitmapFromVector(context,R.drawable.baseline_emoji_people_24))
}
I changed the code in this way :
val geocoder = context?.let { Geocoder(it, Locale.getDefault()) }
in this methode :
fun updateAddressUI(location: Location) {
map.isMyLocationEnabled = true
val addressList: ArrayList<Address>
val geocoder = context?.let { Geocoder(it, Locale.getDefault()) }
if (geocoder != null) {
addressList = geocoder.getFromLocation(
location.latitude,
location.longitude,
1
) as ArrayList<Address>
lat = addressList[0].latitude
long = addressList[0].longitude
}
I am developing location based android app using google maps but when I run project I am getting crash and getting following exception java.lang.IllegalStateException: Fragment MapFragment{2fe7116} (69b05d78-5cf3-46a9-829c-6b6507944575) not attached to an activity.
at androidx.fragment.app.Fragment.requireActivity(Fragment.java:995)
I am getting exception in following function in my MapFragment
#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) {
map.moveCamera(
CameraUpdateFactory.newLatLngZoom(
LatLng(
lastKnownLocation!!.latitude,
lastKnownLocation!!.longitude
), DEFAULT_ZOOM.toFloat()
)
)
} else {
gotoDefaultLocation()
}
} else {
Log.d(TAG, "Current location is null. Using defaults.")
Log.e(TAG, "Exception: %s", task.exception)
gotoDefaultLocation()
}
}
}
} catch (e: SecurityException) {
MakeToast("Standort Zugriff leider nicht erlaubt")
Log.e("Exception: %s", e.message, e)
}
}
I have followed all stackoverflow answer it did not solve my problem
I have tried following stackoverflow answer as well java.lang.IllegalStateException: Fragment not attached to Activity I want to know where exactly I am making mistake
below My Full MapFragment.kt
#AndroidEntryPoint
class MapFragment : Fragment(), OnMapReadyCallback, GoogleMap.OnMarkerClickListener,
GoogleMap.OnInfoWindowClickListener {
private val binding by lazy { MapFragmentBinding.inflate(layoutInflater) }
private var locationPermissionGranted: Boolean = false
// private var mMap: MapView? = null
private lateinit var map: GoogleMap
private val cafMarker: MutableList<CafMarker> = mutableListOf()
private val viewModel by viewModels<MapViewModel>()
#Inject
lateinit var sharedPref: SharedPref
// Declare a variable for the cluster manager.
private lateinit var clusterManager: ClusterManager<CafMarker>
private val markerAdapter by lazy { MarkerAdapter() }
private lateinit var dialogMarker: Dialog
private var isRegistered: Boolean = false
// The entry point to the Places API.
private lateinit var placesClient: PlacesClient
private var lastKnownLocation: Location? = null
private var cameraPosition: CameraPosition? = null
// The entry point to the Fused Location Provider.
private lateinit var fusedLocationProviderClient: FusedLocationProviderClient
private val defaultLocation = LatLng(51.1633611, 10.4476833)
lateinit var CurrentChargePoint: ChargePoint
lateinit var cp: ChargePoint
private var ChargePoints: MutableList<ChargePoint> = mutableListOf<ChargePoint>()
private val TAG = "MapFragment"
private lateinit var activityContext: Context
companion object {
fun newInstance() = MapFragment()
val REQUEST_CODE_LOCATION = 32
private const val COUNTRY_ZOOM = 5.85
private const val DEFAULT_ZOOM = 15
private const val PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION = 1
private const val KEY_CAMERA_POSITION = "camera_position"
private const val KEY_LOCATION = "location"
private const val M_MAX_ENTRIES = 5
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
Log.d("setNavigationToken", "setNavigation: ${sharedPref.token}")
activityContext = requireContext()
binding.mapView.onCreate(savedInstanceState)
binding.mapView.getMapAsync(this)
binding.mapView.setOnClickListener(clickListener)
binding.gotoBookingButton.setOnClickListener(clickListener);
binding.StationInfo.isVisible = false;
createChannel("caf", "alarm")
if (savedInstanceState != null) {
lastKnownLocation = savedInstanceState.getParcelable(KEY_LOCATION)
cameraPosition = savedInstanceState.getParcelable(KEY_CAMERA_POSITION)
}
binding.qrButton.setOnClickListener(clickListener)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel.map(sharedPref.token)
Log.d("onViewCreatedToken", "onViewCreated: ${sharedPref.token}")
}
val clickListener = View.OnClickListener { view ->
when (view.getId()) {
// R.id.gotoBookingButton -> {
// appCommon.CurrentChargePoint = CurrentChargePoint
// if (sharedPref.token.length > 0) {
// Log.d("#######", ": $sharedPref")
//// appCommon.isAdhocBooking = false
// findNavController().navigate(R.id.navigation_reserve)
// } else {
// findNavController().navigate(R.id.navigation_settings_login)
// }
// }
R.id.mapView -> {
binding.StationInfo.isVisible = false
}
R.id.qrButton -> {
findNavController().navigate(R.id.activity_qr)
}
}
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
binding.mapView.onSaveInstanceState(outState)
}
#SuppressLint("MissingPermission")
override fun onMapReady(googleMap: GoogleMap) {
map = googleMap
gotoDefaultLocation()
if (ActivityCompat.checkSelfPermission(
requireContext(),
Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
requireContext(),
Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
ActivityCompat.requestPermissions(
requireActivity(), arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
REQUEST_CODE_LOCATION
)
return
}
locationPermissionGranted = true
map.isMyLocationEnabled = true;
//gMap.addMarker(MarkerOptions().position(devDefault).title("Hier bin ich"))
updateLocationUI()
getDeviceLocation()
map.setOnMarkerClickListener(this)
getChargePoints()
// FetchChargePoints()
}
val broadCastReceiver = object : BroadcastReceiver() {
override fun onReceive(contxt: Context?, intent: Intent?) {
when (intent?.action) {
SET_MAP_PERMISSIONS -> {
if (intent.extras?.get("result")?.toString()!!
.toInt() == PackageManager.PERMISSION_GRANTED
) {
locationPermissionGranted = true
updateLocationUI()
getDeviceLocation()
getChargePoints()
}
}
// BROADCAST_CHANGE_TYPE_CHANGED -> handleChangeTypeChanged()
}
}
}
#SuppressLint("MissingPermission")
private fun updateLocationUI() {
if (map == null) {
return
}
try {
if (locationPermissionGranted) {
map.isMyLocationEnabled = true
map.uiSettings.isMyLocationButtonEnabled = true
} else {
map.isMyLocationEnabled = false
map.uiSettings.isMyLocationButtonEnabled = false
lastKnownLocation = null
getLocationPermission()
}
} catch (e: SecurityException) {
Log.e("Exception: %s", e.message, e)
}
}
private fun getLocationPermission() {
/*
* Request location permission, so that we can get the location of the
* device. The result of the permission request is handled by a callback,
* onRequestPermissionsResult.
*/
if (ContextCompat.checkSelfPermission(
requireContext(),
Manifest.permission.ACCESS_FINE_LOCATION
)
== PackageManager.PERMISSION_GRANTED
) {
locationPermissionGranted = true
updateLocationUI()
} else {
ActivityCompat.requestPermissions(
requireActivity(), arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION
)
}
}
#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) {
map.moveCamera(
CameraUpdateFactory.newLatLngZoom(
LatLng(
lastKnownLocation!!.latitude,
lastKnownLocation!!.longitude
), DEFAULT_ZOOM.toFloat()
)
)
} else {
gotoDefaultLocation()
}
} else {
Log.d(TAG, "Current location is null. Using defaults.")
Log.e(TAG, "Exception: %s", task.exception)
gotoDefaultLocation()
}
}
}
} catch (e: SecurityException) {
MakeToast("Standort Zugriff leider nicht erlaubt")
Log.e("Exception: %s", e.message, e)
}
}
private fun gotoDefaultLocation() {
map.moveCamera(
CameraUpdateFactory
.newLatLngZoom(defaultLocation, COUNTRY_ZOOM.toFloat())
)
map.uiSettings.isMyLocationButtonEnabled = false
}
private fun MakeToast(text: String) {
val toast = text
Toast.makeText(
activity?.applicationContext,
toast,
Toast.LENGTH_SHORT
).show()
}
override fun onResume() {
super.onResume()
registerReceiver()
binding.mapView.onResume()
}
override fun onPause() {
super.onPause()
binding.mapView.onPause()
}
override fun onStart() {
super.onStart()
registerReceiver()
binding.mapView.onStart()
}
override fun onStop() {
super.onStop()
LocalBroadcastManager.getInstance(requireContext()).unregisterReceiver(broadCastReceiver)
binding.mapView.onStop()
}
override fun onDestroy() {
super.onDestroy()
// binding.mapView.onDestroy()
}
private fun registerReceiver() {
if (!isRegistered) {
val filter = IntentFilter()
filter.addAction(SET_MAP_PERMISSIONS)
// filter.addAction(END_PAYMENT)
LocalBroadcastManager.getInstance(requireContext())
.registerReceiver(broadCastReceiver, filter)
isRegistered = true
}
}
override fun onMarkerClick(p0: Marker): Boolean {
getCPs(p0)
UseCpInfo()
return true
}
private fun UseCpInfo() {
if (this::cp.isInitialized) {
CurrentChargePoint = cp // it means
// binding.StationInfo.isVisible = true
// val streetName = binding.StationInfo.findViewById(R.id.textViewStreet) as TextView
// val stationCity = binding.StationInfo.findViewById(R.id.textViewCity) as TextView
// val stationName = binding.StationInfo.findViewById(R.id.textViewStationName) as TextView
// stationName.text = cp.getCpLocName()
// streetName.text = cp.getStreetName()
// stationCity.text = cp.getCityName()
// Log.d("MapFragmentAdhok", "UseCpInfo: ${cp.hasType(ChargePointType.AdHoc)}")
// if (cp.hasType(ChargePointType.AdHoc)) {
// binding.textViewAvailability.text = "nur Direktladen, " + cp.Tarif + " Ct/kWh"
// } else if (cp.Available) {
// binding.textViewAvailability.text =
// String.format(Locale.GERMAN, "%.0f", cp.Tarif) + " Ct/kWh - " + String.format(
// Locale.GERMAN,
// "%.1f",
// cp.Power
// ) + " kW"
// } else {
// binding.textViewAvailability.text = "belegt, " + String.format(
// Locale.GERMAN,
// "%.0f",
// cp.Tarif
// ) + " Ct/kWh - " + String.format(Locale.GERMAN, "%.1f", cp.Power) + " kW"
// }
} else {
MakeToast("Station leider nicht verfügbar")
}
}
private fun getCPs(p0: Marker) {
for (i in 0 until ChargePoints.size) {
if (ChargePoints[i].id == p0.id) {
cp = ChargePoints[i]
}
}
}
private fun getCPsByCafMarker(p0: CafMarker) {
for (i in 0 until ChargePoints.size) {
if (ChargePoints[i].Guid == p0.GetId()) {
cp = ChargePoints[i]
}
}
}
private fun getChargePoints() {
viewLifecycleOwner.lifecycleScope.launchWhenCreated {
viewModel.map.collect {
when (it) {
is UiStateList.LOADING -> {
}
is UiStateList.SUCCESS -> {
Log.d("MapFragmentCharge", "getChargePoint: ${it.data}")
appCommon.setChargePoints(it.data)
setUpClusterer()
}
is UiStateList.ERROR -> {
Log.d(TAG, "getChargePoints: ${it.message}")
Toast.makeText(requireContext(), it.message, Toast.LENGTH_SHORT).show()
}
}
}
}
}
private fun setUpClusterer() {
val markersList = ArrayList<CafMarker>()
clusterManager = ClusterManager<CafMarker>(activityContext, map)
clusterManager.renderer = MapRenderer(activityContext, map, clusterManager)
Log.d(TAG, "setUpClusterer: ${clusterManager.markerCollection}")
map.setOnCameraIdleListener(clusterManager)
map.setOnMarkerClickListener(clusterManager)
map.setOnInfoWindowClickListener(clusterManager)
clusterManager.setOnClusterItemClickListener {
getCPsByCafMarker(it)
UseCpInfo()
CurrentChargePoint = cp
appCommon.CurrentChargePoint = CurrentChargePoint
appCommon.isAdhocBooking = CurrentChargePoint.hasType(ChargePointType.AdHoc)
if (!appCommon.CurrentChargePoint.hasType(ChargePointType.Manual) and !appCommon.CurrentChargePoint.hasType(ChargePointType.Calibrated)) {
Log.d("updateAccessProfileUIReserve", "addItems: ")
appCommon.CurrentChargePoint.hasType(ChargePointType.Calibrated)
}
// appCommon.isCalibrated = CurrentChargePoint.hasType(ChargePointType.Calibrated)
Log.d("TAGsetUpClusterer", "setUpClusterer: $cp")
Log.d(TAG, "setUpClusterer: $CurrentChargePoint")
if (sharedPref.token.length > 0) {
Log.d("#######", ": $sharedPref")
// appCommon.isAdhocBooking = false
findNavController().navigate(R.id.navigation_reserve)
} else {
findNavController().navigate(R.id.navigation_settings_login)
}
true
}
clusterManager.setOnClusterClickListener { cluster ->
// Add ten cluster items in close proximity, for purposes of this example.
val items: List<ChargePoint> = appCommon.getChargePoints()
var available = ""
var tarif = ""
var kW = ""
for (i in cluster.items) {
for (k in 0 until items.size) {
val cp: ChargePoint = items[k]
if (cp.Guid == i.GetId()) {
if (cp.hasType(ChargePointType.AdHoc) == false) {
Log.d("ChargePointBall", "Tarif: ${cp.Tarif}")
available =
requireContext().getResources().getString(R.string.available) + ":"
tarif = cp.Tarif.toInt().toString() + " Ct/kWh"
kW = cp.Power.toString() + " kW"
} else {
available = requireContext().getResources()
.getString(R.string.not_reservable) + ":"
tarif = cp.Tarif.toInt().toString() + " Ct/kWh"
kW = cp.Power.toString() + " kW"
}
}
}
val markerModel = CafMarker(
i.position.latitude,
i.position.longitude,
i.GetId(),
i.title,
i.snippet,
null,
available,
tarif,
kW
)
markersList.add(markerModel)
}
markerAdapter.submitData(markersList)
if (markersList.size > 0) {
showProfessionsDialog()
markersList.clear()
markerAdapter.itemClickListener = {
getCPsByCafMarker(it)
UseCpInfo()
CurrentChargePoint = cp
appCommon.CurrentChargePoint = CurrentChargePoint
Log.d("TAGsetUpClusterer", "setUpClusterer: $cp")
Log.d(TAG, "setUpClusterer: $CurrentChargePoint")
dialogMarker.dismiss()
if (sharedPref.token.length > 0) {
Log.d("#######", ": $sharedPref")
// appCommon.isAdhocBooking = false
findNavController().navigate(R.id.navigation_reserve)
} else {
findNavController().navigate(R.id.navigation_settings_login)
}
map.moveCamera(
CameraUpdateFactory.newLatLngZoom(
LatLng(
it.position.latitude, it.position.longitude
), DEFAULT_ZOOM.toFloat()
)
)
}
}
Log.d(TAG, "setUpClusterer: clicked")
map.animateCamera(
CameraUpdateFactory.newLatLngZoom(
cluster.getPosition(),
Math.floor((map.cameraPosition.zoom + 1).toDouble()).toFloat()
), 300, null
)
true
}
addItems()
getDeviceLocation()
}
private fun showProfessionsDialog() {
dialogMarker = Dialog(requireContext())
val binding = DialogMarkersBinding.inflate(layoutInflater)
dialogMarker.setContentView(binding.root)
dialogMarker.setCancelable(true)
dialogMarker.window!!.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
binding.rvMarkers.adapter = markerAdapter
dialogMarker.show()
}
override fun onInfoWindowClick(marker: Marker) {
onMarkerClick(marker);
}
private fun addItems() {
// Add ten cluster items in close proximity, for purposes of this example.
val items: List<ChargePoint> = appCommon.getChargePoints()
var isGood: Boolean = true
for (i in 0 until items.size) {
val cp: ChargePoint = items[i]
if (cp.Guid != null) {
Log.d("Available", "addItems: ${cp.hasType(ChargePointType.AdHoc)}")
var color: MarkerColor = MarkerColor.Green
if (cp.hasType(ChargePointType.AdHoc)) {
color = MarkerColor.Blue
}
else if (!cp.Available) {
color = MarkerColor.Red
}
val offsetItem = CafMarker(cp.Lat, cp.Lon, cp.Guid, cp.CpName, cp.Name, color, "", "", "")
clusterManager.addItem(offsetItem)
val defaultClusterRenderer = clusterManager.renderer as DefaultClusterRenderer
// defaultClusterRenderer.minClusterSize = 4
if (defaultClusterRenderer.minClusterSize >= 6) {
clusterManager.addItem(offsetItem)
}
cp.uuid = offsetItem.GetId()
ChargePoints.add(i, cp)
} else {
isGood = false
}
}
if (!isGood) {
}
}
private fun createChannel(channelId: String, channelName: String) {
// TODO: Step 1.6 START create a channel
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// Create channel to show notifications.
val notificationChannel = NotificationChannel(
channelId,
channelName,
NotificationManager.IMPORTANCE_HIGH
)
.apply {
setShowBadge(false)
}
notificationChannel.enableLights(true)
notificationChannel.lightColor = Color.RED
notificationChannel.enableVibration(true)
notificationChannel.description = getString(R.string.notification_channel_description)
val notificationManager = requireActivity().getSystemService(
NotificationManager::class.java
)
notificationManager.createNotificationChannel(notificationChannel)
}
}
}
Remove requireActivity(), it gives this IllegalStateException. See Explanation from official document.
locationResult.addOnCompleteListener {task ->
if (task.isSuccessful) {
// Your Code
}
}
Get Location, according to official documentation.
Intention:
I am trying to get user's current location after user grants (coarse/fine)location permission. I am using jetpack compose accompanist lib to manager permission.
So when user grants the permission, am using getCurrentLocation of FusedLocationProviderClient to get the location object, and fetching lat lang from it.
Problem:
In the below code block, Logcat logs: Coordinates[0.0,0.0]
class LocationManager #Inject constructor(
private val fusedLocation: FusedLocationProviderClient
) {
#SuppressLint("MissingPermission")
#Composable
#ExperimentalPermissionsApi
fun getLatLang(context: Context): Coordinates {
val coordinates = Coordinates(0.0, 0.0)
/**
* Checking and requesting permission. If granted it will fetch current lat lang,
* else it will request for permission.
* If denied, will show popup to open app settings and grant location permission.
*/
LocationPermissionManager.RequestPermission(
actionPermissionGranted = {
fusedLocation.getCurrentLocation(LocationRequest.PRIORITY_HIGH_ACCURACY, null)
.addOnSuccessListener { location ->
if (location != null) {
coordinates.lat = location.latitude
coordinates.long = location.longitude
}
}
},
actionPermissionDenied = { context.openAppSystemSettings() }
)
return coordinates
}
}
data class Coordinates(var lat: Double, var long: Double)
Consuming LocationManager below:
#ExperimentalPermissionsApi
#Composable
fun AirQualityLayout(locationManager: LocationManager) {
val context: Context = LocalContext.current
val coordinates: Coordinates = locationManager.getLatLang(context = context)
if (coordinates.lat != 0.0 && coordinates.long != 0.0) {
Timber.d("Current location: $coordinates")
ShowUI()
}
}
Expecting suggestions/help what I am doing wrong here.
Do you have your manifest right? (Access_fine_location and access_coarse_location
This is a class i made sometime ago:
class LocationLiveData(var context: Context): LiveData<LocationDetails>() {
//add dependency implementation "com.google.android.gms:play-services-maps:18.0.2"
private val fusedLocationClient = LocationServices.getFusedLocationProviderClient(context)
override fun onActive() {
super.onActive()
if (ActivityCompat.checkSelfPermission(
context,
Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
context,
Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) { // alse geen permissie hebben just return, anders voer functie location uit
return
}
fusedLocationClient.lastLocation.addOnSuccessListener {
location -> location.also {
setLocationData(it)
}
}
}
internal fun startLocationUpdates() {
if (ActivityCompat.checkSelfPermission(
context,
Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
context,
Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
return
}
fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper())
}
private fun setLocationData(location: Location?) {
location?.let { it ->
//value is observed in LiveData
value = LocationDetails(
longitude = it.longitude.toString(),
lattitude = it.latitude.toString()
)
}
println("value $value")
}
override fun onInactive() {
super.onInactive()
fusedLocationClient.removeLocationUpdates(locationCallback)
}
private val locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
super.onLocationResult(locationResult)
println("we have a new location result")
locationResult ?: return //als er een result is dan prima, zo niet dan just return (elvis operator)
for (location in locationResult.locations) {
setLocationData(location = location)
}
}
}
companion object {
val ONE_MINUTE: Long = 1000
#RequiresApi(Build.VERSION_CODES.S)
val locationRequest : com.google.android.gms.location.LocationRequest = com.google.android.gms.location.LocationRequest.create().apply {
interval = ONE_MINUTE
fastestInterval = ONE_MINUTE/4
priority = LocationRequest.QUALITY_HIGH_ACCURACY
}
}
}
I've just resolved it with UiState, placing function into ViewModel class
Here my solution:
UiState:
data class MyCityUiState(
...
val currentLocation: Location? = null
...
)
update funtion in ViewModel:
fun updateCurrentLocation(location: Location?) {
_uiState.update {
it.copy(
currentLocation = location
)
}
}
fun that use ".addOnListener":
#SuppressLint("MissingPermission")
fun displayDistance(placeLocation: LatLng, context: Context): String? {
var fusedLocationClient = LocationServices.getFusedLocationProviderClient(context)
fusedLocationClient.lastLocation
.addOnSuccessListener { location: Location? ->
if (location != null) {
updateCurrentLocation(location)
}
}
var result: Float?
var formatResult: String? = null
val placeLocationToLocationType = Location("Place")
placeLocationToLocationType.latitude = placeLocation.latitude
placeLocationToLocationType.longitude = placeLocation.longitude
result =
uiState.value.currentLocation?.distanceTo(placeLocationToLocationType)
if (result != null) {
formatResult = "%.1f".format(result / 1000) + " km"
}
return formatResult
}
``
I put a Map Fragment inside dashboard fragment shown in image below:
To view the image clearly https://i.stack.imgur.com/NcxLB.jpg
whenever i am on home fragment and click on dashboard fragment it takes 3-4 sec (at the first time) and 1-2 sec
here is the code of dashboard fragment
class DashboardFragment :
BaseFragment<DashboardViewModel, FragmentDashboardBinding, WeatherRepository>(),
GoogleMap.OnMapClickListener,
GoogleMap.OnMapLongClickListener,
GoogleMap.OnCameraIdleListener,
OnMapReadyCallback {
private var map: GoogleMap? = null
private var cameraPosition: CameraPosition? = null
private lateinit var fusedLocationProviderClient: FusedLocationProviderClient
private val defaultLocation = LatLng(-33.8523341, 151.2106085)
private var locationPermissionGranted = false
private var lastKnownLocation: Location? = null
private var weatherData: WeatherData? = null
private lateinit var bottomSheetBehavior: BottomSheetBehavior<NestedScrollView>
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
if (savedInstanceState != null) {
lastKnownLocation = savedInstanceState.getParcelable(KEY_LOCATION)
cameraPosition = savedInstanceState.getParcelable(KEY_CAMERA_POSITION)
weatherData = savedInstanceState.getParcelable(KEY_WEATHER_DATA)
}
Log.e("Weather Data", weatherData.toString())
fusedLocationProviderClient =
LocationServices.getFusedLocationProviderClient(requireActivity())
val mapFragment =
childFragmentManager.findFragmentById(R.id.myMap) as SupportMapFragment?
mapFragment?.getMapAsync(this#DashboardFragment)
bottomSheetBehavior = BottomSheetBehavior.from(binding.root.bottomSheet)
bottomSheetBehavior.addBottomSheetCallback(object :
BottomSheetBehavior.BottomSheetCallback() {
override fun onSlide(bottomSheet: View, slideOffset: Float) { /*handle onSlide*/ }
override fun onStateChanged(bottomSheet: View, newState: Int) {
when (newState) {
BottomSheetBehavior.STATE_COLLAPSED -> {
binding.root.bottomSheet.background =
(ContextCompat.getDrawable(requireContext(), R.drawable.round))
}
BottomSheetBehavior.STATE_EXPANDED -> {
binding.root.bottomSheet.background =
(ContextCompat.getDrawable(requireContext(), R.drawable.edge))
}
BottomSheetBehavior.STATE_DRAGGING -> {
}
BottomSheetBehavior.STATE_SETTLING -> {
}
BottomSheetBehavior.STATE_HIDDEN -> {
}
else -> {
}
}
}
})
viewModel.weatherResponse.observe(viewLifecycleOwner, {
when (it) {
is Resource.Success -> {
updateUi(binding.root, it.value)
weatherData = it.value
}
is Resource.Failure -> {
Toast.makeText(
requireContext(),
"Damn, Failed To Load Data",
Toast.LENGTH_SHORT
).show()
}
}
})
}
override fun onSaveInstanceState(outState: Bundle) {
map?.let { map ->
outState.putParcelable(KEY_CAMERA_POSITION, map.cameraPosition)
outState.putParcelable(KEY_LOCATION, lastKnownLocation)
}
super.onSaveInstanceState(outState)
}
override fun onMapReady(map: GoogleMap) {
this.map = map
map.setOnMapClickListener(this)
map.setOnMapLongClickListener(this)
map.setOnCameraIdleListener(this)
getLocationPermission()
updateLocationUI()
getDeviceLocation()
}
var marker: Marker? = null
override fun onMapClick(point: LatLng) {
if (marker == null){
marker = map?.addMarker(
MarkerOptions()
.position(point)
.title("${point.latitude.toString()},${point.longitude.toString()} is the location")
)
} else {
marker!!.position = point
marker!!.title = "${point.latitude.toString()},${point.longitude.toString()} is the location"
}
viewModel.getWeather(
point.latitude.toString(),
point.longitude.toString(),
app_id
)
if (bottomSheetBehavior.state == BottomSheetBehavior.STATE_EXPANDED)
bottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
else
bottomSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED
Toast.makeText(this.context, "click $point", Toast.LENGTH_SHORT).show()
}
override fun onMapLongClick(point: LatLng) {
try {
val manager: FragmentManager =
(this.context as AppCompatActivity).supportFragmentManager
CustomBottomSheetDialogFragment().show(manager, CustomBottomSheetDialogFragment.TAG)
} catch (e: Exception) {
Log.e("❤", e.printStackTrace().toString())
}
Toast.makeText(this.context, "long click", Toast.LENGTH_SHORT).show()
}
override fun onCameraIdle() {
//if(!::map.isInitialized) return
//cameraTextView.text = map.cameraPosition.toString()
//Toast.makeText(this.context, "camera idle", Toast.LENGTH_SHORT).show()
}
private fun updateLocationUI() {
if (map == null) {
return
}
try {
if (locationPermissionGranted) {
map?.isMyLocationEnabled = true
map?.uiSettings?.isMyLocationButtonEnabled = true
} else {
map?.isMyLocationEnabled = false
map?.uiSettings?.isMyLocationButtonEnabled = false
lastKnownLocation = null
getLocationPermission()
}
} catch (e: SecurityException) {
Log.e("Exception: %s", e.message, e)
}
}
private fun getDeviceLocation() {
try {
if (locationPermissionGranted) {
val locationResult = fusedLocationProviderClient.lastLocation
locationResult.addOnCompleteListener { task ->
if (task.isSuccessful) {
lastKnownLocation = task.result
if (lastKnownLocation != null) {
map?.moveCamera(
CameraUpdateFactory.newLatLngZoom(
LatLng(
lastKnownLocation!!.latitude,
lastKnownLocation!!.longitude
), DEFAULT_ZOOM.toFloat()
)
)
viewModel.getWeather(
lastKnownLocation!!.latitude.toString(),
lastKnownLocation!!.longitude.toString(),
app_id
)
}
} else {
Log.d(TAG, "Current location is null. Using defaults.")
Log.e(TAG, "Exception: %s", task.exception)
map?.moveCamera(
CameraUpdateFactory
.newLatLngZoom(defaultLocation, DEFAULT_ZOOM.toFloat())
)
map?.uiSettings?.isMyLocationButtonEnabled = false
}
}
}
} catch (e: SecurityException) {
Log.e("Exception: %s", e.message, e)
Toast.makeText(this.context, "Some exception occurred", Toast.LENGTH_SHORT).show()
}
}
private fun getLocationPermission() {
if (ContextCompat.checkSelfPermission(
requireContext(),
Manifest.permission.ACCESS_FINE_LOCATION
)
== PackageManager.PERMISSION_GRANTED
) {
locationPermissionGranted = true
} else {
requestPermissions(
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION
)
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>,
grantResults: IntArray
) {
locationPermissionGranted = false
when (requestCode) {
PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION -> {
if (grantResults.isNotEmpty() &&
grantResults[0] == PackageManager.PERMISSION_GRANTED
) {
locationPermissionGranted = true
}
}
}
updateLocationUI()
}
override fun getViewModal() = DashboardViewModel::class.java
override fun getFragmentBinding(
inflater: LayoutInflater,
container: ViewGroup?
) = FragmentDashboardBinding.inflate(inflater, container, false)
override fun getFragmentRepository() =
WeatherRepository(remoteDataSource.buildApi(WeatherApi::class.java))
companion object {
private val TAG = DashboardFragment::class.java.simpleName
private const val DEFAULT_ZOOM = 15
private const val PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION = 1
private const val KEY_CAMERA_POSITION = "camera_position"
private const val KEY_LOCATION = "location"
private const val KEY_WEATHER_DATA = "weather_data"
const val app_id = "*******api********"
}
}
even if i comment the whole code it the onActivityCreated() method still the lag occurs.
I used the code from the official Google Maps Platform Documentation, still the example app they use don't lags like my app.
Any help will be appreciated.