如果你的活动想要访问地理位置信息,但是没有包含MapView,那会发生什么情况呢?当使用MapView时,在MyLocationOverlay的实现中,一切都很简单,但是如果你不使用地图,获取地理位置信息也不难。本节所提供的代码不是MJAndroid的一部分,但是它说明了如何不通过MapView获取地理位置信息。
我们一起来看一个简单的、单活动应用,它在TextView中显示了当前的地理位置。
Manifest文件和Layout文件
以下是常见的AndroidManifest.xml文件。我们使用Android SDK及Android Manifest Editor创建了这个文件。唯一需要使用编辑器进行修改的是为android.permission.ACCESS_FINE_LOCATION增加uses-permission标签(在文件的倒数第二行)。我们一直需要这个权限,从而能够从GPS地理位置提供者中获取地理位置信息:
<?xml version=/"1.0/" encoding=/"utf-8/"?><manifest xmlns:android=/"http://schemas.android.com/apk/res/android/" package=/"com.microjobsinc.dloc/" android:versionCode=/"1/" android:versionName=/"1.0.0/"><application android:icon=/"@drawable/icon/" android:label=/"@string/app_name/"><activity android:name=/".Main/" 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><uses-permission android:name=/"android.permission.ACCESS_FINE_LOCATION/"></uses-permission></manifest>
这里将使用简单的layout文件,它包含4个TextView:每个维度和经度包含一个标签和一个文本框:
<?xml version=/"1.0/" encoding=/"utf-8/"?> <LinearLayout xmlns:android=/"http://schemas.android.com/apk/res/android/" android:orientation=/"vertical/" android:layout_ android:layout_ > <TextView android:id=/"@+id/lblLatitude/" android:layout_ android:layout_ android:text=/"Latitude:/" /> <TextView android:id=/"@+id/tvLatitude/" android:layout_ android:layout_ /> <TextView android:id=/"@+id/lblLongitude/" android:layout_ android:layout_ android:text=/"Longitude:/" /> <TextView android:id=/"@+id/tvLongitude/" android:layout_ android:layout_ /> </LinearLayout>
连接到LocationProvider,更新地理位置信息
我们一起实现一个活动,它连接到GPS LocationProvider,获取并显示当前地理位置(没有更新):
package com.oreilly.demo.pa.microJobs;import android.app.Activity;import android.content.Context;import android.location.Location;import android.location.LocationManager;import android.os.Bundle;import android.widget.TextView;public class Main extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // find the TextViews TextView tvLatitude = (TextView)findViewById(R.id.tvLatitude); TextView tvLongitude = (TextView)findViewById(R.id.tvLongitude); // get handle for LocationManager LocationManager lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);① // connect to the GPS location service Location loc = lm.getLastKnownLocation(/"gps/");② // fill in the TextViews tvLatitude.setText(Double.toString(loc.getLatitude));③ tvLongitude.setText(Double.toString(loc.getLongitude)); }}
这个过程相当简单。以下是对上述关键代码的分析:
① 通过getSystemService(Context.LOCATION_SERVICE)方法连接到LocationManager。
② 通过getLastKnownLocation(/"provider/")方法,向LocationManager查询当前的地理位置。
③ 从返回的Location中获取维度和经度,并依据需要使用这些信息。
我们还要从LocationManager中周期性地更新位置信息,这样在移动时可以追踪自己的位置。为此,需要增加一个listener,当有更新时,要求LocationManager调用该listener。
应用可以通过DispLocListener类访问LocationManager更新过来的地理位置信息,因此,在主活动中,可以在onCreate方法中创建该类的实例。需要在DispLocListener中重写很多方法来满足LocationListener接口定义,但是在这个应用中不需要实现这些方法,因此保留空定义。完整的实现如下所示:
package com.oreilly.demo.pa.MicroJobs;import android.app.Activity;import android.content.Context;import android.location.Location;import android.location.LocationListener;import android.location.LocationManager;import android.os.Bundle;import android.widget.TextView;public class Main extends Activity { private LocationManager lm; private LocationListener locListenD; public TextView tvLatitude; public TextView tvLongitude; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // find the TextViews tvLatitude = (TextView)findViewById(R.id.tvLatitude); tvLongitude = (TextView)findViewById(R.id.tvLongitude); // get handle for LocationManager LocationManager lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE); // connect to the GPS location service Location loc = lm.getLastKnownLocation(/"gps/"); // fill in the TextViews tvLatitude.setText(Double.toString(loc.getLatitude)); tvLongitude.setText(Double.toString(loc.getLongitude)); // ask the Location Manager to send us location updates locListenD = new DispLocListener; lm.requestLocationUpdates(/"gps/", 30000L, 10.0f, locListenD); } private class DispLocListener implements LocationListener { @Override public void onLocationChanged(Location location) { // update TextViews tvLatitude.setText(Double.toString(location.getLatitude)); tvLongitude.setText(Double.toString(location.getLongitude)); } @Override public void onProviderDisabled(String provider) { } @Override public void onProviderEnabled(String provider) { } @Override public void onStatusChanged(String provider, int status, Bundle extras) { } }}
onCreate方法会创建一个DispLocListener实例,请求LocationManager通过requestLocationUpdates方法更新它。该方法包含4个参数:
String provider
指定要使用的地理位置提供者。在这个例子中,假定是GPS。
long minTime
指定最小更新时间,单位是ms。LocationManager在两次更新之间会至少等待minTime。这是为了省电。更新越频繁,电池消耗越多。
float minDistance
触发更新的最小距离,单位是m。只有当用户至少移动了这么远的距离,LocationManager才会执行更新。
LocationListener listener
当存在更新时会调用的listener名称,在这个例子中,即刚创建的DispLocListener实例。
最后,增加了onPause方法和onResume方法,当启用不在用户屏幕上显示时,可以关闭地理位置更新,并且当再次显示时,重新启用地理位置更新:
/** * Turn off location updates if we/'re paused */@Overridepublic void onPause { super.onPause; lm.removeUpdates(locListenD);}/** * Resume location updates when we/'re resumed */@Overridepublic void onResume { super.onResume; lm.requestLocationUpdates(/"gps/", 30000L, 10.0f, locListenD);}
更新模拟的地理位置
在开发和调试前文所示的应用时,一般都是在模拟器上运行。在模拟器上运行代码时,如果能够更新当前位置将是比较理想的(甚至是比较基础的)。这种模拟地理位置提供者可能功能很完善,但是Android提供了一些内建方式来更新模拟的地理位置:
·Android shell中提供的geo程序
·通过DDMS的一次性更新
·通过DDMS序列化更新的追踪信息
下面将逐个解释这些方式。
使用geo工具更新地理位置信息
geo工具构建在Android图像中,它运行在模拟器上。geo工具包含很多功能,其中有两个功能很有用:
geo fix
可以在模拟的Android的console上执行telnet,使用geo fix命令为Android发送地理位置信息。LocationProvider会使用该信息作为当前的地理位置:
telnet localhost 5554 Android Console: type /'help/' for a list of commands OK geo fix -122.842232 38.411908 0 OK
geo fix接受3个参数:
longitude
以十进制形式表示。
latitude
也是以十进制形式表示。
altitude
单位是米。
通过DDMS更新地理位置
第1章介绍了Dalvik Debug Monitor Server(DDMS)。这里将探讨该工具提供的和地理位置更新相关的两个功能。DDMS屏幕的Emulator Control窗口提供了控制运行的模拟器的一些方式。当切换为DDMS方式时(单击Eclipse窗口右上角的DDMS),在DDMS窗口的左侧中间,可以看到Emulator Control窗口(如图15-1所示)。可能需要在该窗口中使用滚动条往下拉,查看和Location Controls相关的控件。
要给该模拟器发送一次地理位置更新,只需要在相应的窗口中输入经维度,并单击Send按钮。
图15-1:DDMS Emulator Control窗口
如果单击GPX或KML选项卡,还可以加载描述路径的GPX文件或KML文件,如图15-2所示。这里,加载了文件OR.kml,在本书的网站中提供了该文件。它跟踪位于加利福尼亚州塞巴斯玻市的O’Reilly总部附近的一条路径。
图15-2:包含KML地理位置更新的DDMS模拟器
可以使用GPS导航软件工具生成GPX追踪信息,使用Google Earth或其他导航程序生成KML追踪信息。OR.kml文件是使用Google Earth绘制了一系列地标并把它们连接起来后生成的一个文件。以下是OR.kml文件的一个片段: