Home > Software design >  Why is my app crashing when it calls Google Maps class in Android Studio?
Why is my app crashing when it calls Google Maps class in Android Studio?

Time:04-15

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

  • Related