Error al invocar el método virtual ‘double android.location.Location.getLatitude ()’ en una referencia de objeto nulo

Todo lo que bash hacer es dejar que el usuario obtenga una lista de los lugares de los tipos que le gustan. Por ejemplo, si la entrada fue hospitalaria, mi aplicación abriría los mapas de Google con la cadena de búsqueda “Hospital”. Pero como se sugiere en la documentación que utiliza el código geo:0,0?q=hospital como geo:0,0?q=hospital uri muestra todos los hospitales cerca de las coordenadas 0 latitud y 0 longitud. Entonces, cuando intenté obtener las coordenadas de los usuarios primero, utilicé el siguiente código.

Lugares Decoder.java

 package com.kkze.Mappy; import android.app.Activity; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.location.Criteria; import android.location.Location; import android.location.LocationManager; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.provider.Settings; import android.text.TextUtils; import android.util.Log; import android.widget.Toast; public class PlacesDecoder extends Activity { Intent intentThatCalled; public double latitude; public double longitude; public LocationManager locationManager; public Criteria criteria; public String bestProvider; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); intentThatCalled = getIntent(); String voice2text = intentThatCalled.getStringExtra("v2txt"); getLocation(voice2text); } public static boolean isLocationEnabled(Context context) { int locationMode = 0; String locationProviders; if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { try { locationMode = Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.LOCATION_MODE); } catch (Settings.SettingNotFoundException e) { e.printStackTrace(); } return locationMode != Settings.Secure.LOCATION_MODE_OFF; } else { locationProviders = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED); return !TextUtils.isEmpty(locationProviders); } } public void getLocation(String voice2txt) { locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE); criteria = new Criteria(); bestProvider = String.valueOf(locationManager.getBestProvider(criteria, true)).toString(); Location location = locationManager.getLastKnownLocation(bestProvider); if (isLocationEnabled(PlacesDecoder.this)) { Log.e("TAG", "GPS is on"); latitude = location.getLatitude(); longitude = location.getLongitude(); Toast.makeText(PlacesDecoder.this, "latitude:" + latitude + " longitude:" + longitude, Toast.LENGTH_SHORT).show(); searchNearestPlace(voice2txt); } else { AlertDialog.Builder notifyLocationServices = new AlertDialog.Builder(PlacesDecoder.this); notifyLocationServices.setTitle("Switch on Location Services"); notifyLocationServices.setMessage("Location Services must be turned on to complete this action. Also please take note that if on a very weak network connection, such as 'E' Mobile Data or 'Very weak Wifi-Connections' it may take even 15 mins to load. If on a very weak network connection as stated above, location returned to application may be null or nothing and cause the application to crash."); notifyLocationServices.setPositiveButton("Ok, Open Settings", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Intent openLocationSettings = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS); PlacesDecoder.this.startActivity(openLocationSettings); finish(); } }); notifyLocationServices.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { finish(); } }); notifyLocationServices.show(); } } public void searchNearestPlace(String v2txt) { Log.e("TAG", "Started"); v2txt = v2txt.toLowerCase(); String[] placesS = {"accounting", "airport", "aquarium", "atm", "attraction", "bakery", "bakeries", "bank", "bar", "cafe", "campground", "casino", "cemetery", "cemeteries", "church", "courthouse", "dentist", "doctor", "electrician", "embassy", "embassies", "establishment", "finance", "florist", "food", "grocery", "groceries", "supermarket", "gym", "health", "hospital", "laundry", "laundries", "lawyer", "library", "libraries", "locksmith", "lodging", "mosque", "museum", "painter", "park", "parking", "pharmacy", "pharmacies", "physiotherapist", "plumber", "police", "restaurant", "school", "spa", "stadium", "storage", "store", "synagog", "synagogue", "university", "universities", "zoo"}; String[] placesM = {"amusement park", "animal care", "animal care", "animal hospital", "art gallery", "art galleries", "beauty salon", "bicycle store", "book store", "bowling alley", "bus station", "car dealer", "car rental", "car repair", "car wash", "city hall", "clothing store", "convenience store", "department store", "electronics store", "electronic store", "fire station", "funeral home", "furniture store", "gas station", "general contractor", "hair care", "hardware store", "hindu temple", "home good store", "homes good store", "home goods store", "homes goods store", "insurance agency", "insurance agencies", "jewelry store", "liquor store", "local government office", "meal delivery", "meal deliveries", "meal takeaway", "movie rental", "movie theater", "moving company", "moving companies", "night club", "pet store", "place of worship", "places of worship", "post office", "real estate agency", "real estate agencies", "roofing contractor", "rv park", "shoe store", "shopping mall", "subway station", "taxi stand", "train station", "travel agency", "travel agencies", "veterinary care"}; int index; for (int i = 0; i <= placesM.length - 1; i++) { Log.e("TAG", "forM"); if (v2txt.contains(placesM[i])) { Log.e("TAG", "sensedM?!"); index = i; Uri gmmIntentUri = Uri.parse("geo:" + latitude + "," + longitude + "?q=" + placesM[index]); Intent mapIntent = new Intent(Intent.ACTION_VIEW, gmmIntentUri); mapIntent.setPackage("com.google.android.apps.maps"); startActivity(mapIntent); finish(); } } for (int i = 0; i <= placesS.length - 1; i++) { Log.e("TAG", "forS"); if (v2txt.contains(placesS[i])) { Log.e("TAG", "sensedS?!"); index = i; Uri gmmIntentUri = Uri.parse("geo:" + latitude + "," + longitude + "?q=" + placesS[index]); Intent mapIntent = new Intent(Intent.ACTION_VIEW, gmmIntentUri); mapIntent.setPackage("com.google.android.apps.maps"); startActivity(mapIntent); finish(); } } } } 

El problema es que siempre y siempre la ubicación devuelve nulo. Y sé de hecho que otra aplicación Jarvis realiza fácilmente la tarea siempre que la ubicación esté habilitada, si no es simplemente le pide al usuario que lo haga. Pero en las mismas condiciones, mi aplicación siempre falla.

Que he hecho:

  1. Pasé día y noche tratando de resolver este problema.
  2. Navegado a través de numerosas páginas sobre el tema.
  3. Intenté diferentes códigos propios.

Y todavía sucede. Soy un principiante en Android. Y por favor, ayúdenme. ¿No hay una forma posible de resolver mi problema? incluso pensé que otra aplicación de alguna manera logra hacerlo.

Este es mi LogCat.

 Process: com.kkze.Mappy, PID: 6742 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.kkze.Mappy/com.kkze.Mappy.PlacesDecoder}: java.lang.NullPointerException: Attempt to invoke virtual method 'double android.location.Location.getLatitude()' on a null object reference at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2658) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2723) at android.app.ActivityThread.access$900(ActivityThread.java:172) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1422) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:145) at android.app.ActivityThread.main(ActivityThread.java:5832) at java.lang.reflect.Method.invoke(Native Method) at java.lang.reflect.Method.invoke(Method.java:372) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1399) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194) Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'double android.location.Location.getLatitude()' on a null object reference at com.kkze.Mappy.PlacesDecoder.getLocation(PlacesDecoder.java:62) at com.kkze.Mappy.PlacesDecoder.onCreate(PlacesDecoder.java:32) at android.app.Activity.performCreate(Activity.java:6221) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1119) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2611) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2723) at android.app.ActivityThread.access$900(ActivityThread.java:172) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1422) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:145) at android.app.ActivityThread.main(ActivityThread.java:5832) at java.lang.reflect.Method.invoke(Native Method) at java.lang.reflect.Method.invoke(Method.java:372) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1399) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194) 

También verificando la ubicación! = Null requiere el permiso ACCESS_FINE_LOCATION que daña mi aplicación y hace que siempre vuelva como nula.

Como Jon Skeet mencionó en los comentarios, el método getLastKnownLocation() puede devolver el valor nulo. El principal problema es que no solicita el SO para un nuevo locking de ubicación, sino que solo comprueba si hubo una última ubicación conocida de la solicitud de ubicación de otra aplicación. Si ninguna otra aplicación ha realizado recientemente una solicitud de ubicación, entonces le devuelven una ubicación nula.

La única manera de garantizar que realmente obtenga una ubicación es solicitar una, y esto se hace con una llamada a requestLocationUpdates() .

La ubicación pasada al método de callback onLocationChanged() no será nula, ya que la callback solo se produce en un locking de ubicación exitosa.

Solo para tener en cuenta, todo el tiempo que su aplicación se registre para las actualizaciones de ubicación, causará un extra de batería, así que asegúrese de anular el registro de actualizaciones de ubicación tan pronto como sea posible. Aquí parece que puede cancelar su registro tan pronto como ingrese la primera ubicación.

Además, es posible que desee considerar la posibilidad de mostrar un cuadro de diálogo de progreso en esta Actividad mientras espera un locking de ubicación para darle al usuario algunos comentarios de que la aplicación está esperando algo.

Aquí está la estructura general de cómo debería verse su código:

 public class MainActivity extends Activity implements LocationListener { Intent intentThatCalled; public double latitude; public double longitude; public LocationManager locationManager; public Criteria criteria; public String bestProvider; String voice2text; //added @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); intentThatCalled = getIntent(); voice2text = intentThatCalled.getStringExtra("v2txt"); getLocation(); } public static boolean isLocationEnabled(Context context) { //............... return true; } protected void getLocation() { if (isLocationEnabled(MainActivity.this)) { locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE); criteria = new Criteria(); bestProvider = String.valueOf(locationManager.getBestProvider(criteria, true)).toString(); //You can still do this if you like, you might get lucky: Location location = locationManager.getLastKnownLocation(bestProvider); if (location != null) { Log.e("TAG", "GPS is on"); latitude = location.getLatitude(); longitude = location.getLongitude(); Toast.makeText(MainActivity.this, "latitude:" + latitude + " longitude:" + longitude, Toast.LENGTH_SHORT).show(); searchNearestPlace(voice2text); } else{ //This is what you need: locationManager.requestLocationUpdates(bestProvider, 1000, 0, this); } } else { //prompt user to enable location.... //................. } } @Override protected void onPause() { super.onPause(); locationManager.removeUpdates(this); } @Override public void onLocationChanged(Location location) { //Hey, a non null location! Sweet! //remove location callback: locationManager.removeUpdates(this); //open the map: latitude = location.getLatitude(); longitude = location.getLongitude(); Toast.makeText(MainActivity.this, "latitude:" + latitude + " longitude:" + longitude, Toast.LENGTH_SHORT).show(); searchNearestPlace(voice2text); } @Override public void onStatusChanged(String provider, int status, Bundle extras) { } @Override public void onProviderEnabled(String provider) { } @Override public void onProviderDisabled(String provider) { } public void searchNearestPlace(String v2txt) { //..... } } 

Cambie esto en su método getLocation

 if (isLocationEnabled(PlacesDecoder.this) && location != null) { ... } 

La excepción del puntero nulo se produce porque su aplicación no solicita la ubicación actual, sino que usa la última ubicación encontrada y simplemente comprueba que haya activado su ubicación y ejecute cualquier otra aplicación que use su ubicación actual. Después de eso solo intenta ejecutar tu proyecto nuevamente. Espero que esto resuelva tu problema.