首页 » Android程序设计:第2版 » Android程序设计:第2版全文在线阅读

《Android程序设计:第2版》没有地图的地理位置

关灯直达底部

如果你的活动想要访问地理位置信息,但是没有包含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文件的一个片段: