关于本文档

基于位置的应用程序是移动通讯中的一种重要要素,这构成了手机应用程序收入的重要部分。此类基于位置的应用程序可使用GPS定位或Google地图外部库来加以开发。本文阐述了如何使用您手机中已激活的GPS来查找位置。

范围

本文旨在为希望简单了解Android编程的初学者而设计。本文逐步指导了初学者来开发基于GPS的应用程序。假定您已经安装了可开发应用程序的Android和必要的工具。同样假定您熟悉Java或熟悉基于对象的编程概念。

什么是GPS

全球定位系统(GPS)是一种基于空间的全球导航卫星系统(GNSS),其可在朝向四颗或更多的GPS卫星上视线未受阻碍时,在任何天气情况下随时随地均能提供可靠的位置和时间信息。

通过从三颗或更多的卫星上捕捉信号,GPS接收器能够对数据进行三角定位,并准确地找出您的位置。

由于增加了计算能力,并且在内存中存储了数据(如道路地图、影像和目标点、地形资料以及更多信息),GPS接收器可将位置、速度以及时间信息转变为有用的显示格式。

成本增加

GPS无线电和处理器非常便宜,但手机材料清单成本中增加的10美元仍相当多。

电池寿命降低

尽管在降低GPS无线电和处理器功耗方面已取得了巨大的进展,但它们仍旧消耗了较高的电池电量。大多数内置GPS的手机都具有一种可使用户进行开启和关闭的功能。如果应用程序取决于GPS准确度,则要牢记必须检查应用程序以查看是否已开启GPS设备,并且如果未开启,则通知用户。

不稳定的可用性

没有任何部件可“长期工作”,尤其是依赖于您的手机设备可看到当前位于头顶上卫星的GPS。如果身处高层建筑的地下室,并且周围均为钢筋混凝土,则您将可能无法使用GPS。

基于位置的服务概述

android.location是一种包,其包含了与Android平台中位置服务相关的若干个类。它介绍了LocationManager系统服务,并在基础设备支持下可提供一种确定位置和方位的API。

LocationManager不应直接予以实例化,而应通过调用Context.getSystemService(Context.LOCATION_SERVICE)来检索其操作。该方法可将操作返回至LocationManager实例。

LocationManager实例,则应用程序即可执行如下操作:

  • LocationProvider列表,以获取最近已知的用户位置。
  • 注册/注销以从位置提供商定期更新用户的当前位置(通过标准或名称来确定)。
  • 如果该设备位于给定纬度/经度的区域(通过半径确定,单位:米)范围内,注册/注销以获取一个给定的待触发的Intent。

获得位置更新

如欲获取android中的位置,则通过使用getSystemService()方法来获得LocationManager类的参考。

如欲在位置变更时获得随时告知,则您需要注册以请求获取位置的变化,从而定期通知手机程序。可通过requestLocationUpdates()方法来完成。此方法包括四个参数:

  • 提供商:您用以注册的提供商的名称
  • MinTime:通知的最小时间间隔,单位:毫秒。
  • MinDistance: 通知的最小距离间隔,单位:米。
  • 监听器:针对每次位置更新将调用其onLocationChanged()方法的对象。

    在执行LocationListener抽象类的类中,您需在此执行过程中重载四种方法:
  • onLocationChanged(Location location):位置已变更时可调用此方法。
  • onProviderDisabled(String provider):用户禁用提供商可调用此方法。
  • onProviderEnabled(String provider): 用户启用提供商可调用此方法。
  • onStatusChanged(String provider、int status、Bundle extras):提供商状态变化时可调用此方法。

以下给定内容为位置变更的相关样例

Class: GPSLocations.java 
package com.gps;

 import android.app.Activity;
 import android.content.Context;
 import android.content.Intent;
 import android.location.Location;
 import android.location.LocationListener;
 import android.location.LocationManager;
 import android.location.LocationProvider;
 import android.os.Bundle;
 import android.widget.TextView;
 import android.widget.Toast;
public class GPSLocations extends Activity {

 private LocationManager locationManger;
 private TextView tv;
 private int fixesCount;
/** Called when the activity is first created. */
 @Override
 public void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.main);

   /*get the textview*/
   tv = (TextView) findViewById(R.id.textView);
  /* Use the LocationManager class to obtain user Locations*/
   locationManger = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

    /*listen for the location updates*/
    LocationListener locListener = new GPSLocationListener();
    /* add location listener and updates each time*/
     locationManger.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0,
                    0, locListener);
}

 /*class with location update event listener*/
 public class GPSLocationListener implements LocationListener {
/*callback for listening location changes*/ @Override public void onLocationChanged(Location location) { /* TODO Auto-generated method stub*/ fixesCount++; tv.setText("No of Fixes: " + fixesCount + "\nlongitude: " + location.getLongitude() + "\nlatitude: " + location.getLatitude()); } /*location service status disabled*/ @Override public void onProviderDisabled(String provider) { /* bring up the GPS settings */ Intent intent = new Intent( android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS); startActivity(intent); } /*location service status enabled*/ @Override public void onProviderEnabled(String provider) { Toast.makeText(getApplicationContext(), "Gps Enabled", Toast.LENGTH_SHORT).show(); } /*Location status detection*/ @Override public void onStatusChanged(String provider, int status, Bundle extras) { /* This is called when the GPS status alters */ switch (status) { case LocationProvider.OUT_OF_SERVICE: Toast.makeText(getApplicationContext(), "Status Changed: Out of Service", Toast.LENGTH_SHORT) .show(); break; case LocationProvider.TEMPORARILY_UNAVAILABLE: Toast.makeText(getApplicationContext(), "Status Changed: Temporarily Unavailable", Toast.LENGTH_SHORT).show(); break; case LocationProvider.AVAILABLE: Toast.makeText(getApplicationContext(), "Status Changed: Available", Toast.LENGTH_SHORT).show(); break; }         }
   }
 }
 添加代码中指定的id用于Main.xml布局中的文本显示
   <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
       android:orientation="vertical"
       android:layout_width="fill_parent"
       android:layout_height="fill_parent"
     >
    <TextView
       android:id="@+id/textView"
       android:layout_width="fill_parent"
       android:layout_height="wrap_content"
       android:text="@string/hello"
     />
 </LinearLayout>
 添加许可
GPS_PROVIDER获取位置更新,您须通过分别在Android描述文件中声明ACCESS_FINE_LOCATION许可来请求用户许可。例如:
<manifest ... >
     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
     ...
 </manifest>

测试模拟器

如欲开发并调试模拟器上基于GPS的应用程序,则需在运行您的代码时更新模拟器使用的当前位置。此Mock位置提供商的成本可能非常高昂,但Android仍提供了更新模拟位置的一些内置方法。

  • 使用DDMS更新位置
  • 使用Geo更新位置 

使用DDMS更新位置

Android插件中用于Eclipse的此DDMS(Dalvik调试监控服务)工具可使您非常轻松地测试GPS功能。在Eclipse中,切换至DDMS以查看并查找如图1中所示的模拟器控制标签卡中的位置控制部分。


在此位置控制部分中,有三个单独的选项卡。在首个手动选项卡中,经纬度坐标均可手动发送。当在Android模拟器上接收GPS数据时,应用程序将获得的经纬度,如图2所示。



第二个选项卡为地理位置中的另外一种发送方式,其可使用一种具有轻便XML数据格式的.GPX file.GPX(GPS交换格式)来交换GPS数据。只需点击图3所示的Load GPX(加载GPX)按钮,即可加载.GPX文件,同时点击播放按钮,可定期将坐标系列发送至Android模拟器。



在第三个选项卡中,您可使用图x中所示的加载KML按钮来加载KML(Keyhole Markup Language)文件,然后点击播放按钮,从而定期向Android模拟器发送坐标系列。


 

使用Geo更新位置

如欲从命令行发送mock位置数据: 

  • 开启Android模拟器中的应用程序,并打开SDK/工具目录中的终端/控制台。
  • 连接至模拟器控制它:

telnet localhost <console-port>


  • 发送位置数据:
  • Geo fix可发送一个固定的geo位置。此命令可接受十进制的经纬度,并可接受以米为单位的可选高度。例如:

geo fix -121.45356 46.51119 4392

geo nmea可发送NMEA 0183语句。此命令可接受‘$GPGGA'(固定数据)或‘$GPRMC'(传送数据)类型的单个NMEA语句。例如:

geo nmea $GPRMC,081836,A,3751.65,S,14507.36,E,000.0,360.0,130998,011.3,E*62