MobileJava MobileBring Location Services into Your Android App Development

Bring Location Services into Your Android App Development

Developer.com content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

One of the coolest features in Android app development is location services. After all, Android devices are mobile devices and mobile devices are, well, mobile. So knowing where the user is located can be really useful. For example, if you know where the user of your Android application is located, you can show them all of the garage sales in the vicinity, or where to get the cheapest gas price. Obviously, you would need to have access to that type of data, but you get the idea.

This Android development tutorial is a quick getting started guide for building location-aware Android apps. It explains how to enable your Android app to get a user’s location and then do something with it. But before diving into the code, let’s talk about Android location services for a bit.

Choosing Location Services for Your Android App

There are several ways to determine where an Android user is located. The two most prominent methods are to use the global positioning system (GPS) and Android’s Network Location Provider.

GPS is the most accurate way to determine a user’s location, but pinging a global positioning satellite too much will quickly drain a mobile device’s battery and this method doesn’t always work indoors.

Android’s Network Location Provider figures out a user’s location based on cell tower and Wi-Fi signals. It not only uses less battery power than GPS, but it’s also faster and it works whether the user is outside or inside.

So, which one should you use in your Android app? Fortunately, you don’t have to choose; you can use both services in your application. How you leverage these location providers will be dictated by the needs of your application.

Essentially, the choice between GPS and Android’s Network Location Provider is largely weighing accuracy versus battery consumption. The example I present in this tutorial uses both GPS and the network provider.

Using GPS and Network Location Provider in Your Android App

Let’s write some code. The application I present in this tutorial is really basic: It determines the location of the user and maps that location to a nearby street address, if possible.

First, you need to request permission to access the location feature of the Android device. To do that, add the following to your Android manifest file.

<uses-permissionandroid:name="android.permission.ACCESS_FINE_LOCATION"/>

The ACCESS_FINE_LOCATION permission gives you access to both GPS and the Android Location Network Provider. If you need only the network provider, you can request the ACCESS_COARSE_LOCATION permission.

Next, set up your member variables and some constants.

public class MainActivity extends FragmentActivity {

// These are the three UI components we’ll be updating.

private TextView mLatLng;

private TextView mAddress;

private TextView mLastUp;

private LocationManager mLocationMgr;

private Handler mHandler;

private Location mLastLocation;

private boolean mGeocoderAvailable;

private static final int UPDATE_LASTLATLNG = 4;

private static final int LAST_UP = 3;

private static final int UPDATE_LATLNG = 2;

private static final int UPDATE_ADDRESS = 1;

// These static variables control when to the application should check again for location.

private static final int SECONDS_TO_UP = 10000;

private static final int METERS_TO_UP = 10;

private static final int MINUTES_TO_STALE = 1000 * 60 * 2;

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

mLatLng = (TextView) findViewById(R.id.latlng);

mLastUp = (TextView) findViewById(R.id.lastup);

mAddress = (TextView) findViewById(R.id.address);

 

// This handles updating the UI components.

mHandler = new Handler() {

public void handleMessage(Message msg) {

switch (msg.what) {

case UPDATE_ADDRESS:

mAddress.setText((String) msg.obj);

break;

case UPDATE_LATLNG:

mLatLng.setText((String) msg.obj);

break;

case LAST_UP:

mLastUp.setText((String) msg.obj);

break;

}

}

}

;

mGeocoderAvailable = Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD && Geocoder.isPresent();

mLocationMgr = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);

}

Now build out the onStart method. This method checks to see if GPS is enabled on the device, and if not, it prompts the user to enable it.

public void onStart() {

super.onStart();

LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

final boolean gpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);

if (!gpsEnabled) {

new EnableGpsDialogFragment().show(getSupportFragmentManager(),

“enableGpsDialog”);

}

}

The next method is setup. The setup method actually initiates the bulk of the work:

  1. It fetches the user location from GPS.
  2. If Step 1 fails, it attempts to get the location from the network provider.
  3. If a location is determined, it calls the getBestLocation method to see if the new location is better than the old location.

The reason for Step 3 is that the new location might not be better than the old location. For example, if the previous location was pulled from a GPS satellite but the new location is pulled from the network provider, the old location might be more accurate. In that case, the application will stick with the old location for the time being.

private void setup() {

Location newLocation = null;

mLocationMgr.removeUpdates(listener);

mLatLng.setText(R.string.unknown);

newLocation = requestUpdatesFromProvider(LocationManager.GPS_PROVIDER, R.string.no_gps_support);

// If gps location doesn’t work, try network location

if (newLocation == null) {

newLocation = requestUpdatesFromProvider(LocationManager.NETWORK_PROVIDER, R.string.no_network_support);

}

if (newLocation != null) {

updateUILocation(getBestLocation(newLocation, mLastLocation));

}

}

The call to getBestLocation is a critical component to any location application. The version I am using here is derived from an Android API guide.

protected Location getBestLocation(Location newLocation, Location currentBestLocation) {

if (currentBestLocation == null) {

return newLocation;

}

// Check whether the new location fix is newer or older

long timeDelta = newLocation.getTime() – currentBestLocation.getTime();

boolean isNewerThanStale = timeDelta > MINUTES_TO_STALE;

boolean isOlderThanStale = timeDelta < -MINUTES_TO_STALE;

boolean isNewer = timeDelta > 0;

if (isNewerThanStale) {

return newLocation;

}

else if (isOlderThanStale) {

return currentBestLocation;

}

int accuracyDelta = (int) (newLocation.getAccuracy() – currentBestLocation.getAccuracy());

boolean isLessAccurate = accuracyDelta > 0;

boolean isMoreAccurate = accuracyDelta < 0;

boolean isSignificantlyLessAccurate = accuracyDelta > 200;

// Check if the old and new location are from the same provider

boolean isFromSameProvider = isSameProvider(newLocation.getProvider(),

currentBestLocation.getProvider());

// Determine location quality using a combination of timeliness and accuracy

if (isMoreAccurate) {

return newLocation;

}

else if (isNewer && !isLessAccurate) {

return newLocation;

}

else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) {

return newLocation;

}

return currentBestLocation;

}

Depending on the Android app you are building, determining when a new location is appropriate to use is vital to the application’s usefulness.

After the example application has a new location, all it is doing with this data is reverse geocoding it to a physical address. It does this with the following inner class.

private class ReverseGeocode extends AsyncTask<Location, Void, Void> {

Context mContext;

public ReverseGeocode(Context context) {

super();

mContext = context;

}

@Override

protected Void doInBackground(Location… params) {

Geocoder geocoder = new Geocoder(mContext, Locale.getDefault());

Location loc = params[0];

List<Address> addresses = null;

try {

addresses = geocoder.getFromLocation(loc.getLatitude(),

loc.getLongitude(), 1);

}

catch (IOException e) {

e.printStackTrace();

// Update address field with the exception.

Message.obtain(mHandler, UPDATE_ADDRESS, e.toString()).sendToTarget();

}

if (addresses != null && addresses.size() > 0) {

Address address = addresses.get(0);

// Format the first line of address (if available), city, and country name.

String addressText = String.format(“%s, %s, %s”,

address.getMaxAddressLineIndex() > 0 ? address.getAddressLine(0) : “”,

address.getLocality(),

address.getCountryName());

// Update address field on UI.

Message.obtain(mHandler, UPDATE_ADDRESS, addressText).sendToTarget();

}

return null;

}

}

Of course this application is of marginal value, but it does highlight how simple it is to access the location feature on Android devices.

When to Update the User’s Location

Something to think about when building your location-aware Android application is determining when to stop listening for location updates. Listening for long periods of time drains a device’s battery, which can be annoying to users.

However, at certain times, particularly if the user is able to plug the device into a power source, constant updating of the device’s location is necessary. When doing that, I suggest running the real-time updating as a background process and using the system notification bar to make the user aware that it’s happening.

What can make location-aware applications even more useful is tapping into the power of the Google Maps API. While not part of the standard Android development kit, it’s available directly from Google.

Hopefully, this tutorial helps you get started with Android’s location features.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories