I have a fragment with a listview in it, that retrieves the users location, then updates the list view based on the users location.
The problem with my code, is that it seems to grab the location update the list, then keep updating. And reloading the list, almost to the point of annoyance. Here is my code:
public class FindBrewery extends Fragment implements LocationListener {
private TextView latituteField;
private TextView longitudeField;
LocationManager locationManager;
private String provider;
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
Context c = getActivity().getApplicationContext();
locationManager =(LocationManager)activity.getSystemService(Context.LOCATION_SERVICE);
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
//todo change view
View rootView = inflater.inflate(R.layout.beer_location_list,container, false);
// Get the location manager
// Define the criteria how to select the locatioin provider -> use
// default
Criteria criteria = new Criteria();
provider = locationManager.getBestProvider(criteria, false);
Location location = locationManager.getLastKnownLocation(provider);
// Initialize the location fields
if (location != null) {
System.out.println("Provider " + provider + " has been selected.");
onLocationChanged(location);
} else {
}
return rootView;
}
/* Request updates at startup */
@Override
public void onResume() {
super.onResume();
locationManager.requestLocationUpdates(provider, 400, 1, this);
}
/* Remove the locationlistener updates when Activity is paused */
@Override
public void onPause() {
super.onPause();
locationManager.removeUpdates(this);
}
@Override
public void onLocationChanged(Location location) {
int lat = (int) (location.getLatitude());
int lng = (int) (location.getLongitude());
//latituteField.setText(String.valueOf(lat));
//longitudeField.setText(String.valueOf(lng));
//Toast.makeText(this, "Finding your loaction",Toast.LENGTH_SHORT).show();
//call asycn task for location
String url = "myURL";
Log.d("urlTest", url);
//async task goes here
new GetNearbyBreweries(this.getActivity()).execute(url);
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
// TODO Auto-generated method stub
}
@Override
public void onProviderEnabled(String provider) {
//Toast.makeText(this, "Enabled new provider " + provider,Toast.LENGTH_SHORT).show();
}
@Override
public void onProviderDisabled(String provider) {
//Toast.makeText(this, "Disabled provider " + provider,Toast.LENGTH_SHORT).show();
}
}
Maybe you'd want to try this approach:
LocationClient mLocationClient;
LocationRequest mLocationRequest;
@Override
public void onAttach(Activity activity) {
if (GooglePlayServicesUtil.isGooglePlayServicesAvailable(activity)) {
mLocationClient = new LocationClient(activity, activity, activity);
mLocationRequest = LocationRequest.create();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setInterval(5000);
mLocationRequest.setNumUpdates(1);
mLocationRequest.setFastestInterval(1000);
}
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
if (mLocationClient != null) {
mLocationClient.connect();
}
}
@Override
protected void onStop() {
if (mLocationClient != null) {
if (mLocationClient.isConnected()) {
mLocationClient.removeLocationUpdates(this);
}
mLocationClient.disconnect();
}
super.onStop();
}
@Override
public void onConnected(Bundle dataBundle) {
LocationManager lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
mLocationClient.requestLocationUpdates(mLocationRequest, this);
}
@Override
public void onLocationChanged(Location location) {
int lat = (int) (location.getLatitude());
int lng = (int) (location.getLongitude());
// post to a handler to update the list items
}
The trick is in the following:
- you don't use
getLastKnownLocation
as it uses cache and more often than not returns wrong data,
- you set
setNumUpdates(1)
so you don't need to call removeLocationUpdates()
Don't forget AndroidManifest permissions:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Here is a huge post on GPS location and how to check it every so often.
(30 minutes in that example)
You also may want to have a look at Timer
to set a repeated call to a method that gets the location at the interval you want.
Though it may be a bit robust for your needs, check out Fused Location Provider. It is pretty revolutionary as far as the Location Manager in Android goes. It allows you to do certain things like setting the maximum and minimum interval times as well as a pretty straight forward shut down implementation. I did my first run through from this example and it worked really well (I was trying to do the opposite, I needed updates every 5 seconds where Android was doing updates ever 30-45 seconds):
http://www.kpbird.com/2013/06/fused-location-provider-example.html
You should remove updates from the gps somewhere in your code (suppose that in your case you might do it when you have the current localtion from the user), so call locationManager.removeUpdates(this); inside the onLocationChanged() method once you have a suitable location for your needs.
I've used a separate service for this purpose and implemented GPS relates features inside of it. This service makes location requests and broadcasts them back. So you can just register receiver to obtain received coordinates.
LocationService.java
package com.my.package.services;
import android.app.Service;
import android.content.Intent;
import android.location.Location;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesClient.ConnectionCallbacks;
import com.google.android.gms.common.GooglePlayServicesClient.OnConnectionFailedListener;
import com.google.android.gms.location.LocationClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
public class LocationService extends Service implements LocationListener, ConnectionCallbacks, OnConnectionFailedListener {
private static final String TAG = LocationService.class.getSimpleName();
public static final String BROADCAST_ACTION = "com.my.package.LOCATION_UPDATE";
// Milliseconds per second
private static final int MILLISECONDS_PER_SECOND = 1000;
// Update frequency in seconds
public static final int UPDATE_INTERVAL_IN_SECONDS = 60;
// Update frequency in milliseconds
private static final long UPDATE_INTERVAL = MILLISECONDS_PER_SECOND * UPDATE_INTERVAL_IN_SECONDS;
// The fastest update frequency, in seconds
private static final int FASTEST_INTERVAL_IN_SECONDS = 40;
// A fast frequency ceiling in milliseconds
private static final long FASTEST_INTERVAL = MILLISECONDS_PER_SECOND * FASTEST_INTERVAL_IN_SECONDS;
private LocationClient locationClient;
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "Location service created…");
locationClient = new LocationClient(this, this, this);
locationClient.connect();
}
// Unregister location listeners
private void clearLocationData() {
locationClient.disconnect();
if (locationClient.isConnected()) {
locationClient.removeLocationUpdates(this);
}
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
// When service destroyed we need to unbind location listeners
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "Location service destroyed…");
clearLocationData();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "Calling command…");
return START_STICKY;
}
@Override
public void onConnected(Bundle bundle) {
Log.d(TAG, "Location Callback. onConnected");
Location currentLocation = locationClient.getLastLocation();
// Create the LocationRequest object
LocationRequest locationRequest = LocationRequest.create();
// Use power balanced mode
locationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
// Set the update interval to 5 seconds
locationRequest.setInterval(UPDATE_INTERVAL);
// Set the fastest update interval to 1 second
locationRequest.setFastestInterval(FASTEST_INTERVAL);
locationClient.requestLocationUpdates(locationRequest, this);
onLocationChanged(currentLocation);
}
@Override
public void onLocationChanged(Location location) {
Log.d(TAG, "onLocationChanged");
Log.d(TAG, "LOCATION: " + location.getLatitude() + ":" + location.getLongitude());
// Since location information updated, broadcast it
Intent broadcast = new Intent();
// Set action so other parts of application can distinguish and use this information if needed
broadcast.setAction(BROADCAST_ACTION);
broadcast.putExtra("latitude", location.getLatitude());
broadcast.putExtra("longitude", location.getLongitude());
sendBroadcast(broadcast);
}
@Override
public void onDisconnected() {
Log.d(TAG, "Location Callback. onDisconnected");
}
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Log.d(TAG, "Location Callback. onConnectionFailed");
}
}