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.
Related
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!
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
It is OK when I open the GPS long times, I can get my current location, but when I turn off and then turn on the GPS, it returns null as the current location. I need to refresh or reinstall the app to make the current location work. Is it possible to get the location after a few seconds of turning on the GPS?
Here is my code:
client = LocationServices.getFusedLocationProviderClient(this);
LocationManager locationManager = (LocationManager)getSystemService(LOCATION_SERVICE);
if(!locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)){
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
intent.addCategory(Intent.CATEGORY_DEFAULT);
startActivity(intent);
finish();
} else {
if (ActivityCompat.checkSelfPermission(MapsActivity.this, ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED ) {
return;
}
client.getLastLocation().addOnSuccessListener(MapsActivity.this, new OnSuccessListener<Location>() {
#Override
public void onSuccess(Location location) {
if(location!= null){
latitude = location.getLatitude();
longitude = location.getLongitude();
}
}
});
}
I found out that I need to use requestsLoctionUpdates, but I cannot find any tutorial that explains me how to do it in the new version of android studio (Location : 11.8.0). Can anyone can tell me how to use this code?
I'm using Google API to getting the last location in my android app.
Can you please explain me, why or what can be the reason that my app is reaching addOnFailureListener?
I have my code like this:
mFusedLocationClient.getLastLocation()
.addOnSuccessListener(this, new OnSuccessListener<Location>() {
#Override
public void onSuccess(Location location) {
if (location != null) {
//Sucesso na localização
double altitude = location.getAltitude();
locAtual.setLatitude(location.getLatitude());
locAtual.setLongitude(location.getLongitude());
}
}
})
.addOnFailureListener(this, new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
//Erro
}
});
}
I just want to know what are the reasons, for the fail of listener.
Maybe that device have no LastLocation for your apps. You can use requestLocationUpdates() if getLastLocation() called OnFailureListener() callback. Hopely it can help you
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)
}
}
}