I've an app which allows usage if user is in certain area, meaning I don't need to track the user, but I need to make sure location that's received is fresh (even if it requires waiting).
What's the best way to do this? Currently using:
getLastLocation()
but it can sometimes get previous location, understandably.
You can register a location listener and proceed to the code if the location condition is met:
locationCallback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
if (locationResult == null) {
return;
}
for (Location location : locationResult.getLocations()) {
//if(this is the location) jump to the code which makes the app usable
}
//stay unusable
};
};
getting the location might take some time. If by force you mean holding the ui thread until the precise-enough location is available then force getting the location is a bad but feasible idea.
Related
I'm trying to show the location of a DJI Drone on the Mapbox map and constantly update it's location.
This is what I'm doing.
private void addDroneMarker(double latitude, double longitude){
Bitmap bitmap = ((BitmapDrawable)getResources().getDrawable(R.drawable.aircraft_icon)).getBitmap();
AnnotationPlugin annotationAPI = AnnotationPluginImplKt.getAnnotations(mapView);
pointAnnotationManager = PointAnnotationManagerKt.createPointAnnotationManager(annotationAPI, new AnnotationConfig());
PointAnnotationOptions pointAnnotationOptions = new PointAnnotationOptions()
.withPoint(Point.fromLngLat(longitude, latitude))
.withIconImage(bitmap);
dronePoint = pointAnnotationManager.create(pointAnnotationOptions);
}
private void updateDroneMarker(double latitude, double longitude){
dronePoint.setPoint(Point.fromLngLat(longitude, latitude));
pointAnnotationManager.update(dronePoint);
}
private void initFlightController(){
BaseProduct product = FPVApplication.getProductInstance();
if (product != null && product.isConnected()) {
if (product instanceof Aircraft) {
mFlightController = ((Aircraft) product).getFlightController();
}
}
if (mFlightController != null) {
mFlightController.setStateCallback(new FlightControllerState.Callback() {
#Override
public void onUpdate(FlightControllerState djiFlightControllerCurrentState) {
droneLocationLat = djiFlightControllerCurrentState.getAircraftLocation().getLatitude();
droneLocationLng = djiFlightControllerCurrentState.getAircraftLocation().getLongitude();
updateDroneMarker(droneLocationLat, droneLocationLng);
}
});
}
}
I create the drone annotation when the map loads and everytime the drone gives me a new location from the callback I update its location.
But my problem is, sometimes when I'm moving the map it gives me an error
Error while setting camera options : std::exception
This error could cause the application to crash with a Fatal Error
Fatal signal 11 (SIGSEGV), code 2 (SEGV_ACCERR), fault addr 0x787c881d0c in tid 17420 (RenderThread), pid 17347
And I realized that this error was caused by the UpdateDroneMarker (maybe because of the camera Animation), so I'm trying to find a different way to update the drones location. Hope someone could help me, thank you.
Try running on ui thread. I don't know for specific for mapbox, however callbacks from dji are not running on ui thread, so I would try that first. Otherwise you will get all kinds of strange errors.
After several (unsuccessful) attempts to make my applications compliant about the background access to the location, I decided to re-structure my code in order to remove the ACCESS_BACKGROUND_LOCATION permission from the manifest.
My application necessarily needs to get the location of the device at certain times (specifically I need the coordinates), what I'm interested in knowing is:
without using the permission mentioned above, how do I get, in foreground, the location of the device?
is it possible to do it with a one-time call without using services etc?
I thought about using this code, do you think it could be enough?
LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
Location lastKnownLocation = locationManager.getLastKnownLocation(locationProvider);
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
mFusedLocationClient.getLastLocation()
.addOnSuccessListener(this, new OnSuccessListener<Location>() {
#Override
public void onSuccess(Location location) {
if (location != null) {
// Logic to handle location object
}
}
});
or something like this:
LocationManager mLocationManager = (LocationManager) context.getSystemService(LOCATION_SERVICE);
List<String> providers = mLocationManager.getProviders(true);
Location bestLocation = null;
for (String provider : providers) {
Location location = mLocationManager.getLastKnownLocation(provider);
if (location == null) {
continue;
}
if (bestLocation == null || location.getAccuracy() < bestLocation.getAccuracy()) {
bestLocation = location;
}
}
is there a better way to do this?
To get the last know location you need to have following permissions declared in Manifest file.
"android.permission.ACCESS_FINE_LOCATION"
Then you may use Fused Location Provider as you have used.
Now if you want periodic updates you may want to register for those updates using following callback.
requestLocationUpdates
passed with a request object and callback to receive updates.
Helpful links with exact code: Request Updates
I've implemented user geolocation tracking with the following:
#1
locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
locationListener = new LocationListener() {
#Override
public void onLocationChanged(Location location) {
mMap.clear();
repaintUserLocationPin(location);
}
#2
locationProviderClient = LocationServices.getFusedLocationProviderClient(this);
locationRequest = new LocationRequest();
locationRequest.setInterval(3000);
locationRequest.setFastestInterval(3000);
locationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
LocationCallback locationCallback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
List<Location> locationList = locationResult.getLocations();
if (locationList.size() > 0) {
//The last location in the list is the newest
Location location = locationList.get(locationList.size() - 1);
mLastLocation = location;
if (mCurrLocationMarker != null) {
mCurrLocationMarker.remove();
}
repaintUserLocationPin(mLastLocation);
}
}
};
To summarize IMHO:
These both seem to achieve the same,track and update the current user's location.
At the end of the day, they are both equally verbose and have the same complexity.
#2 needs new 'implementation' libraries but, this isn't much of an overhead
On the other hand, there is a 3rd solution but this doesn't allow me to get the updated current location unless, I click on the Geolocate button in the map. I'm talking about:
map.setOnMyLocationButtonClickListener(new GeolocateBtnClickListener(MapsActivity.this));
map.setOnMyLocationClickListener(new GeolocateClickListener(MapsActivity.this));
This has one BIG advantage, and it's that the marker is automatically created and it is much more responsive to the user's movements. For example, it points in the directo that the user is pointing at.
So, Why use one over the other or in what cases would you recommend using one over the other?
All the below is just my opinions
These both seem to achieve the same,track and update the current
user's location.
The difference can be realized with their location obtain ways. LocationManager gives us chance of choosing the location source. So then we can pick any source from gps, network and passive alternatives. But LocationServices does not give this chance, instead gives taste of location, the momentum of between quality and battery usage.
At the end of the day, they are both equally verbose and have the same
complexity.
Configuring them seems a bit same, but LocationServices could be first option. Deciding quality/power seems more reasonable than dealing with providers.
#2 needs new 'implementation' libraries but, this isn't much of an overhead
LocationManager is available from version 1, while LocationServices is available if device supports play services.
I made a geotagged social report application to report broken streets on Android. It requires location data to post a report. Either from photo's Exif, Gps sensor or set it manually from MapsPickerActivity.
I managed to make the location request using RxLocation library. There's a button that's being made enabled when the app is still getting the location from Gps. Since getting a location data from Gps might take a while, I let the user to just set a location manually at the same time. I want to stop the getGpsLocationObservable if the user pressed the button. If I don't stop the getGpsLocationObservable, I'm afraid the process would still be running and come after setting a custom location. That would be annoying.
How could I achieve that?
Here's snippets of the simplified code
Main disposable :
Disposable myDisposable = imageProcessingObservable()
.compose(getExifLocationTransformer()) //custom location button enabled here
.filter(isLocationSet -> isLocationSet)
.flatmap(x->getGpsLocationObservable());
RxLocation getGpsLocationObservable :
private Observable<String> getGpsLocationObservable(){
locationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setNumUpdates(1)
.setInterval(3000);
rxLocation = new RxLocation(PostActivity.this);
rxLocation.setDefaultTimeout(10, TimeUnit.SECONDS);
return rxLocation.settings()
.checkAndHandleResolution(locationRequest)
.flatMapObservable(isActivated->{
if (isActivated) {
return locationSettingsActivatedObservable();
}
else locationNotFoundObservable();
});
}
#SuppressLint("MissingPermission")
private Observable<String> locationSettingsActivatedObservable(){
return rxLocation.location().updates(locationRequest)
.map(location -> {
LatLng latLng = new LatLng(location.getLatitude(),location.getLongitude());
String street = getStreetName(latLng);
return street;
})
.doOnNext(street->{
updateUI(street);
});
}
I guess it's a great use case for .amb() operator which only takes output of the observable which started emitting first and ignores all others. See http://reactivex.io/RxJava/javadoc/rx/Observable.html#amb-rx.Observable-rx.Observable-
Hie, im new in using arcgis in Android to display map on Android phone.
I manage to display the map on the Android phone, however , i am having difficulties to show the current location.
As in,at your current location, it would display a small blue dot.
Do you guys know how to show your current location using arcgis ?
Thanks in advance.
All you need to do it get the MapView's LocationService and call start() on it. But you need to do it after the map has been initialized. Here's a simple way to do that in your Activity's onCreate method (assuming your MapView is named map):
map = (MapView) findViewById(R.id.map);
map.setOnStatusChangedListener(new OnStatusChangedListener() {
#Override
public void onStatusChanged(Object source, STATUS status) {
if (STATUS.INITIALIZED == status) {
map.getLocationService().start();
}
}
});
//Then add layers to the map