I am developing an android application in which I need to get my current Location. I have successfully wrote the code and I am getting my current location using Google Play Service.
The problem is sometimes it gives me the location after a long time. I have noticed that it was only for first use of the app.
Any way to avoid this problem and get the current location fast? Is it related to the version of google play service in my code? (I am not using the last one in fact I am using version 9.8.0.)
As #tahsinRupam said, avoid using getLastLocation as it has a high tendency to return null. It also does not request a new location, so even if you get a location, it could be very old, and not reflect the current location. You might want to check the sample code in this thread: get the current location fast and once in android.
public void foo(Context context) {
// when you need location
// if inside activity context = this;
SingleShotLocationProvider.requestSingleUpdate(context,
new SingleShotLocationProvider.LocationCallback() {
#Override public void onNewLocationAvailable(GPSCoordinates location) {
Log.d("Location", "my location is " + location.toString());
}
});
}
You might want to verify the lat/long are actual values and not 0 or something. If I remember correctly this shouldn't throw an NPE but you might want to verify that.
Here's another SO post which might help:
What is the simplest and most robust way to get the user's current location on Android?
Related
I'm trying to set some protection against people using mock locations to manipulate my app. I realise that it's impossible to prevent 100%... I'm just trying to do what I can.
The app uses Google location services (part of play services) in its main activity.
The onLocationChanged() method is:
public void onLocationChanged(Location location) {
this.mCurrentLocation = location;
if (Build.VERSION.SDK_INT > 17 && mCurrentLocation.isFromMockProvider()) {
Log.i(TAG, "QQ Location is MOCK");
// TODO: add code to stop app
// otherwise, currently, location will never be updated and app will never start
} else {
Double LAT = mCurrentLocation.getLatitude();
Double LON = mCurrentLocation.getLongitude();
if ((LAT.doubleValue() > 33.309171) || (LAT.doubleValue() < 33.226442) || (LON.doubleValue() < -90.790165) || (LON.doubleValue() > -90.707081)) {
buildAlertMessageOutOfBounds();
} else if (waiting4FirstLocationUpdate) {
Log.i(TAG, "YYY onLocationChanged() determines this is the FIRST update.");
waiting4FirstLocationUpdate = false;
setContentView(R.layout.activity_main);
startDisplayingLists();
}
}
}
The location services work perfectly and all is well with the app in general, but when I run the app in an emulator with Android Studio (Nexus One API 23), and I set the location using extended controls (mock), the app just continues to work as normal, and so it seems that the condition:
if (Build.VERSION.SDK_INT > 17 && mCurrentLocation.isFromMockProvider())
Is returning false.
This doesn't make any sense to me. Does anyone know why this would happen?
Thanks!
The short answer: .isFromMockProvider is unreliable. Some fake locations are not properly detected as such.
I have spent an extensive amount of time researching this and written a detailed blog post about it.
I also spent time to find a solution to reliably suppress mock locations across all recent/relevant Android versions and made a utility class, called the LocationAssistant, that does the job.
In a nutshell (using the aforementioned LocationAssistant):
Set up permissions in your manifest and Google Play Services in your gradle file.
Copy the file LocationAssistant.java to your project.
In the onCreate() method of your Activity, instantiate a LocationAssistant with the desired parameters. For example, to receive high-accuracy location updates roughly every 5 seconds and reject mock locations, call new LocationAssistant(this, this, LocationAssistant.Accuracy.HIGH, 5000, false). The last argument specifies that mock locations shouldn't be allowed.
Start/stop the assistant with your Activity and notify it of permission/location settings changes (see the documentation for details).
Enjoy location updates in onNewLocationAvailable(Location location). If you chose to reject mock locations, the callback is only invoked with non-mock locations.
There are some more methods to implement, but essentially this is it. Obviously, there are some ways to get around mock provider detection with rooted devices, but on stock, non-rooted devices the rejection should work reliably.
Im using GoogleMap.OnMyLocationChangeListener to get the current location (below)
private GoogleMap.OnMyLocationChangeListener myLocationChangeListener = new GoogleMap.OnMyLocationChangeListener() {
#Override
public void onMyLocationChange(Location location) {
start = new LatLng(location.getLatitude(), location.getLongitude());
map.addMarker(new MarkerOptions().position(start));
}
};
However, I need a way to wait for the listener to complete. Reason being that, Start var will obviously be null if I continue to execute other code without location data. I thought that AsyncTask might be useful here, but have no idea what to call inside doInBackground/onPostExecute.
map.setOnMyLocationChangeListener(myLocationChangeListener); // set the listener
// perform wait and initiate start variable
String url = getDirectionsUrl(start, destination);
// a sync task here using the url
Any hints or code snippets would be much appreciated~!
I need the location information after setting the listener
That is not possible. There may not be any "location information after setting the listener". It may take some time to get a location fix. Given your existing code, your first opportunity to have location data will be in onMyLocationChange(), and you cannot use the location data before that point.
Also note that setOnMyLocationChangeListener() has been deprecated for about a year. Quoting the documentation:
This method is deprecated.
use FusedLocationProviderApi instead. FusedLocationProviderApi provides improved location finding and power usage and is used by the "My Location" blue dot. See the MyLocationDemoActivity in the sample applications folder for example example code, or the Location Developer Guide.
To be clear: This is an activity in my Android application that is meant to pull the coordinates for the users location using the GPS_PROVIDER. The Activity contains a button which, when pressed, should initiate a method that obtains the coordinate data. The problem is that the application crashes when there is no previously known location information (ie if the phone was recently reset). If I open up the Maps application (for example) and pinpoint my location, then re-open my own application and run this method, it works as intended. My question is why is this crashing and/or how can I prevent this crash from occurring? Help is appreciated, thanks.
This method is run when the button is pressed - and an intent response is generated back to the calling activity when the coordinates are properly found:
protected void getCurrentLocation() {
Location location = null;
try {
location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
} catch (IllegalArgumentException iae) { }
if (location != null) {
longV = location.getLongitude();
latV = location.getLatitude();
response(longV, latV);
} else {
getCurrentLocation();
}
I'm guessing that you are receiving a StackOverflowException, because if location is null you call the exact same function creating an indefinite loop...
If there is no last know location, you need to request a new location. (getLastKnownLocation() will not change on its own no matter how many times you call it.)
I want the exact location of user. So I created two listeners as:
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, mGPSListener);
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, mNetworkListener);
I am listening for location updates from both the network and gps providers and wanted to check the accurary of locations obtained by both so that I can pick the accurate location. I just want to ask am I using the right way of acheiving that...??? if not, please provide some guideline how to do this...???
My example code is:
if(MyGPSListener.currentLocation != null) {
if(MyNetworkListener.currentLocation != null) {
if(MyGPSListener.currentLocation.getAccuracy() <= MyNetworkListener.currentLocation.getAccuracy()) {
useGPSLocation();
}
else if(MyGPSListener.currentLocation.getAccuracy() > MyNetworkListener.currentLocation.getAccuracy()) {
useNetworkLocation();
}
}
else {
useGPSLocation();
}
}
else if(MyNetworkListener.currentLocation != null){
useNetworkLocation();
}
You should take a look at: http://developer.android.com/guide/topics/location/obtaining-user-location.html
Especially the function: isBetterLocation
I would probably use something like the isBetterLocation. Since it's actually quite important to see how old the location updates are. At least if you really want to know where the user is know and not where the user were.
But you can surely implement a time check in your own function which you described.
You can use https://github.com/balwinderSingh1989/androidBestLocationTracker
Android Best Location Tracker is an Android library that helps you get user best location with a object named BaseLocationStrategy that would give a accurate location using accuracy alogrithm.
It has added support till latest android api levels and can fetch location in background with ease.
For usage, refer "READ ME" of project.
You can check Google's offical document.
Define a model for the best performance
And Validate the accuracy of a location fix:
Check if the location retrieved is significantly newer than the previous estimate.
Check if the accuracy claimed by the location is better or worse than the previous estimate.
Check which provider the new location is from and determine if you trust it more.
I'm having trouble getting a LocationListener to call the onLocationChanged() callback on my phone. When I run my code in the emulator, it works fine, the callback is called each time I do a geo fix.
When I run the application on my phone, nothing at all happens. The callback is never called. I have location enabled by both GPS and by Wireless in my settings. The application has all of the uses-permissions for location permissions.
Also, when I call getLastKnownLocation() on a LocationManager object, my application crashes. (Still, only on my stupid phone). Even if I try to catch an exception that's causing it to crash, it still just crashes, so I can't even get any information on what is causing it to crash. This is extremely frustrating.
LocationManager.getBestProvider() is returning GPS, and when I open google maps it finds my location in no time at all. What the heck is going on here? Is there some way I can figure out why it's crashing on my phone?
private void setupLocListener(){
Criteria c = new Criteria();
c.setAccuracy(Criteria.ACCURACY_FINE);
c.setAltitudeRequired(false);
c.setBearingRequired(false);
c.setSpeedRequired(false);
c.setCostAllowed(false);
lm.requestLocationUpdates(lm.getBestProvider(c,true), 0, 0, new LocationListener() {
#Override
public void onLocationChanged(Location arg0) {
map.setLocation(arg0);
}
public void onProviderDisabled(String arg0) {
}
public void onProviderEnabled(String arg0) {
}
public void onStatusChanged(String arg0, int arg1, Bundle arg2) { }
});
}
onLocationChanged() wont fire until you actually start receiving GPS coordinates.
By that I mean the chip has to warm up for about a minute or so from my experience before you start receiving data from it.
I usually start some other application and wait for it to prove that the GPS chip has warmed up before I go testing any of my GPS apps.
I know that you mentioned that it works properly in Google Maps but have you tried clearing your memory and restarting your application straight away afterwards?
Also getLastKnownLocation() is always null until you start receiving coords.
The Location framework pushes coordinates to your callback, when they become available. Depending on weather, etc. you may not get a "fix" initially. You should see the "GPS" indicator on the status bar when your listener is successfully registered.
getLastKnownPosition() works just fine (it may return null); and Google Maps uses that, while it is waiting for an initial fix from the location provider.
You may also want to see what other providers are available, e.g. cell-tower data, and attempt to obtain data from those (i.e. LKP), either instead of, or until, your "preferred" provider starts pushing data.
Also, don't assume any particular service exists, e.g. LocationManager (Context.getSystemService() can return null), or any suitable provider exists, (getBestProvider() can return null). Your code will fail as-is on the right device with the right settings. If the documentation says null you must check for it, or users will be uninstalling it because it FC's all over the place.