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汗.

posted @ 2012-06-08 16:13  Johnny Yan  阅读(533)  评论(0)    收藏  举报