23

All I am trying to do is let the user get a list of the places of types he likes. For example if the input was hospital my application would open google maps with the search string "Hospital". But as suggested in the documentation using the geocode like geo:0,0?q=hospital uri shows all the hospitals near the coordinates 0 latitude & 0 longitude. So when I tried to get the users coordinates first by using the following code.

Places 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();
        }
    }
}
}

The problem is that always and always location returns null. And I know for a fact that another application Jarvis easily does the task as long as location is enabled, if not is simply asks the user to. But under the same conditions my application always crashes.

What I have done:

  1. Spent Day and Night trying to solve this problem.
  2. Browsed through numerous pages on the topic.
  3. Tried different codes of my own.

And it still happens. I am a beginner in Android. And please, please do help me. Is there no possible way to solve my problem? even thought that other application somehow manages to do it.

This my 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)

Also checking for location!=null requires ACCESS_FINE_LOCATION permission which messes up my app causing it to always return as null.

KISHORE_ZE
  • 1,466
  • 3
  • 16
  • 26
  • 4
    So `getLastKnownLocation` is returning null, which it's documented can happen: "If the provider is currently disabled, null is returned." Your code should check for that and handle it accordingly. You say "under the same conditions" - are those conditions that location is currently disabled? Because if so, there's nothing else to explain, really. – Jon Skeet Aug 29 '15 at 19:49
  • How should I do that? Under the same conditions the other app does that. Or could there be a way to solve my problem without getting the user's location. Please do help. – KISHORE_ZE Aug 29 '15 at 19:52
  • I am sorry if I am pressurising you or something but I am really frustrated that I can't even solve something this simple even after scouring the Web to the best I can. Sorry. It's already over midnight over here and I still can't stop this issue from occuring. – KISHORE_ZE Aug 29 '15 at 19:55
  • @Jon Skeet No location is switched on. My app crashes. It succeeds. If location is off both our apps direct the user to the settings page to switch it on. – KISHORE_ZE Aug 29 '15 at 19:58
  • 1
    Right, so the API is behaving *exactly as documented*. You should check whether `location` is `null` before you call any methods on it: `if (location == null) { /* take appropriate action */ } else { /* use location */ }` – Jon Skeet Aug 29 '15 at 20:08
  • Please do see my above edit. Is there a way to do this without getting the user's lastKnownLocation. – KISHORE_ZE Aug 29 '15 at 20:09
  • Checking a reference doesn't require any special permission. Checking for a fine-grained location might, but that's not the same thing. And I don't know what you mean by "do this"... you should put effort into making your question clear. (I would suggest removing all reference to a NullPointerException - we know what's null and why, so the exception is pretty much irrelevant.) – Jon Skeet Aug 29 '15 at 20:13
  • I am sorry All I am trying to do is let the user get a list of the places of types he likes. For example if the input was hospital my application would open google maps with the search string "Hospital". But as suggested in the documentation using the geocode like geo:0,0?q=hospital uri shows all the hospitals near the coordinates 0 latitude & 0 longitude. – KISHORE_ZE Aug 29 '15 at 20:16
  • I am guessing that the other application should also be getting a null pointer exception if trying to get the users location. So is there another way? It was documented in the maps api that Google maps could search the nearby location if you put latitude 0 and longitude 0 but this doesn't work – KISHORE_ZE Aug 29 '15 at 20:18
  • No, I suspect the other application is checking whether it's receiving a null location in a normal way. – Jon Skeet Aug 29 '15 at 20:19
  • @Jon Skeet 08-30 01:54:42.735 11831 11831 E SELinux [DEBUG] get_category: variable seinfo: default sensitivity: NULL, cateogry: NULL 08-30 01:54:43.335 11831 11831 E AndroidRuntime FATAL EXCEPTION: main 08-30 01:54:43.335 11831 11831 E AndroidRuntime Process: com.mycompany.myapp4, PID: 11831 08-30 01:54:43.335 11831 11831 E AndroidRuntime java.lang.RuntimeException: Unable to start activity ComponentInfo{com.mycompany.myapp4/com.mycompany.myapp4.MainActivity}: – KISHORE_ZE Aug 29 '15 at 20:26

7 Answers7

34

As Jon Skeet mentioned in the comments, the getLastKnownLocation() method can and will return null. The main problem is that it doesn't prompt a request to the OS for a new location lock, instead it just checks if there was a last known location from some other app's location request. If no other app had recently made a location request, then you get a null location returned to you.

The only way to guarantee that you actually get a location is to request one, and this is done with a call to requestLocationUpdates().

The location passed into the onLocationChanged() callback method will not be null, since the callback only occurs on a successful location lock.

Just to note, the entire time your app is registered for location updates, it will be causing extra battery drain, so be sure to un-register for location updates as soon as possible. Here it looks like you can un-register as soon as the first location comes in.

Also, you might want to consider showing a progress dialog in this Activity while it waits for a location lock in order to give the user some feedback that the app is waiting on something.

Here is the general structure of what your code should look like:

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) {
        //.....
    }
}
Daniel Nugent
  • 43,104
  • 15
  • 109
  • 137
  • Thanks for the answer I'll try it and let you know. – KISHORE_ZE Aug 30 '15 at 02:57
  • Thanks. Its working! Thank you so much. It finally worked. I also added a loading screen or rather a `Progress Dialog` and its working perfectly now. Once again, Thanks a Lot Daniel. – KISHORE_ZE Aug 30 '15 at 03:57
  • I thought you said you weren't able to compare `location` with `null`, which is what this code does... – Jon Skeet Aug 30 '15 at 08:18
  • @Jon Skeet I removed the `location!=null`. Daniel Nugent said it was not really required. And it's working like a charm. It's because I just switch on Location Service and immediately ask for location that it crashes. It requires time to locate it. Especially on weak connections. Daniel Nugent's Solution keeps waiting for the location to be set and then does the job. Making it, I hope, completely error proof. Also his idea of a wait screen,i.e., my progress dialog kind of fills wait time, making it run kinda smooth. Anyway guys thanks a lot for your efforts, I really appreciate it. – KISHORE_ZE Aug 30 '15 at 18:43
  • @kishore just to note, calling getLastKnownLocation() is optional, but if you call it, doing a null check on the result is not optional! (Unless you're ok with the app crashing!) – Daniel Nugent Aug 30 '15 at 23:29
  • Ok thanks for the info. @Jon Skeet and Daniel Nugent just to check I added a non null check on it and simply never started the process since it seems to always return null because of what Daniel Nugent explained above. But just asking is there a way to simply pass a search string to Google maps? I think I'll check it's Manifest and let you guys know. – KISHORE_ZE Aug 31 '15 at 04:08
  • @kishore Notice in the code in the answer, the call to requestLocationUpdates() is in the else statement, and the if statement is `if (location!=null)`. Basically, either use the location immediately if it's not null, otherwise request a location. – Daniel Nugent Aug 31 '15 at 04:58
  • Ok thanks. I'll do that. BTW it will decrease the loading time too if there is already a lastKnownLocation right? – KISHORE_ZE Aug 31 '15 at 05:00
  • Also any idea where to find the Google Maps Manifest file. Searched google and Github. Converted apk to zip opened manifest but it's encoded. Any other way? Thanks. – KISHORE_ZE Aug 31 '15 at 05:01
  • Thanks Daniel. On my Nexus-5, I observed that getLastLocation returns null even after I launch Google Map app and then launch my app again. Even if location is detected correctly in Google Map app, getLastLocation API returns null. I did not understand: If Google Map had requested for location then why cached location was not updated. Also, I have seen getLastLocation API working even if no other app makes location request – srs Apr 18 '17 at 08:24
1

Change this in your getLocation method

if (isLocationEnabled(PlacesDecoder.this) && location != null) {
 ...
}
Stas Parshin
  • 7,973
  • 3
  • 24
  • 43
  • Also checking for location!=null requires ACCESS_FINE_LOCATION permission which messes up my app causing it to always return as null. – KISHORE_ZE Aug 29 '15 at 20:17
  • @KISHORE_ZE: As I've said in other comments, that's just not true. It's just comparing a reference with null - how could that require more permissions? *Getting* the location might (although it sounds like you should just request that permission anyway) but that's not the same as checking whether or not it's null. – Jon Skeet Aug 29 '15 at 20:18
  • But it's asking me. If you want I'll show you the logcat. I don't have the PC now but I'll compile it in the phone and let you know. – KISHORE_ZE Aug 29 '15 at 20:19
  • @Jon Skeet 08-30 01:54:42.735 11831 11831 E SELinux [DEBUG] get_category: variable seinfo: default sensitivity: NULL, cateogry: NULL 08-30 01:54:43.335 11831 11831 E AndroidRuntime FATAL EXCEPTION: main 08-30 01:54:43.335 11831 11831 E AndroidRuntime Process: com.mycompany.myapp4, PID: 11831 08-30 01:54:43.335 11831 11831 E AndroidRuntime java.lang.RuntimeException: Unable to start activity ComponentInfo{com.mycompany.myapp4/com.mycompany.myapp4.MainActivity}: – KISHORE_ZE Aug 29 '15 at 20:26
  • Did both of you get it – KISHORE_ZE Aug 29 '15 at 20:26
  • @Jon Skeet This is what always happens. Why does this happen? – KISHORE_ZE Aug 29 '15 at 20:28
  • Well I *don't* think it happens because you're comparing a reference with null. But I'm done here, I think - I don't think we're getting anywhere. – Jon Skeet Aug 29 '15 at 20:29
  • @Jon Skeet that's it? There is no solution – KISHORE_ZE Aug 29 '15 at 20:32
  • @Jon Skeet if it can do it why can't I? – KISHORE_ZE Aug 29 '15 at 20:32
  • 1
    There may well be a solution, but you seem convinced that you can't compare a reference with null, which seems very unlikely to me, so I don't thin *I* can help you further. Additionally, I'm going to bed... – Jon Skeet Aug 29 '15 at 20:34
  • No I tried. It worked before with different other stuff but it's not working with this. Why is this so? – KISHORE_ZE Aug 29 '15 at 20:36
  • @Jon Skeet is there anyway you can simply pass the search string to it. – KISHORE_ZE Aug 29 '15 at 20:37
  • @Jon Skeet or pengrad are you guys there? – KISHORE_ZE Aug 29 '15 at 20:45
1

you wrote codes that get your current location (latlng) and this error is because of your gps(location) on your real android device is not turn on. I turned it on and it works for me. hope to be useful

Mosayeb Masoumi
  • 481
  • 4
  • 10
  • Please note that this function returns the last known location from the previous app which used the API. Thus, it does not work on his device/emulator. – Rudra Saraswat Jun 17 '20 at 07:57
1

here is another way to do this one your fuse location concept i have used this and was successfull to me mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);

is declaration fused location

 @SuppressWarnings( {"MissingPermission"})
private void enableLocationComponent() {
    System.out.println("on map click is here in permission///////////////");
    // Check if permissions are enabled and if not request
    if (PermissionsManager.areLocationPermissionsGranted(this)) {

        // Activate the MapboxMap LocationComponent to show user location
        // Adding in LocationComponentOptions is also an optional parameter
        LocationComponent locationComponent = mapboxMap.getLocationComponent();
        locationComponent.activateLocationComponent(this);
        locationComponent.setLocationComponentEnabled(true);
        // Set the component's camera mode
        locationComponent.setCameraMode(CameraMode.TRACKING);

        mFusedLocationClient.getLastLocation().addOnSuccessListener(this, new OnSuccessListener<Location>() {
                    @Override
                    public void onSuccess(Location location) {
                        originLocation=location;
                        // Got last known location. In some rare situations this can be null.
                        if (location != null) {
                            originLocation=location;
                            System.out.println(" permission granted location is in iff ++///////////////"+location);
                        }
                    }
                });

        //originLocation = locationComponent.getLastKnownLocation();
        System.out.println("origin location is that//////////"+originLocation);


    } else {


        permissionsManager = new PermissionsManager(this);
        permissionsManager.requestLocationPermissions(this);
    }
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    permissionsManager.onRequestPermissionsResult(requestCode, permissions, grantResults);
    Toast.makeText(this, "granted", Toast.LENGTH_LONG).show();
}

@Override
public void onExplanationNeeded(List<String> permissionsToExplain) {
    Toast.makeText(this, R.string.user_location_permission_explanation, Toast.LENGTH_LONG).show();
}

@Override
public void onPermissionResult(boolean granted) {
    if (granted) {
        enableLocationComponent();
    } else {
        Toast.makeText(this, R.string.user_location_permission_not_granted, Toast.LENGTH_LONG).show();``
        finish();
    }
}
Qasim
  • 21
  • 4
0

Null pointer exception occurs because your app doesn't request for the current location it rather it uses last found location and just checks you've turned your location on and run any other app which uses your current location. After that just try to run your project again. Hope this solves your problem.

0

As Said by Yash your App does not request for the current Location rather it uses last found location a simple work around that worked for me for this Error is that, Switch On your GPS and open your google maps app on your mobile or emulator see your current Location and then close it. Now , when your open your Current App (You working on) or run it ,it would not give this error. worked for me.

manojkragy
  • 19
  • 1
0

I got the same problem using .getLastLocation(). Then I used mMap.setMyLocationEnabeled(true), and got the GPS location using the on map location button enabled by the .setMyLocationEnabeled(true). After that the next time .getLastLocation() worked fine. I don't know the exact reason but I think the on map location button once saved my current location and the next time I used .getLastLocation(), it was not null because the last location was already there.

m02ph3u5
  • 3,022
  • 7
  • 38
  • 51