I have the following code:
public class MyLocationListener implements LocationListener {
#Override
public void onLocationChanged(Location loc) {
// called when the listener is notified with a location update from the GPS
Log.d("Latitude", Double.toString(loc.getLatitude()));
Log.d("Longitude", Double.toString(loc.getLongitude()));
}
#Override
public void onProviderDisabled(String provider) {
// called when the GPS provider is turned off (user turning off the GPS on the phone)
}
#Override
public void onProviderEnabled(String provider) {
// called when the GPS provider is turned on (user turning on the GPS on the phone)
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
and in my MainActivity
LocationListener locationListener = new MyLocationListener();
LocationManager lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
Now, all I want is to receive the current position of the device ONCE to the MainActivity class (get altitude and longitude variables to use later in the application).
A. how do I stop receiving the location after a single time? The function lm.removeUpdates(listener) can only be called in the MainActivity class.
B. basically the same. How do I connect between the MyLocationListener class and the MainActivity one?
Sorry, I'm a newbie to Android and Java development.
And thanks!
You may use the following sample code:
public class LocationGetter {
private final Context context;
private Location location = null;
private final Cordinate gotLocationLock = new Cordinate();
private final LocationResult locationResult = new LocationResult() {
#Override
public void gotLocation(Location location) {
synchronized (gotLocationLock) {
LocationGetter.this.location = location;
gotLocationLock.notifyAll();
Looper.myLooper().quit();
}
}
};
public LocationGetter(Context context) {
if (context == null)
throw new IllegalArgumentException("context == null");
this.context = context;
}
public void getLocation(int maxWaitingTime, int updateTimeout) {
try {
final int updateTimeoutPar = updateTimeout;
synchronized (gotLocationLock) {
new Thread() {
public void run() {
Looper.prepare();
LocationResolver locationResolver = new LocationResolver();
locationResolver.prepare();
locationResolver.getLocation(context, locationResult, updateTimeoutPar);
Looper.loop();
}
}.start();
gotLocationLock.wait(maxWaitingTime);
}
} catch (InterruptedException e1) {
e1.printStackTrace();
}
gteAddress ();
}
public double getLatitude() {
return location.getLatitude();
}
public double getLongitude() {
return location.getLongitude();
}
In your activity use:
_locationGetter=new LocationGetter(context);
_locationGetter.getLocation(200000000, 10000000);
_locationGetter.getLongitude();
_locationGetter.getLatitude();
You can also use LocationManager.removeUpdates after obtining the coordinates (and possibly checking if the coordinates are sufficient for your needs):
#Override
public void onLocationChanged(Location loc) {
// called when the listener is notified with a location update from the GPS
Log.d("Latitude", Double.toString(loc.getLatitude()));
Log.d("Longitude", Double.toString(loc.getLongitude()));
lm.removeUpdates(this);
}
Related
I think I know the issue for why when running my code the gps tracking only works on emulated devices. It has something to do with the location listener being inside the onCreate() function. I just don't know how I would be able to edit my existing code so Locationlistener still works when placed outside of the onCreate() function.
I want to test the code on a mobile device because the getSpeed() function does not work when emulating.
Here is the code that fetches the location:
private LocationListener listener;
private LocationManager location;
private Float speedStr;
private Boolean boolSpeed;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#SuppressLint("MissingPermission")
#Override
public void onCreate() { //Get coords and send to main activity. Also get speed.
listener = new LocationListener() {
#Override
public void onLocationChanged(Location location) {
Intent i = new Intent("location update");
i.putExtra("coords",location.getLatitude());
i.putExtra("coords2",location.getLongitude());
sendBroadcast(i);
Toast.makeText(GPS_Service.this,"reading",Toast.LENGTH_SHORT).show();
speedStr = location.getSpeed();
boolSpeed = location.hasSpeed();
Log.i("speed",speedStr.toString());
Log.i("speed",boolSpeed.toString());
}
#Override
public void onProviderDisabled(String s) {
Intent i = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
}
};
location = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
location.requestLocationUpdates(LocationManager.GPS_PROVIDER,3000,200,listener); //set min distance proper units
}
#SuppressLint("MissingPermission")
#Override
public void onDestroy() {
super.onDestroy();
if(location != null) {
location.removeUpdates(listener);
}
}
}
I'm trying to get the user's current location for my weather application but i get the location of some "US" area. I've tried multiples tutorials but failed to get the correct current location.
It returns me:
latitude: 37.421998333333335
longitude: -122.08400000000002
The location is "Mountain View,CA,US"
The code I've used is below:
GpsTracker.java
public class GpsTracker implements LocationListener {
Context context;
public GpsTracker(Context c)
{
context = c;
}
public Location getLocation()
{
if(ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED){
Toast.makeText(context,"Permission not granted",Toast.LENGTH_SHORT).show();
return null;
}
LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
boolean isGpsEnabled = lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
if(isGpsEnabled)
{
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER,0,0,this);
Location l = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);
return l;
}
else{
Toast.makeText(context,"Enable GPS",Toast.LENGTH_SHORT).show();
}
return null;
}
#Override
public void onLocationChanged(Location location) {
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onProviderDisabled(String provider) {
}
}
In my main class I'm getting the location like this:
public void getLocation()
{
gpsTracker = new GpsTracker(getApplicationContext());
Location l = gpsTracker.getLocation();
if(l != null)
{
lat = l.getLatitude();
lon = l.getLongitude();
}
Log.d("User's location","Latitude"+lat);
Log.d("User's location","Longitude"+lon);
}
The Location that you need is returned in the method onLocationChanged.
So you could assign it to a variable and then return it:
private Location lastLocation;
#Override
public void onLocationChanged(Location location) {
lastLocation = location;
}
public Location getLastLocation() {
return lastLocation;
}
Call requestLocationUpdates in the onCreate of your activity and then call getLastLocation when you need to show it.
Or you can implement a callback to notify the activity when the location changes.
You are probably getting the last known location and using that tool is probably handing back this address. Consider using a better tool or just FusedLocationProviderClient. However, I like SmartLocation library personally.
https://github.com/mrmans0n/smart-location-lib
It gives fallback providers in the event of one unavailable. There is a little learning curve to use the library, but once you implement it, it works nicely.
I'm having an issue stopping a service that I have started.
The service is called when the user logs in, and starts to track the user's location. This is working fine. The service is meant to stop when the user presses the logout button and is successfully logged out.
It's an android service that is being called through a JavaScript interface by a HTML button.
Here is my Main Class which contains the methods for starting and stopping the service:
public class CasesMain extends DroidGap {
Intent gpsTracking;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.init();
appView.addJavascriptInterface(this, "StartGPS");
super.loadUrl(Config.getStartUrl());
}
public void startGPS(){
gpsTracking = new Intent(this, MyService.class);
startService(gpsTracking);
}
public void stopGPS(){
stopService( gpsTracking );
}
}
Here is the MyService class:
public class MyService extends Service {
private LocationManager locManager;
private LocationListener locListener = new myLocationListener();
private boolean gps_enabled = false;
private boolean network_enabled = false;
private Handler handler = new Handler();
Thread t;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
}
#Override
public void onDestroy() {
}
#Override
public void onStart(Intent intent, int startid) {
}
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(getBaseContext(), "Service Started", Toast.LENGTH_SHORT)
.show();
final Runnable r = new Runnable() {
public void run() {
location();
handler.postDelayed(this, 10000);
}
};
handler.postDelayed(r, 10000);
return START_STICKY;
}
public void location() {
locManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
try {
gps_enabled = locManager
.isProviderEnabled(LocationManager.GPS_PROVIDER);
} catch (Exception ex) {
}
try {
network_enabled = locManager
.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
} catch (Exception ex) {
}
if (gps_enabled) {
locManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0,
0, locListener);
}
if (network_enabled) {
locManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
0, 0, locListener);
}
}
private class myLocationListener implements LocationListener {
double lat_old = 0.0;
double lon_old = 0.0;
double lat_new;
double lon_new;
#Override
public void onLocationChanged(Location location) {
if (location != null) {
locManager.removeUpdates(locListener);
lon_new = location.getLongitude();
lat_new = location.getLatitude();
String longitude = "Longitude: " + location.getLongitude();
String latitude = "Latitude: " + location.getLatitude();
Log.v("Debug", "Latt: " + latitude + " Long: " + longitude);
Toast.makeText(getApplicationContext(),
longitude + "\n" + latitude, Toast.LENGTH_SHORT).show();
lat_old = lat_new;
lon_old = lon_new;
}
}
#Override
public void onProviderDisabled(String provider) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
}
}
And here is my call to stop the service: window.StartGPS.stopGPS();
The start works perfectly, but when I log out, the app continues to show messages of the latt and long meaning the call to stopService() either didn't work or is not called.
Can anyone see where my mistake is or what is going wrong?
Any help would be greatly appreciated!
FIXED
Adding handler.removeCallbacksAndMessages(null); in the onDestroy() method of MyService fixed it for me.
Can anyone see where my mistake is or what is going wrong?
You have an empty onDestroy() method. You need to call removeCallbacks() on your Handler there.
If you are using any android.os.Handler in the service remember to call removeCallbacksAndMessages like this:
#Override
public void onDestroy() {
Toast.makeText(this, "service onDestroy", Toast.LENGTH_LONG).show();
Utils.cancelNotification(this);
customHandler.removeCallbacksAndMessages(null);
}
And the service will destroy successfully. It worked for me.
Here's what I would suggest
1) Put more log statements in calls leading to stopService.
2) Implement On ServiceConnection interface and see what's happening in OServiceConnected and onServiceDisconnected.
I have an application written in HTML5 and wrapped in PhoneGap.
I have a map on an application and I want to find a user's location by GPS.
I tried it the following way:
In JS I have a function that changes the position of the marker:
function GPS(lat, lon) {
alert('Now U move');
var CurrentPosition = new google.maps.LatLng(lat, lon);
markerMyLoc.setPosition(CurrentPosition);
}
In Java, I have functions that care on location and send the JS function:
public class MainActivity extends DroidGap {
private LocationManager locationManager;
private LocationListener locationListener;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.setIntegerProperty("splashscreen", R.drawable.splash);
super.loadUrl("file:///android_asset/www/XXX.html", 10000);
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
locationListener = new GPSLocationListener();
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER,
0,
0,
locationListener);
}
}
GPSLocationListener class:
public class GPSLocationListener implements LocationListener
{
#Override
public void onLocationChanged(Location location) {
if (location != null) {
GPScls MyGPS= new GPScls();
MyGPS.GPS(location.getLatitude(),location.getLongitude());
}
}
#Override
public void onProviderDisabled(String provider) {
// TODO Auto-generated method stub
}
#Override
public void onProviderEnabled(String provider) {
// TODO Auto-generated method stub
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
// TODO Auto-generated method stub
}
}
GPScls class:
public class GPScls extends DroidGap {
public void GPS(double latitude,double longitude) {
super.loadUrl("javascript:GPS("+latitude+","+longitude+")");
}
}
the alert: alert('Now U move'); Not shown, can anyone help me solve this?
I realized that, I did not go enough to return an answer from GPS
Look at the following question:
Is the function onLocationChanged called every movement of Android device?
I am trying to build an application that needs to use the GPS API's on android. I have two activities that need to use the gps.
The first one is just an activity that has a LocationListener and when it gets the location it gets weather for that location from a web API and saves it somewhere.
After doing that, it starts an intent that starts another activity. The other activity on other hand, needs to get speed from gps and update in realtime.
Now my question is, is it possible to use the same LocationListener from another activity on the second activity without having to reconnect to gps and do all that stuff again? Or is there any other alternatives than reconnecting again on the second activity as well?
Any help is appreciated. Thanks.
#KSubedi -- create a class for location listener & use objects of class in both your activity.
You can create class like below or you can edit below as per you requirement or create new one.
import java.util.Timer;
import java.util.TimerTask;
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
public abstract class MyLocation {
Timer timer1;
static LocationManager lm;
LocationResult locationResult;
boolean gps_enabled = false;
boolean network_enabled = false;
public boolean getLocation(Context context, LocationResult result)
{
//I use LocationResult callback class to pass location value from MyLocation to user code.
locationResult=result;
if(MyLocation.lm == null)
MyLocation.lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
//exceptions will be thrown if provider is not permitted.
try
{
gps_enabled = MyLocation.lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
}
catch(Exception ex)
{}
try
{
network_enabled = MyLocation.lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
}
catch(Exception ex)
{}
//don't start listeners if no provider is enabled
if(!gps_enabled && !network_enabled)
return false;
if(gps_enabled)
MyLocation.lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListenerGps);
if(network_enabled)
MyLocation.lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListenerNetwork);
timer1=new Timer();
// timer1.schedule(new GetLastLocation(), 20000);
timer1.scheduleAtFixedRate(new GetLastLocation(), 0,50000);
return true;
}
LocationListener locationListenerGps = new LocationListener() {
public void onLocationChanged(Location location) {
timer1.cancel();
locationResult.gotLocation(location);
MyLocation.lm.removeUpdates(this);
MyLocation.lm.removeUpdates(locationListenerNetwork);
}
public void onProviderDisabled(String provider) {}
public void onProviderEnabled(String provider) {}
public void onStatusChanged(String provider, int status, Bundle extras) {}
};
LocationListener locationListenerNetwork = new LocationListener() {
public void onLocationChanged(Location location) {
timer1.cancel();
locationResult.gotLocation(location);
MyLocation.lm.removeUpdates(this);
MyLocation.lm.removeUpdates(locationListenerGps);
}
public void onProviderDisabled(String provider) {}
public void onProviderEnabled(String provider) {}
public void onStatusChanged(String provider, int status, Bundle extras) {}
};
class GetLastLocation extends TimerTask {
#Override
public void run() {
// lm.removeUpdates(locationListenerGps);
// lm.removeUpdates(locationListenerNetwork);
Location net_loc=null, gps_loc=null;
if(gps_enabled)
gps_loc = MyLocation.lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if(network_enabled)
net_loc = MyLocation.lm.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
//if there are both values use the latest one
if(gps_loc!=null && net_loc!=null){
if(gps_loc.getTime()>net_loc.getTime())
locationResult.gotLocation(gps_loc);
else
locationResult.gotLocation(net_loc);
return;
}
if(gps_loc!=null){
locationResult.gotLocation(gps_loc);
return;
}
if(net_loc!=null){
locationResult.gotLocation(net_loc);
return;
}
locationResult.gotLocation(null);
}
}
public void closeListeners(){
timer1.cancel();
lm.removeUpdates(locationListenerGps);
lm.removeUpdates(locationListenerNetwork);
}
public static abstract class LocationResult{
public abstract void gotLocation(Location location);
}
public abstract void locationClick() ;
}
For this purpose use Services to get locations instead of using two activites.