Thursday, May 3, 2012

Updating User Location

Updating User Location




Android supports location-based services, as you'd expect from any modern mobile OS. In Android, LocationManager is responsible for handling this.

To get the location manager, we ask the context to getSystemService() for location services. Next we ask the location manager for list of all available providers.


You may not care about all available location providers but just want to get the best one available. To do this, we specify our criteria for "best". For example, do we require altitude and bearing, allow cost, etc.

We can now ask the location manager for the last known location, for the specific provider. This is helpful to quickly place you close to last location, while waiting for updates to come in.

It is important to register with the location manager to receive the location updates. To do so, we recommend the onResume(). Also, you should unregister from location notifications in your onPause(). Tracking your location can be expensive on the battery and CPU of the device, so this is good practice to stop doing the work while we are paused and normally don't care about the updates. This is important.

The LocationListener which we are implementing will allow us to get certain callbacks. Those callbacks include location, provider and status changes.

LocationDemo.java
Code:
package com.marakana;

import java.util.List;

import android.app.Activity;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.os.Bundle;
import android.widget.TextView;

public class LocationDemo extends Activity implements LocationListener {
 private static final String TAG = "LocationDemo";
 private static final String[] S = { "Out of Service",
   "Temporarily Unavailable", "Available" };

 private TextView output;
 private LocationManager locationManager;
 private String bestProvider;

 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);

  // Get the output UI
  output = (TextView) findViewById(R.id.output);

  // Get the location manager
  locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);

  // List all providers:
  List<String> providers = locationManager.getAllProviders();
  for (String provider : providers) {
   printProvider(provider);
  }

  Criteria criteria = new Criteria();
  bestProvider = locationManager.getBestProvider(criteria, false);
  output.append("\n\nBEST Provider:\n");
  printProvider(bestProvider);

  output.append("\n\nLocations (starting with last known):");
  Location location = locationManager.getLastKnownLocation(bestProvider);
  printLocation(location);
 }

 /** Register for the updates when Activity is in foreground */
 @Override
 protected void onResume() {
  super.onResume();
  locationManager.requestLocationUpdates(bestProvider, 20000, 1, this);
 }

 /** Stop the updates when Activity is paused */
 @Override
 protected void onPause() {
  super.onPause();
  locationManager.removeUpdates(this);
 }

 public void onLocationChanged(Location location) {
  printLocation(location);
 }

 public void onProviderDisabled(String provider) {
  // let okProvider be bestProvider
  // re-register for updates
  output.append("\n\nProvider Disabled: " + provider);
 }

 public void onProviderEnabled(String provider) {
  // is provider better than bestProvider?
  // is yes, bestProvider = provider
  output.append("\n\nProvider Enabled: " + provider);
 }

 public void onStatusChanged(String provider, int status, Bundle extras) {
  output.append("\n\nProvider Status Changed: " + provider + ", Status="
    + S[status] + ", Extras=" + extras);
 }

 private void printProvider(String provider) {
  LocationProvider info = locationManager.getProvider(provider);
  output.append(info.toString() + "\n\n");
 }

 private void printLocation(Location location) {
  if (location == null)
   output.append("\nLocation[unknown]\n\n");
  else
   output.append("\n\n" + location.toString());
 }

}


The layout file for this application is trivial. It uses a single TextView for the output. Yes, we could use maps to show the location, but that's subject of another demo.

/res/layout/main.xml
Code:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical" android:layout_width="fill_parent"
  android:layout_height="fill_parent">

  <ScrollView android:layout_width="wrap_content"
    android:layout_height="wrap_content">
    <TextView android:id="@+id/output" android:layout_width="fill_parent"
      android:layout_height="wrap_content" />
  </ScrollView>
</LinearLayout>



And finally, remember to add the appropriate permissions to your AndroidManifest.xml file

AndroidManifest.xml
Code:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="com.marakana" android:versionCode="1" android:versionName="1.0.0">
  <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  <application android:icon="@drawable/icon" android:label="@string/app_name"
    android:theme="@android:style/Theme.Light">
    <activity android:name=".LocationDemo" android:label="@string/app_name">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity>
  </application>
</manifest> 



The output should look similar to this:

No comments: