Android位置和地图使用
上一节中介绍了在Android中使用Google Map的方法,这一节继续介绍如何显示地理位置。Android位置服务需要用到android.Location包。
LocationManager Service
位置服务的核心组件是LocationManager系统服务,在创建LocationManager实例时,只需要调用getSystemService(Context.LOCATION_SERVICE)来创建
LocationProviders
Android设备获取位置的方法有两种:GPS 和 Network.
GPS:
- 精度高(5-10m)
- 速度比Network慢
- 耗电严重
Network
- 精度较差(200-1000m)
- 可以通过基站或者WiFi获取信息
为了获取信息,你可以同时使用或者两者取其一。
新建Android项目ShowLocation,Build Target选择Google APIs。
在layout下的main.xml中放置一个TextView和一个Button. TextView用来显示获取的地理信息,Button用来打开Google Map。android:onClick="openMapView"制定了Button的点击事件,后文将用到。
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:id="@+id/locationTextView" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Waiting for location ...." /> <Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Open Map" android:onClick="openMapView" /> </LinearLayout>
打开ShowLocationActivity.java
在onCreate(Bundle savedInstanceState)中创建Location Service
/** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mLocationTextView = (TextView) findViewById(R.id.locationTextView); mGeocoder = new Geocoder(this,Locale.getDefault()); //创建LocationManager实例 LocationManager locationManager = (LocationManager) this .getSystemService(Context.LOCATION_SERVICE); //监听位置变化 locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener); }
当用户的位置改变时,要获取最新的位置,就需要用到LocationListener来监听用户位置
// Define a listener that responds to location updates LocationListener locationListener = new LocationListener() { //用户位置改变 public void onLocationChanged(Location location) { mLocation = location; //获取当前位置的经纬度 StringBuffer sb = new StringBuffer(); sb.append("latitude = " + location.getLatitude() + "\n"); sb.append("longitude = " + location.getLongitude() + "\n"); List<Address> addresses = null; try { //根据经纬度获取位置信息 addresses = mGeocoder.getFromLocation(location.getLatitude(), location.getLongitude(), 10); } catch (IOException e) { e.printStackTrace(); } if(null!= addresses){ for (Address address : addresses) { sb.append(address.getAddressLine(0)); sb.append("\n"); } } mLocationTextView.setText(sb.toString()); } public void onStatusChanged(String provider, int status, Bundle extras) { } public void onProviderEnabled(String provider) { } public void onProviderDisabled(String provider) { } };
在本例中,我们选用的GPS来获取位置。模拟器本身不支持GPS位置数据,我们需要手动的向模拟器发送经纬度信息。
首先开启Android的虚拟GPS功能
运行模拟器(AVD),Build Target仍然选择Google APIs,
然后打开CMD,使用telnet localhost 5554进行登录
Microsoft Windows [Version 6.1.7600] Copyright (c) 2009 Microsoft Corporation. All rights reserved. C:\Users\jyan>telnet localhost 5554
登陆后,输入help,我们可以查看各命令的作用
Android Console: type 'help' for a list of commands OK help Android console command help: help|h|? print a list of commands event simulate hardware events geo Geo-location commands gsm GSM related commands cdma CDMA related commands kill kill the emulator instance network manage network settings power power related commands quit|exit quit control session redir manage port redirections sms SMS related commands avd control virtual device execution window manage emulator window qemu QEMU-specific commands sensor manage emulator sensors try 'help <command>' for command-specific help OK
help geo fix 'geo fix <longitude> <latitude> [<altitude> [<satellites>]]' allows you to send a simple GPS fix to the emulated system. The parameters are: <longitude> longitude, in decimal degrees <latitude> latitude, in decimal degrees <altitude> optional altitude in meters <satellites> number of satellites being tracked (1-12) OK
geo fix 接收经度,纬度信息,高度信息为可选参数
这里我们使用青岛软件园的经纬度 120.413824 36.075402
Android Console: type 'help' for a list of commands OK geo fix 120.413824 36.075402 OK
OK表示设置成功。至此我们已经开启了Android的虚拟GPS功能,并设置了经纬度信息。为了能够手动将经纬度信息发送到AVD模拟器,我们还需要打开Emulator Control。在Eclipse中Window->Show VIew->Other在Android下选择Emulator Control

在启动项目之前,我们需要在AndroidManifest.xml设置ACCESS_COARSE_LOCATION,ACCESS_FINE_LOCATION权限以及INTERNET
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.training.location" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="7" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" > <uses-library android:name="com.google.android.maps" /> <activity android:name=".ShowLocationActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".LocationOnMapActivity" android:label="@string/app_name" > </activity> </application> </manifest>
启动项目:
启动后如下左图,在Emulator Control中,点击Send将经纬度发送到模拟器,可以看到该位置的详细信息。
|
|
|
点击Open Map,将该位置在Google Map上了显示,需要新建一个Activity: LocationOnMapActivity用来显示Google Map,并使用Intent将经纬度传入该Activity。
在ShowLocationActivity中为
public void openMapView(View view) { Intent openMapActivityIntent = new Intent(this, LocationOnMapActivity.class); openMapActivityIntent.putExtra(getString(R.string.intentFieldLatitude), mLocation.getLatitude()); openMapActivityIntent.putExtra( getString(R.string.intentFieldLongitude), mLocation.getLongitude()); startActivity(openMapActivityIntent); }
LocationOnMapActivity的内容和上一节Android 中使用Google Map中介绍的内容基本一致,唯一的不同就是要获取Intent信息中的经纬度参数,然后根据经纬度声明一个OverlayItem,然后在Map上显示。
public class LocationOnMapActivity extends MapActivity { private MapView mMapView; @Override protected void onCreate(Bundle bundle) { super.onCreate(bundle); setContentView(R.layout.mapview); mMapView = (MapView) findViewById(R.id.mapview); mMapView.setBuiltInZoomControls(true); mMapView.getController().setZoom(17); List<Overlay> mapOverlays = mMapView.getOverlays(); Drawable drawable = this.getResources().getDrawable( R.drawable.ic_launcher); BasicItemizedOverlay itemizedOverlay = new BasicItemizedOverlay( drawable); double doubleLatitude = getIntent().getDoubleExtra( getString(R.string.intentFieldLatitude), -1); double doubleLongitude = getIntent().getDoubleExtra( getString(R.string.intentFieldLongitude), -1); final int e6 = 1000000; int intLatitude = (int)(doubleLatitude * e6); int intLongitude = (int)(doubleLongitude * e6); GeoPoint geo = new GeoPoint(intLatitude, intLongitude); OverlayItem overlayitem = new OverlayItem(geo, "", ""); itemizedOverlay.addOverlay(overlayitem); mapOverlays.add(itemizedOverlay); mMapView.getController().animateTo(geo); } @Override protected boolean isRouteDisplayed() { return false; } }
BasicItemizedOverlay 和Android 中使用Google Map中介绍的HelloItemizedOVerlay 代码完全一致,点击Open Map结果如下:

在该工程中,笔者创建了两个AVD,分别为2.2版本和4.0版本。在使用2.2版本时, mGeocoder.getFromLocation(location.getLatitude(),location.getLongitude(), 10)总是返回null,为此焦头烂额了一阵子,后查找了一些资料,居然是2.2版本的一个Bug,
具体可见http://code.google.com/p/android/issues/detail?id=8816 。该问题直至API14中才得到解决。14之前的版本问题仍然存在,⊙﹏⊙b汗.




浙公网安备 33010602011771号