I am building an app and need to open the map after either a picture is taken from the camera or is selected from their images. It runs a python script to generate a random set of GPS coordinates, which I know is working fine as I have had it output the result to the screen and has done so correctly. Now, when I call the Google Maps class to open the map and display the generated coordinates, it gives an error.
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.aggiemap/com.example.aggiemap.MapsActivity}: java.lang.NullPointerException: null cannot be cast to non-null type com.google.android.gms.maps.SupportMapFragment
I am writing it in Kotlin. Here is the code from MainActivity. The map opened before but once I added the python script, it has stopped working and closes the app every time it gets to that point.
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == RESULT_OK && requestCode == pickImage) {
imageUri = data?.data
imageView.setImageURI(imageUri)
// PYTHON HERE
val py = Python.getInstance()
val pyobj = py.getModule("main")
this.lat = pyobj.callAttr("runlat").toDouble()
this.long = pyobj.callAttr("runlong").toDouble()
/* Open the map after image has been received from user
This will be changed later to instead call the external object recognition/pathfinding
scripts and then pull up the map after those finish running
*/
val intent = Intent(this, MapsActivity::class.java)
startActivity(intent)
}
if (dynamic) {
// PYTHON HERE
val py = Python.getInstance()
val pyobj = py.getModule("main")
this.lat = pyobj.callAttr("runlat").toDouble()
this.long = pyobj.callAttr("runlong").toDouble()
dynamic = false
/* Open the map after image has been received from user
This will be changed later to instead call the external object recognition/pathfinding
scripts and then pull up the map after those finish running
*/
val intent = Intent(this, MapsActivity::class.java)
startActivity(intent)
}
}
And here is the code from MapsActivity class
class MapsActivity : AppCompatActivity(), OnMapReadyCallback {
private lateinit var mMap: GoogleMap
private lateinit var binding: ActivityMapsBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMapsBinding.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.google_map) as SupportMapFragment
mapFragment.getMapAsync(this)
}
/**
* Manipulates the map once available.
* This callback is triggered when the map is ready to be used.
* This is where we can add markers or lines, add listeners or move the camera. In this case,
* we just add a marker near Sydney, Australia.
* If Google Play services is not installed on the device, the user will be prompted to install
* it inside the SupportMapFragment. This method will only be triggered once the user has
* installed Google Play services and returned to the app.
*/
override fun onMapReady(googleMap: GoogleMap) {
mMap = googleMap
// Add a marker at generated coordinate
val location = LatLng(MainActivity().lat, MainActivity().long)
val zoomLevel = (17.0).toFloat()
mMap.addMarker(MarkerOptions().position(location).title("Your Estimated Location"))
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(location,zoomLevel))
}
}
Thank you in advance for any help. I have been stuck on this issue for days and can't figure out why it isn't working or what the error means.
CodePudding user response:
onMapReady(...)
is called with null
parameter.
Now, when you override that function onMapReady
with non-null parameter googleMap: GoogleMap
, Kotlin compiler automatically generates validation code that actually forcing the parameter to be non-null by throwing that exception you encountered if it's null.
Since this parameter can be null, you should mark it as nullable, then that validation code won't be generated - googleMap: GoogleMap?
(also, you need to add handling in case it's null).
Full signature:
override fun onMapReady(googleMap: GoogleMap?) {
mMap = googleMap
// Add a marker at generated coordinate
val location = LatLng(MainActivity().lat, MainActivity().long)
val zoomLevel = (17.0).toFloat()
mMap.addMarker(MarkerOptions().position(location).title("Your Estimated Location"))
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(location,zoomLevel))
}
Cheers
CodePudding user response:
Here's your error:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.aggiemap/com.example.aggiemap.MapsActivity}:
java.lang.NullPointerException: null cannot be cast to non-null type com.google.android.gms.maps.SupportMapFragment
null cannot be cast to non-null type SupportMapFragment
means you're trying to cast something (using as
) to the non-null type SupportMapFragment
, but the thing you're casting is actually null, so the cast fails. Here's where you're doing that (the stacktrace tells you exactly which line number the error is on btw):
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
val mapFragment = supportFragmentManager
.findFragmentById(R.id.google_map) as SupportMapFragment
findFragmentById
will return null if there's no fragment with that ID present in the FragmentManager
. So you need to either cast to the nullable type (SupportMapFragment?
) and handle the null, or ensure that fragment definitely exists before you make this call