Getting location when the app is closed using fusedLocationProviderClient - java

I am currently working on a location-based reminder app.
Obviously, the should send a notification when the user is close to a location he set.
For that, I am using a foreground service - which starts when the app starts. It also works when the app is closed, like swiped up from the apps list (not force stopped).
In the service, I am getting the current location and iterating over the location to see which ones I should send a notification for.
Every thing works fine, but for some reason, when the app is closed, the service doesn't enter the onLocationResult:
LocationServices.getFusedLocationProviderClient
(ServiceLocationNotification.this).requestLocationUpdates(locationRequest, new LocationCallback() {
#Override
public void onLocationResult(#NonNull LocationResult locationResult) {
GetCurrentLocationAsyncTaskServiceLocationNotification task =
new GetCurrentLocationAsyncTaskServiceLocationNotification
(ServiceLocationNotification.this,
locationResult,
this);
try
{
currentLatLng = task.execute().get();
}
catch (Exception e)
{
System.out.println("Exception");
e.printStackTrace();
}
}
},
Looper.getMainLooper()); // Use the main thread's looper to receive location updates
(I checked with prints).
GetCurrentLocationAsyncTaskServiceLocationNotification (sorry for the long name) is a class i created to retrieve the current location and get the latLng out of it:
// for the ServiceLocationNotification class.
public class GetCurrentLocationAsyncTaskServiceLocationNotification extends AsyncTask<Void, Void, LatLng>
{
private WeakReference<ServiceLocationNotification> ServiceLocationNotificationWeakReference;
private LocationCallback locationCallback;
private LocationResult locationResult;
GetCurrentLocationAsyncTaskServiceLocationNotification(ServiceLocationNotification activity,
#NonNull LocationResult locationResult,
LocationCallback locationCallback)
{
ServiceLocationNotificationWeakReference = new WeakReference<>(activity);
this.locationResult = locationResult;
this.locationCallback = locationCallback;
}
// .execute().get() gets the return value.
#Override
protected LatLng doInBackground(Void... voids)
{
double latitude;
double longitude;
// get location
LocationServices.getFusedLocationProviderClient(ServiceLocationNotificationWeakReference.get())
.removeLocationUpdates(locationCallback);
// Check if the location result is not null and has at least one location
if (locationResult != null && locationResult.getLocations().size() > 0)
{
// Get the most recent location from the location result
int index = locationResult.getLocations().size() - 1;
latitude = locationResult.getLocations().get(index).getLatitude();
longitude = locationResult.getLocations().get(index).getLongitude();
return new LatLng(latitude, longitude);
}
return null;
}
}
I would appreciate any help understanding why this happens (not entering the onLocationResult function).
Thanks!

Related

How can I cat latitude and longitude of Android device?

So I'm making this app which finds restaurants near you, fetching information from a food-delivery app, using JSoup library.
The only problem with it is that sometimes the latitude and the longitude are getting null value.
Situations in which my application is working:
-turning on GPS and the waiting at least 1-2 minutes;
-opening google maps, closing it, and then returning to the application;
So the main problem: I can't fetch the location right after I enable it and hit the 'Find restaurants' button, I need to wait 1-2 minutes after enabling location, then it's working.
private TextView result;
private FusedLocationProviderClient client;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
requestPermission();
client = LocationServices.getFusedLocationProviderClient(this);
getBtn = findViewById(R.id.getRestaurants);
result = findViewById(R.id.restaurantsList);
getBtn.setOnClickListener(this);
}
private void requestPermission(){
ActivityCompat.requestPermissions(this, new String[]{ACCESS_FINE_LOCATION}, 1 );
}
public void onClick(View v) {
if (ActivityCompat.checkSelfPermission(MainActivity.this, ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED){
return;
}
client.getLastLocation().addOnSuccessListener(MainActivity.this, new OnSuccessListener<Location>() {
#Override
public void onSuccess(Location location) {
result.setText("Getting location...");
if(location != null){
double latitude = getLat(location);
double longitude = getLng(location);
result.setText("Finding restaurants near you...");
getWebsite(latitude, longitude);
}else{
result.setText("Couldn't fetch location!");
}
}
});
Here is a good way to implement the FusedLocationProvider in Kotlin (you might adapt to Java or use Java and Kotlin side by side) :
private fun startLoc() {
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
try {
fusedLocationClient.lastLocation
.addOnSuccessListener { location: Location? ->
//showDialog(this#MapsActivity, TAG, "last know loc = ${location?.latitude} + ${location?.longitude}")
if (location != null){
lastKnowLoc = LatLng(location.latitude, location.longitude)
addMarkerToLocation(lastKnowLoc)
}
}
val locationRequest = LocationRequest()
locationRequest.interval = 10000
locationRequest.fastestInterval = 10000
locationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult?) {
locationResult ?: return
for (location in locationResult.locations){
//showDialog(this#MapsActivity, "locationResult", "location=${location.latitude};${location.longitude}")
addMarkerToLocation(LatLng(location.latitude, location.longitude))
val speed = location.speed
updateCamera(location.bearing)
}
}
}
fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, null)
btnStartLoc.isEnabled = false
btnStopLoc.isEnabled = true
}catch (e:SecurityException){}
}
you must use requestLocationUpdates()
you are using getLastLocation() and when the GPS is off and turned on after the last known location becomes null so you must call requestLocationUpdates()
you can find more information in the below link
https://developer.android.com/training/location/receive-location-updates

Using mFusedLocationClient to get current location within a firebase service

I'm new to java/android dev so my code may be dumb.
I have a website which uses google maps, I have a button on the website which sends a push cURL message to a specific device using firebase. I want the device to then get the current location and update my database.
I'm using MyFirebaseMessagingService and onMessageReceived to grab the cURL message and that all works fine, it breaks when I start going into the location code. I had various errors so I tried creating a class for getting the location then calling a method of that class within my service.
The class:
public class LocationMedium {
private FusedLocationProviderClient mFusedLocationClient;
private Context mContext;
public LocationMedium(Context context) {
mContext=context;
}
public void getLocation()
{
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(mContext);
if (ActivityCompat.checkSelfPermission(mContext, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(mContext, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
//currently pointless
//return;
}
mFusedLocationClient.getLastLocation()
.addOnSuccessListener((Activity)mContext, new OnSuccessListener<Location>() {
#Override
public void onSuccess(Location location) {
Log.d("mytag", "2222");
// Got last known location. In some rare situations this can be null.
if (location != null) {
// Logic to handle location object
double x = location.getLatitude();
double y = location.getLongitude();
Log.d("mytag1", String.valueOf(x));
Log.d("mytag2", String.valueOf(y));
String user = PreferenceManager.getDefaultSharedPreferences(mContext).getString("USERNAME", "none");
MyFirebaseInstanceIDService firebase = new MyFirebaseInstanceIDService();
firebase.onDeadline(user, x, y);
} else //no location found
{
String user = PreferenceManager.getDefaultSharedPreferences(mContext).getString("USERNAME", "none");
MyFirebaseInstanceIDService firebase = new MyFirebaseInstanceIDService();
firebase.onDeadline(user, 0, 0);
Log.d("mytag", "hmm");
}
}
});
//END OF LOCATION
Log.d("mytag", "theend");
}//end of run
}
And I call it with this from the MyFirebaseMessagingService
if (Objects.equals(user, " location ")) {
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
public void run() {
LocationMedium task = new LocationMedium(context);
task.getLocation();
}
});
}
The error with this I get is:
MyFirebaseMessagingService cannot be cast to android.app.Activity
And it appears to be on this line:
mFusedLocationClient.getLastLocation()
I tried removing the (Activity) bit from:
.addOnSuccessListener((Activity) mContext, new OnSuccessListener<Location>()
and changing it to:
.addOnSuccessListener(mContext, new OnSuccessListener<Location>()
but then I get the error:
Cannot resolve method 'addOnSuccessListener...'
Perhaps I'm going about this completely the wrong way. Any help/suggestions would be appreciated. Thanks.
.addOnSuccessListener(mContext, new OnSuccessListener<Location>()
Replace the above code with this,
.addOnSuccessListener(new OnSuccessListener<Location>()
Worked for me.

getLatitude and getLongitude throws NullPointerException [duplicate]

This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 3 years ago.
Would you please explain me why getLongitude and getLatitude returns a NullPointerException?
The truth is the problem already has been solved, but there's one thing that is bugging me for this might be asked by our thesis coordinator. The situation is that I have to get the user's current coordinates (latitude and longitude). I've decided to use FusedLocationClient.getLastLocation() in order to get the coordinates.
mFusedLocationClient = getFusedLocationProviderClient(this);
//app already crashes once the line below is executed
mFusedLocationClient.getLastLocation().addOnSuccessListener(this, new OnSuccessListener<Location>() {
#Override
public void onSuccess(Location location) {
if(location != null){
//myLocation is an instance variable of this class
myLocation = location;
}else{
Toast.makeText(PlaceCategoriesActivity.this, "Location fetch failed!", Toast.LENGTH_SHORT).show();
}
}
});
latitude = myLocation.getLatitude(); //this line throws NullPointerException
longitude = myLocation.getLongitude();
The app seems to compile fine but then it crashes, upon inspecting by adding a breakpoint for debugging on myLocation.getLatiude() and myLocation.getLongititude(), it turns out that this method invokes a null pointer exception, which for me is weird because myLocation already has referenced the location object brought by the onSuccess method of the addOnSuccessListener.
I've already solved the problem by moving the last two lines of code and putting in within the listener like this:
mFusedLocationClient = getFusedLocationProviderClient(this);
mFusedLocationClient.getLastLocation().addOnSuccessListener(this, new OnSuccessListener<Location>() {
#Override
public void onSuccess(Location location) {
if(location != null){
myLocation = location;
//moved the 2 lines of code and it now works
latitude = myLocation.getLatitude();
longitude = myLocation.getLongitude();
}else{
Toast.makeText(PlaceCategoriesActivity.this, "Location fetch failed!", Toast.LENGTH_SHORT).show();
}
}
});
//Toast returns a value of 0 on latitude and 0 on longitude
Toast.makeText(this, "Lat: " + latitude + "Long: + " + longitude, Toast.LENGTH_SHORT).show();
The funny thing is that the longitude and latitude is shown on the Toast and both has a value of 0.
which for me is weird because myLocation already has referenced the location object brought by the onSuccess method of the addOnSuccessListener
Let's simplify your first code listing:
mFusedLocationClient = getFusedLocationProviderClient(this);
latitude = myLocation.getLatitude(); //this line throws NullPointerException
longitude = myLocation.getLongitude();
Here, myLocation has not been assigned a value. If you have not assigned a value to myLocation in preceding lines, myLocation will be null, and you will get a NullPointerException.
Now, let's restore some lines to that code snippet:
mFusedLocationClient = getFusedLocationProviderClient(this);
//app already crashes once the line below is executed
mFusedLocationClient.getLastLocation().addOnSuccessListener(this, new OnSuccessListener<Location>() {
#Override
public void onSuccess(Location location) {
}
});
latitude = myLocation.getLatitude(); //this line throws NullPointerException
longitude = myLocation.getLongitude();
The last word in addOnSuccessListener() is "listener". This suggests that you are registering an event listener. Usually — though not always — such a listener is only invoked on future events. It is likely that onSuccess() will not be called until sometime later. However, your program keeps running, and you then try calling getLatitude() on myLocation. Since we still have not done anything to assign a value to myLocation, it will be null, and you will crash with a NullPointerException.
And so while your first code snippet does assign a value to myLocation, you as a programmer have to assume that it will not do so until some time in the future (e.g., when we get a new location fix). Do not attempt to use myLocation until onSuccess() has assigned it a value.
you should not add these lines after addOnSuccessListener:
latitude = myLocation.getLatitude(); //this line throws NullPointerException
longitude = myLocation.getLongitude();
because you have to wait until mFusedLocationClient successfully gets LastLocation
i.e. move these lines into onSuccess method!
As for the reason of the nullPointerException it's because myLocation has not yet been initialized !
You simply need to display the location when you get it, not before. That's said, just put the display code in the listener.
mFusedLocationClient = getFusedLocationProviderClient(this);
// Register a listener, that will be called when the location will be available
mFusedLocationClient.getLastLocation().addOnSuccessListener(this, new OnSuccessListener<Location>() {
#Override
public void onSuccess(Location location) {
if (location != null) {
// We have a location!
myLocation = location;
// So print it now
latitude = myLocation.getLatitude();
longitude = myLocation.getLongitude();
Toast.makeText(PlaceCategoriesActivity.this, "Lat: " + latitude + "Long: + " + longitude, Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(PlaceCategoriesActivity.this, "Location fetch failed!", Toast.LENGTH_SHORT).show();
}
}
});
// Loading, as we wait for listener to be called
Toast.makeText(this, "Loading...", Toast.LENGTH_SHORT).show();
Example:
class LocationApi : Service(), GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener, LocationListener {
private var myGoogleApiClient: GoogleApiClient? = null
private val myLocationRequest = LocationRequest.create()
override fun onBind(intent: Intent?): IBinder? {
return null
}
override fun onCreate() {
super.onCreate()
myGoogleApiClient = GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addOnConnectionFailedListener(this)
.addConnectionCallbacks(this)
.build()
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
myGoogleApiClient?.connect()
return super.onStartCommand(intent, flags, startId)
}
override fun onDestroy() {
myGoogleApiClient?.disconnect()
if (myGoogleApiClient != null && myGoogleApiClient?.isConnected!!) {
LocationServices.getFusedLocationProviderClient(this).removeLocationUpdates(locationCallBack)
}
super.onDestroy()
}
override fun onConnected(bundle: Bundle?) {
//here u can define your interval and priority
// request locations, check permissions ok
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
LocationServices.getFusedLocationProviderClient(this).requestLocationUpdates(myLocationRequest, locationCallBack, Looper.myLooper())
}
}
override fun onConnectionSuspended(p0: Int) {
}
override fun onConnectionFailed(p0: ConnectionResult) {
}
override fun onLocationChanged(location: Location?) {
//saving location on DB
LocationInteractor(location)
}
private val locationCallBack = object : LocationCallback() {
override fun onLocationResult(location: LocationResult) {
super.onLocationResult(location)
onLocationChanged(location.lastLocation)
}
}
}

Location returns NULL

I am writing an Android app that returns longitude and latitude, however location holds a Null value.
Please see if you can see why, Its been bugging me all day. Code below:
public class example extends Activity {
public static double latitude;
public static double longitude;
LocationManager lm;
LocationListener ll;
Location location;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.questions);
lm = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
ll = new MyLocationListener();
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, ll);
//location = lm.getLastKnownLocation(lm.getBestProvider(criteria, true));
Button b = (Button) findViewById(R.id.button2);
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
String provider = Settings.Secure.getString(getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
int index1 = provider.indexOf("gps");
if(index1 < 0)
// gps not enabled, call msgbox
showMsgBox("GPS is off", "GPS is off. Turn it on?", "Turn on");
else
areWeThereYet(); }});
}
private void areWeThereYet()
{
if(weAreThere())
{
toastMsg("in correct place");
}
else if(location!=null)
toastMsg("not there yet");
}
private boolean weAreThere() {
location = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (location!=null)
{
longitude = location.getLongitude();
latitude = location.getLatitude();
toastMsg(latitude + " " + longitude);
return inCorrectPlace(question);
}
else
{
toastMsg("Location not ready yet");
return false;
}
}
private void toastMsg(String msg) {
Toast toast = Toast.makeText(this, msg, 2000);
toast.setGravity(Gravity.BOTTOM, 0, 0);
toast.show();
}
}
If the GPS has not ever gotten a location since the device was booted, the location object will be null. One thing you can do is attempt to get a GPS location and a network location, and check to two to see if either of them are good (or which one is better) and use that location.
If you're using the emulator, then see here for advice on setting up the emulator to provide a location. If you're testing it on your device, it may be because you've never had a gps location on it. Try using the Google maps application before testing your app.

Android requestLocationUpdates without minDistance

I have a need to get the gps location every 20 seconds or so, but ignoring the need to have the user move a certain number of meters, I tried setting the minDistance to zero but still no luck, its only when I manually send the location using the location control from DDMS that this gets activated and the location gets updated.
Note - This is run and tested from the emulator and not a real device, for now at least
private final static Long INTERVAL_TIME = new Long(20);
private final static Float METERS_MOVED_VALUE = 0f;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.journey);
Bundle dataBundle = this.getIntent().getExtras();
try {
driverData = new JSONObject(dataBundle.getString("driverData"));
} catch (JSONException e) {
e.printStackTrace();
}
//Set the UI elements into variables
journeyDescription = (TextView)findViewById(R.id.journeyDescription);
journeyText = (TextView)findViewById(R.id.journeyText);
confirmButton = (Button)findViewById(R.id.btnCheck);
//Acquire a reference to the system Location Manager
locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
LocationListener locationListener = new LocationListener() {
public void onLocationChanged(Location location) {
try{
//Until requests are found keep broadcasting the drivers location and checking for requests
if(!foundRequest){
updateDriverLocationAndCheckForNewDriverRequests(location);
}
//Always keep updating the drivers location
Double latitude = location.getLatitude()*1E6;
Double longitude = location.getLongitude()*1E6;
geoPoint = new GeoPoint(latitude.intValue(), longitude.intValue());
}catch(JSONException e){
Toast.makeText(JourneyActivity.this, "An unexpected error occurred", Toast.LENGTH_LONG).show();
e.printStackTrace();
}
}
public void onStatusChanged(String provider, int status, Bundle extras) {}
public void onProviderEnabled(String provider) {}
public void onProviderDisabled(String provider) {}
};
//Register the listener with the Location Manager to receive location updates can be either gps provider
if (!locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)){
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, INTERVAL_TIME, METERS_MOVED_VALUE, locationListener);
}
else {
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, INTERVAL_TIME, METERS_MOVED_VALUE, locationListener);
}
}
Here is the related code fragment, any ideas on how to trigger the listener without having the user move or me having to send information from the DDMS Location Controls woild be greatly appreciated
Regards,
Milinda
requestLocationUpdates takes milliseconds, not seconds.
You should change:
private final static Long INTERVAL_TIME = new Long(20);
private final static Float METERS_MOVED_VALUE = 0f;
to:
private final static int INTERVAL_TIME_SECONDS = 20 * 1000; // 20 seconds
private final static float INTERVAL_DISTANCE_METERS = 0f; // 0 meters
As far as testing on the emulator goes. I think your limited to manually pushing GPS locations or creating a few automated simulators:
Testing GPS in Android

Categories

Resources