Google Map Update Markers Positions with Clusters - android

Hello I have a fragment with a MapView inside and I need to update the position of his markers every X seconds.
Actually I re-download the data every X seconds then I call "updateAdams" function to relocate all the markers. The problem is that I see the marker move only if I zoom in/zoom out the map, if I don't zoom I don't see the markers move.
How can I solve this?
I tryed to add mGoogleMap.clear() but doing this the markers just disappear and re-appear only if I zoom in/zoom out again.
This is my code (an Adam is a Vehicle):
class GestioneAdamMapFragment : Fragment(),
OnMapReadyCallback,
GetLocationManager.OnLocationUpdateCallback {
private var mGoogleMap: GoogleMap? = null
private lateinit var mGetLocationManager: GetLocationManager
private var mMyLocation: LatLng? = null
private var mAdams: ArrayList<Adam> = ArrayList()
private var mIsFirstInit = true
private var mIdAdamMarkerClicked: Int? = null
private lateinit var mClusterManager: ClusterManager<MarkerClusterItem>
private val mClusterItems = ArrayList<MarkerClusterItem>()
companion object {
fun newInstance(adams: ArrayList<Adam>): GestioneAdamMapFragment {
val mInstance = GestioneAdamMapFragment()
val args = Bundle()
args.putSerializable(KEY_ADAMS, adams)
mInstance.arguments = args
return mInstance
}
fun newInstance() = GestioneAdamMapFragment()
}
//region [#] Override Lifecycle Methods
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.fragment_gestione_adam_map, container, false)
initOnCreateView()
MapsInitializer.initialize(requireContext())
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initOnViewCreated(savedInstanceState)
}
override fun onResume() {
mMapView.onResume()
super.onResume()
}
override fun onPause() {
super.onPause()
mMapView.onPause()
}
override fun onDestroy() {
mMapView?.onDestroy()
super.onDestroy()
}
override fun onLowMemory() {
super.onLowMemory()
mMapView.onLowMemory()
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
if(requestCode == REQ_CODE_PERMISSION_LOCATION){
if(grantResults.size > 0x0){
for(res in grantResults){
if(res == PackageManager.PERMISSION_GRANTED){
mMapView.getMapAsync(this)
break
}
}
}
}
}
//endregion
//region [#] Override OnMapReadyCallback Methods
override fun onMapReady(p0: GoogleMap) {
mGoogleMap = p0
initGoogleMap()
if(mAdams.isNotEmpty()){
initListenersAndCluster()
}
if(mMyLocation != null){
var included = false
if(mAdams.isNotEmpty()){
for(adam in mAdams){
if(adam?.getPosizione() != null && adam!!.getPosizione()!!.getLatitude() != null && adam!!.getPosizione()!!.getLongitude() != null){
included = true
}
}
}
if(!included){
mGoogleMap!!.animateCamera(CameraUpdateFactory.newLatLngZoom(mMyLocation!!, 5.0f))
}
}
}
//region [#] Override GetLocationManager.OnLocationUpdateCallback Methods
override fun onLocationUpdated(location: Location?) {
mMyLocation = if(location != null)
LatLng(location.latitude, location.longitude)
else
null
}
//endregion
//region [#] Public Methods
fun setAdams(adams: List<Adam>){
mAdams.clear()
mAdams.addAll(adams)
if(mGoogleMap != null){
initListenersAndCluster()
}
}
fun updateAdams(adams: List<Adam>){
mClusterManager.removeItems(mClusterItems)
mAdams.clear()
mAdams.addAll(adams)
addClusterItems()
}
//endregion
//region [#] Private Methods
private fun initOnCreateView(){
mGetLocationManager = GetLocationManager.initInstance(requireActivity()).setCallback(this)
mGetLocationManager.startLocationUpdates()
}
private fun initOnViewCreated(savedInstanceState: Bundle?){
mMapView.onCreate(savedInstanceState)
try {
MapsInitializer.initialize(requireActivity().applicationContext)
} catch (e: Exception){
BaseEnvironment.onExceptionLevelLow(TAG, e)
}
mMapView.getMapAsync(this)
mibMapType.setOnClickListener{
when (mGoogleMap!!.mapType) {
GoogleMap.MAP_TYPE_NONE, GoogleMap.MAP_TYPE_HYBRID, GoogleMap.MAP_TYPE_SATELLITE -> mGoogleMap!!.mapType = GoogleMap.MAP_TYPE_NORMAL
GoogleMap.MAP_TYPE_NORMAL, GoogleMap.MAP_TYPE_TERRAIN -> mGoogleMap!!.mapType = GoogleMap.MAP_TYPE_HYBRID
}
}
}
private fun initGoogleMap(){
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, Manifest.permission.ACCESS_COARSE_LOCATION), REQ_CODE_PERMISSION_LOCATION)
} else {
mGoogleMap?.isMyLocationEnabled = true
}
}
private fun initListenersAndCluster(){
mGoogleMap?.clear()
if(mIsFirstInit){
initClusterManager()
zoomToCenterOfAdams()
initOnClickMarker()
initOnClickMap()
mIsFirstInit = false
initOnClickMarkerLabel()
}
addClusterItems()
}
//endregion
private fun zoomToCenterOfAdams(){
val builder: LatLngBounds.Builder = LatLngBounds.Builder()
var included = false
for(adam in mAdams){
if(adam?.getPosizione() != null && adam!!.getPosizione()!!.getLatitude() != null && adam!!.getPosizione()!!.getLongitude() != null){
builder.include(LatLng(adam!!.getPosizione()!!.getLatitude()!!.toDouble(), adam!!.getPosizione()!!.getLongitude()!!.toDouble()))
included = true
}
}
if(included){
val cu: CameraUpdate = CameraUpdateFactory.newLatLngBounds(builder.build(), resources.getDimensionPixelSize(R.dimen.padding_100dp))
mGoogleMap?.animateCamera(cu)
}
}
private fun initOnClickMarkerLabel(){
mClusterManager.setOnClusterItemInfoWindowClickListener {
var adam: Adam? = null
for(a in mAdams){
if(a.getId() == it.title!!.toInt()){
adam = a
break
}
}
if(adam != null){
startActivity(DettagliAdamActivity.getIntent(requireContext(), adam))
}
}
}
private fun initOnClickMarker(){
mClusterManager.setOnClusterItemClickListener {
mIdAdamMarkerClicked = it.title!!.toInt()
false
}
}
private fun initOnClickMap(){
mGoogleMap?.setOnMapClickListener {
mIdAdamMarkerClicked = null
}
}
private fun initClusterManager(){
mClusterManager = ClusterManager(requireContext(), mGoogleMap)
mClusterManager.markerCollection.setInfoWindowAdapter(InfoWindowAdapter(mAdams, requireContext()))
mClusterManager.renderer = ClusterItemRenderer(requireContext(), mGoogleMap!!, mClusterManager)
mGoogleMap!!.setOnCameraIdleListener(mClusterManager)
}
private fun addClusterItems(){
for(adam in mAdams){
var lat = adam.getPosizione()?.getLatitude()?.toDouble()
var lng = adam.getPosizione()?.getLongitude()?.toDouble()
if(lat != null && lng != null){
val marker = MarkerClusterItem(adam, lat, lng, adam.getId().toString(), "Snippet")
mClusterItems.add(marker)
mClusterManager.addItem(marker)
}
}
}
//endregion
}
Actually I'm solving this problem by zooming in of 0.001, is there a better way to solve this problem?
I'm doing as last line of "updateAdams":
mGoogleMap?.animateCamera(CameraUpdateFactory.newLatLngZoom(mGoogleMap?.cameraPosition?.target!!, mGoogleMap!!.cameraPosition!!.zoom + 0.001f))

Related

I get "not attached to a context" error when I want to go back from current fragment

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
}

How to make a check for entering the correct city when entering

I have a way where when I enter the name of the city, I substitute the name of the city in the api, and everything works fine, but if I enter a non-real city, then nonsense is put in the api accordingly and the application crashes. I would like to make it so that if the city does not exist, that is, I output an error, then Toast "enter the correct name of the city" appears. Thank you in advance
Код:
const val USE_DEVICE_LOCATION = "USE_DEVICE_LOCATION"
const val CUSTOM_LOCATION = "CUSTOM_LOCATION"
class LocationProviderImpl(
private val fusedLocationProviderClient: FusedLocationProviderClient,
context: Context) : PreferenceProvider(context), LocationProvider {
private val appContext = context.applicationContext
override suspend fun hasLocationChanged(lastWeatherLocation: WeatherLocation): Boolean {
val deviceLocationChanged = try {
hasDeviceLocationChanged(lastWeatherLocation)
} catch (e: LocationPermissionNotGrantedException) {
false
}
return deviceLocationChanged || hasCustomLocationChanged(lastWeatherLocation)
}
override suspend fun getPreferredLocationString(): String {
if(isUsingDeviceLocation()) {
try {
val deviceLocation = getLastDeviceLocation()
?: return "${getCustomLocationName()}"
return "${deviceLocation.latitude},${deviceLocation.longitude}"
} catch (e: LocationPermissionNotGrantedException) {
return "${getCustomLocationName()}"
}
}
else {
return "${getCustomLocationName()}"
}
}
private suspend fun hasDeviceLocationChanged(lastWeatherLocation: WeatherLocation): Boolean {
if (!isUsingDeviceLocation())
return false
val deviceLocation = getLastDeviceLocation()
?: return false
// Comparing doubles cannot be done with "=="
val comparisonThreshold = 0.03
return Math.abs(deviceLocation.latitude - lastWeatherLocation.lat) > comparisonThreshold &&
Math.abs(deviceLocation.longitude - lastWeatherLocation.lon) > comparisonThreshold
}
private fun hasCustomLocationChanged(lastWeatherLocation: WeatherLocation): Boolean {
if (!isUsingDeviceLocation()) {
val customLocationName = getCustomLocationName()
return customLocationName != lastWeatherLocation.name
}
return false
}
private fun getCustomLocationName(): String? {
try {
return preferences.getString(CUSTOM_LOCATION, null)
}
catch (e: Exception) {
isUsingDeviceLocation()
}
throw LocationPermissionNotGrantedException()
}
private fun isUsingDeviceLocation(): Boolean {
return preferences.getBoolean(USE_DEVICE_LOCATION, true)
}
#SuppressLint("MissingPermission")
private suspend fun getLastDeviceLocation(): Location? {
return (if (hasLocationPermission())
fusedLocationProviderClient.lastLocation.asDeferred()
else {
throw LocationPermissionNotGrantedException()
}).await()
}
private fun hasLocationPermission(): Boolean {
return ContextCompat.checkSelfPermission(appContext,
android.Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED
}
}
CurrentWeatherFragment
class CurrentWeatherFragment : ScopedFragment(), KodeinAware, SharedPreferences.OnSharedPreferenceChangeListener {
override val kodein by closestKodein()
private val viewModelFactory: CurrentWeatherViewModelFactory by instance()
private lateinit var viewModel: CurrentWeatherViewModel
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.current_weather_fragment, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
loadBannerAd()
viewModel = ViewModelProvider(this, viewModelFactory)
.get(CurrentWeatherViewModel::class.java)
bindUI()
applyDarkModeSetting()
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
}
private fun loadBannerAd() {
MobileAds.initialize(context) {}
mAdViewCurrent = adView
val adRequest = AdRequest.Builder().build()
mAdViewCurrent.loadAd(adRequest)
mAdViewCurrent.adListener = object: AdListener() {
override fun onAdLoaded() {
}
override fun onAdFailedToLoad(adError : LoadAdError) {
// Code to be executed when an ad request fails.
}
override fun onAdOpened() {
// Code to be executed when an ad opens an overlay that
// covers the screen.
}
override fun onAdClicked() {
// Code to be executed when the user clicks on an ad.
}
override fun onAdClosed() {
}
}
}
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
if (key == "GENDER") {
val prefs = sharedPreferences?.getString(key, "1")
when(prefs?.toInt()) {
1->{
bindUI()
}
2->{
bindUIWomen()
}
}
}
applyDarkModeSetting()
}
override fun onDestroy() {
super.onDestroy()
context?.let {
PreferenceManager.getDefaultSharedPreferences(it)
.registerOnSharedPreferenceChangeListener(this)
}
}
private fun applyDarkModeSetting() {
val sharedPreferences = context?.let { PreferenceManager.getDefaultSharedPreferences(it) }
val settingValue = sharedPreferences?.getString("GENDER", null)?.toIntOrNull() ?: 1
val mode = when (settingValue) {
1 -> {bindUI()}
2 -> {bindUIWomen()}
else -> Toast.makeText(context, "Nothing", Toast.LENGTH_LONG).show()
}
}
private fun bindUI() = launch(Dispatchers.Main) {
val currentWeather = viewModel.weather.await()
val weatherLocation = viewModel.weatherLocation.await()
val CurrentWeatherEntries = viewModel.weather.await()
CurrentWeatherEntries.observe(viewLifecycleOwner, Observer { weatherAll ->
if (weatherAll == null){
return#Observer
}
recyclerViewClothes.apply {
layoutManager = LinearLayoutManager(activity)
adapter = ClothesAdapter(weatherAll)
}
})
weatherLocation.observe(viewLifecycleOwner, Observer { location ->
if (location == null) return#Observer
updateLocation(location.name)
updateCityName(location.name)
})
currentWeather.observe(viewLifecycleOwner, Observer {
if(it == null) return#Observer
group_loading.visibility = View.GONE
weatherAll.visibility = View.VISIBLE
updateDateToday()
//updateIsDay(it.isDay)
updateHumidity(it.humidity)
updateTemperature(it.temperature, it.feelsLikeTemperature)
updateCondition(it.conditionText)
updatePressure(it.pressure)
updateWind(it.windSpeed)
updateCloudy(it.cloud)
GlideApp.with(this#CurrentWeatherFragment)
.load("https:${it.conditionIconUrl}")
.into(imageView_condition_icon)
})
refreshApp()
}
private fun List<UnitSpecificCurrentWeatherEntry>.toCurrentWeatherItems() : List<ClothesAdapter> {
return this.map {
ClothesAdapter(it) //ClothesAdapter
}
}
// private fun List<UnitSpecificCurrentWeatherEntry>.toCurrentWeatherItems() : List<ClothesAdapterWomen> {
// return this.map {
// ClothesAdapterWomen(it) //ClothesAdapter
// }
// }
private fun chooseLocalizationUnitAbbreviation(metric: String, imperial: String): String {
return if(viewModel.isMetricUnit) metric else imperial
}
private fun updateLocation(location: String) {
(activity as? AppCompatActivity)?.supportActionBar?.subtitle = getString(R.string.todayTitle)
}
private fun updateDateToday() {
(activity as? AppCompatActivity)?.supportActionBar?.subtitle = getString(R.string.todayTitle)
}
private fun updateCityName(cityName: String) {
textView_cityName.text = cityName
}
}

NullPointerException when using Kotlin Synthetic

I am getting a NullPointerException when I try to access an element in the layout from a DialogFragment. I have checked that, if I call getView() inside the same DialogFragment the result is 'null'.
Thank you in advance!
This is the Activity that calls commits the FragmentDialog "NewPOIDialog"
class MainActivity : AppCompatActivity() {
//Variables for Location service
private var hasGps: Boolean = false
private var hasNetwork: Boolean = false
private var locationGps: Location? = null
private var locationNetwork: Location? = null
private companion object {
private const val TAG = "MainActivity"
}
private lateinit var auth: FirebaseAuth
private lateinit var permissionsRequestor: PermissionsRequestor
private lateinit var mapView: MapView
private lateinit var mapActivity: MapActivity
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
//Get the authorisation from Firebase
auth = Firebase.auth
Log.d("", "HERE SDK version: " + SDKBuildInformation.sdkVersion().versionName)
// Get a MapView instance from layout.
mapView = findViewById(R.id.map_view)
mapView.onCreate(savedInstanceState)
location()
handleAndroidPermissions()
}
fun searchInMap(view: View?) {
NewPOIDialog().show(supportFragmentManager, "test")
}
fun clearRouteButtonClicked(view: View?) {
mapActivity.clearMap()
}
fun clearWaypoints(view: View?) {
mapActivity.clearWaypoints()
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.menu_main, menu)
return true //we provided the menu that needs to be inflated
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == R.id.miLogout) {
Log.i(TAG, "Logout")
//Logout the user
auth.signOut()
LoginManager.getInstance().logOut()
val logoutIntent = Intent(this, LoginActivity::class.java)
logoutIntent.flags =
Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK //Clear the backstack
startActivity(logoutIntent)
}
return super.onOptionsItemSelected(item)
}
private fun handleAndroidPermissions() {
permissionsRequestor = PermissionsRequestor(this)
permissionsRequestor.request(object : PermissionsRequestor.ResultListener {
override fun permissionsGranted() {
loadMapScene()
}
override fun permissionsDenied() {
Log.e(TAG, "Permissions denied by user.")
}
})
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
permissionsRequestor.onRequestPermissionsResult(requestCode, grantResults)
}
private fun loadMapScene() {
mapView.mapScene.loadScene(MapScheme.NORMAL_DAY, object : MapScene.LoadSceneCallback {
override fun onLoadScene(p0: MapError?) {
if (p0 == null) {
mapActivity = MapActivity(this#MainActivity, mapView, supportFragmentManager)
mapView.camera.lookAt(
GeoCoordinates(53.57407651646072, -1.525012498490556),
100000.0
)
} else {
Log.d("TAG", "onLoadScene failed: $p0")
}
}
})
}
fun location() {
var locationManager: LocationManager = getSystemService(LOCATION_SERVICE) as LocationManager
hasGps = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)
hasNetwork = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
if (hasGps || hasNetwork) {
if (hasGps) {
Log.d(TAG, "hasGPS")
if (ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
//return
handleAndroidPermissions()
}
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER,
1000,
0f,
object :
LocationListener {
override fun onLocationChanged(p0: Location?) {
if (p0 != null) {
locationNetwork = p0
}
}
override fun onStatusChanged(p0: String?, p1: Int, p2: Bundle?) {
}
override fun onProviderEnabled(p0: String?) {
}
override fun onProviderDisabled(p0: String?) {
}
})
val localGpsLocation =
locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)
if (localGpsLocation != null) {
locationGps = localGpsLocation
}
}
///////////////////////////////////////////////////////////////////////////
if (hasNetwork) {
Log.d(TAG, "hasGPS")
locationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER,
1000,
0f,
object :
LocationListener {
override fun onLocationChanged(p0: Location?) {
if (p0 != null) {
locationNetwork = p0
}
}
override fun onStatusChanged(p0: String?, p1: Int, p2: Bundle?) {
}
override fun onProviderEnabled(p0: String?) {
}
override fun onProviderDisabled(p0: String?) {
}
})
val localGpsLocation =
locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)
if (localGpsLocation != null) {
locationGps = localGpsLocation
}
val localNetworkLocation =
locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER)
if (localNetworkLocation != null) {
locationNetwork = localNetworkLocation
}
if (locationGps != null && locationNetwork != null) {
if (locationGps!!.accuracy!! > locationNetwork!!.accuracy!!) { //The lower number is the accurate location
Log.d(TAG, "Network Latitude : ${locationNetwork!!.latitude}")
Log.d(TAG, "Network Longitude : ${locationNetwork!!.longitude}")
latitude_txt.text = "Latitude : ${locationNetwork!!.latitude} - Network"
longitude_txt.text = "Longitude : ${locationNetwork!!.longitude} - Network"
latitude_txt.text = "Latitude : ${locationGps!!.latitude} - Gps"
longitude_txt.text = "Longitude : ${locationGps!!.longitude} - Gps"
} else {
Log.d(TAG, "Gps Latitude : ${locationGps!!.latitude}")
Log.d(TAG, "Gps Longitude : ${locationGps!!.longitude}")
latitude_txt.text = "Latitude : ${locationGps!!.latitude} - Gps"
longitude_txt.text = "Longitude : ${locationGps!!.longitude} - Gps"
}
}
}
// if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) &&
// this.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LOCATION_GPS)
// ) {
// locationManager.requestLocationUpdates(
// LocationManager.GPS_PROVIDER,
// LOCATION_UPDATE_INTERVAL_IN_MS,
// 1,
// this
// );
// } else if (locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
// locationManager.requestLocationUpdates(
// LocationManager.NETWORK_PROVIDER,
// LOCATION_UPDATE_INTERVAL_IN_MS,
// 1,
// this
// );
// } else {
// Log.d(TAG, "Positioning not possible.");
// // ...
// }
}
}
}
NewPOIDialog
The view was initially called as below, I changed it as I was receiving a StackOverFlowError:
var view = layoutInflater.inflate(R.layout.activity_new_poi_dialog,null)
class NewPOIDialog : DialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
var view = LayoutInflater.from(context).inflate(R.layout.activity_new_poi_dialog, null)
var dialog = AlertDialog.Builder(requireContext())
.setMessage("TITLE")
.setView(view)
.setPositiveButton("ok") { _, _ -> }
.setNegativeButton("Cancel") { _, _ -> }
.create()
//THIS LINE WORKS FINE
var coordinatesvalue = view.findViewById<TextView>(R.id.coordinates_value)
coordinatesvalue.text =
"${arguments?.getDouble("latitude")}\n, ${arguments?.getDouble("longitude")}"
//THIS CAUSES A NULL POINTER EXCEPTION
coordinates_value.text = "TEST"
return dialog
}
}
The exception I am getting:
D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.robin.socialparking, PID: 19187
java.lang.NullPointerException: coordinates_value must not be null
at com.robin.socialparking.dialog.NewPOIDialog.onCreateDialog(NewPOIDialog.kt:54)
at androidx.fragment.app.DialogFragment.onGetLayoutInflater(DialogFragment.java:380)
at androidx.fragment.app.Fragment.performGetLayoutInflater(Fragment.java:1412)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:881)
at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManagerImpl.java:1238)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:1303)
at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:439)
at androidx.fragment.app.FragmentManagerImpl.executeOps(FragmentManagerImpl.java:2079)
at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManagerImpl.java:1869)
at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManagerImpl.java:1824)
at androidx.fragment.app.FragmentManagerImpl.execPendingActions(FragmentManagerImpl.java:1727)
at androidx.fragment.app.FragmentManagerImpl$2.run(FragmentManagerImpl.java:150)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7050)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:965)
I/Process: Sending signal. PID: 19187 SIG: 9

Map Fragment loading slowly

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.

android mapBox java.lang.Exception: Last location unavailable

Integrated mapbox in android.On some devices theres no problem and on some other devices the current location is not being set.It just shows a black screen for mapView.In the devices that not showing the current location in the mapview the Logcat logs this java.lang.Exception: Last location unavailable.Tested in oreo - two devices(in Xiaomi it's showing but in samsung its not) Nougat(HUAWEI DRA-LX2 ) not showing.Thanks in advance.
class HomeFragment : BaseFragment() {
#Inject
lateinit var factory: ViewModelProvider.Factory
lateinit var binding: HomeBinding
var anchorClicked: Boolean = false
private lateinit var mapboxMap: MapboxMap
private lateinit var locationEngine: LocationEngine
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = inflater.bind(R.layout.fragment_home, container)
return binding.root
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
binding.handler = this
binding.lifecycleOwner = viewLifecycleOwner
binding.mapView.onCreate(savedInstanceState)
val navigationView: NavigationView = requireActivity().findViewById(R.id.sideNV)
val headerView = navigationView.getHeaderView(0)
withViewModel<MapViewModel>(factory) {
binding.mapView.getMapAsync { mapBoxMap ->
this#HomeFragment.mapboxMap = mapBoxMap
if (getCurrentTheme())
mapBoxMap.setStyle(Style.TRAFFIC_NIGHT) {
requestPermission(it)
}
else mapBoxMap.setStyle(Style.TRAFFIC_DAY) {
requestPermission(it)
}
}
val auth = FirebaseAuth.getInstance()
if (auth.currentUser != null) {
val auth1 = FirebaseAuth.getInstance()
if (auth1.currentUser != null) {
headerView.userNameTV.text = auth1.currentUser?.displayName
headerView.userEmailTV.text = auth1.currentUser?.email.toString()
Glide.with(requireActivity())
.load(auth1.currentUser?.photoUrl)
.apply(RequestOptions.bitmapTransform(RoundedCorners(14)))
.into(headerView.userPicIV)
}
}
binding.vm = this
getCountries().observe(viewLifecycleOwner, Observer { })
}
}
fun onAnchor() {
var valueAnimator = ValueAnimator()
valueAnimator = if (anchorClicked) {
ValueAnimator.ofFloat(0.5f, 0.75f)
} else {
ValueAnimator.ofFloat(0.75f, 0.5f)
}
valueAnimator.duration = 500
valueAnimator.interpolator = AccelerateDecelerateInterpolator()
valueAnimator.addUpdateListener { valueAnimator ->
val lp = binding.guideline.layoutParams as ConstraintLayout.LayoutParams
// get the float value
lp.guidePercent = valueAnimator.animatedValue as Float
// update layout params
binding.guideline.layoutParams = lp
}
valueAnimator.start()
anchorClicked = !anchorClicked
}
fun requestPermission(style: Style) {
if (!hasPermissions(context!!, permissions)) requestPermissions(permissions, RC_LOCATION)
else enableLocationComponent(style)
}
private fun enableLocationComponent(loadedMapStyle: Style) {
val customLocationComponentOptions = LocationComponentOptions.builder(context!!)
.trackingGesturesManagement(true)
.accuracyColor(ContextCompat.getColor(context!!, R.color.com_facebook_blue))
.build()
val locationComponentActivationOptions =
LocationComponentActivationOptions.builder(context!!, loadedMapStyle)
.locationComponentOptions(customLocationComponentOptions)
.build()
mapboxMap.locationComponent.apply {
activateLocationComponent(locationComponentActivationOptions)
isLocationComponentEnabled = true
cameraMode = CameraMode.TRACKING
renderMode = RenderMode.COMPASS
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == RC_LOCATION) {
if (grantResults.isNotEmpty()
&& grantResults[0] == PackageManager.PERMISSION_GRANTED
) {
enableLocationComponent(mapboxMap.style!!)
}
}
}
override fun onResume() {
super.onResume()
mapView.onResume()
}
override fun onStart() {
super.onStart()
mapView?.onStart()
}
override fun onStop() {
super.onStop()
mapView?.onStop()
}
override fun onPause() {
super.onPause()
mapView?.onPause()
}
override fun onLowMemory() {
super.onLowMemory()
mapView?.onLowMemory()
}
override fun onDestroy() {
super.onDestroy()
mapView?.onDestroy()
}
companion object {
const val RC_LOCATION = 10
}
}

Categories

Resources