Google Map API v2 步步为营 (二)----- Location

接上篇。

改造一下MapsActivity:

public class MapsActivity extends Activity implements LocationListener, InfoWindowAdapter, OnMarkerClickListener, OnMarkerDragListener{
}

实现4个interface:

android.location.LocationListener

GoogleMap.InfoWindowAdapter

GoogleMap.OnMarkerClickListener

GoogleMap.OnMarkerDragListener

本篇要实现在地图上定位,主要用到LocationListener接口。

另外3个接口关系到 打标记(Marker),移动标记点,以及点击标记弹出info窗口。这些功能将在下一篇文中整理。   

 

地图初始化

首先在onCreate中需要对地图对象做一些设置:

@Override
public void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.map);

    ........
            
    if(servicesConnected()){
        initMapView();
    }
}

 

servicesConnected 检查service是否可用

private boolean servicesConnected() {
    // Check that Google Play services is available
    int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
    // If Google Play services is available
    if(ConnectionResult.SUCCESS == resultCode) {
        log("Google Play services is available.");
        isServiceOk = true;
    } else {
        // Get the error code
        ConnectionResult connectionResult = new ConnectionResult(resultCode, null);
        int errorCode = connectionResult.getErrorCode();
        // Get the error dialog from Google Play services
        Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog(
                    errorCode,
                    this,
                    RESULT_CODE_SERVICE_FAILURE);

        // If Google Play services can provide an error dialog
        if(errorDialog != null) {
            errorDialog.show();
        }
        isServiceOk = false;
    }
    return isServiceOk;
}

上一篇说过,手机调试环境需要安装Google Play服务和play store。如果没有安装,这里就会返回错误码。

 

initMapView 初始化

1 private void initMapView(){
2     mMapView = ((MapFragment)getFragmentManager().findFragmentById(R.id.map_view)).getMap();
3     mMapView.setMapType(GoogleMap.MAP_TYPE_NORMAL);
4 
5     UiSettings setting = mMapView.getUiSettings();
6     setting.setTiltGesturesEnabled(true);
7     //setting.setCompassEnabled(false);
8 }
9     

2行,获得地图对象 GoogleMap mMapView;后面很多操作都要通过它。

3行,设在地图模式为normal

4行,UiSettings 设置人机交互相关的各种按钮手势等待,例如:

void setTiltGesturesEnabled(boolean)  是否允许手势改变视角;

void setCompassEnabled(boolean)  是否显示指南针;

详细的UiSettings用法可参考官文 https://developers.google.com/maps/documentation/android/reference/com/google/android/gms/maps/UiSettings

 

移动到经纬度地点

先阐明一个概念,Goolge Map假定地图本身是固定不动的,移动的是camera(public final class CameraUpdate)。

想象一下,在地球上空漂浮着一只佳能无敌兔,把镜头对准魔都,焦距拉近看到了一号线,再拉远,视角倾斜一下,看到了魔都全貌,还是带广角的。不错吧!

 

回到代码,这里需要用的GPS。通过LocationManager来获得位置服务

mLocManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
mGPSOk = mLocManager.isProviderEnabled(LocationManager.GPS_PROVIDER);

获得LocationManager,并检查GPS是否可用。

在onResume函数中注册监听

 1 @Override
 2 protected void onResume(){
 3     super.onResume();
 4     if(isServiceOk == false)
 5         return;
 6 
 7     String provider = getBestProvider();
 8     if(provider != null){
 9        mLocManager.requestLocationUpdates(provider, 5*1000, 1, this);
10     }
11 
12     updateCurrentLoction();
13     setLatLng();
14 }

7行,获得可用的Location Provider,开启GPS的情况下这里得到的是GPS provider

9行,注册位置变化监听。第二入参5*1000表示每隔5秒更新一次,第三入参表示移动超过1米更新一次。最后一个入参即LocationListener,由于activity implement了LocationListener,所以这里只需要给activity的this指针。

12行和13行的两个函数,用于主动获取最新位置,移动地图到该位置,稍后贴出。

先看一下位置变化的监听函数,activity在implement了LocationListener后 需要实现一下几个函数:

 1 /* LocationListener begin */
 2 @Override
 3 public void onLocationChanged(Location newLoction) {
 4     if(mLocation != null){
 5         mLocation.setLatitude(newLoction.getLatitude());
 6         mLocation.setLongitude(newLoction.getLongitude());
 7         animateLatLng();
 8     }
 9 }
10 
11 @Override
12 public void onProviderDisabled(String arg0) {
13     // TODO Auto-generated method stub    
14 }
15 @Override
16 public void onProviderEnabled(String arg0) {
17     // TODO Auto-generated method stub    
18 }
19 @Override
20 public void onStatusChanged(String arg0, int arg1, Bundle arg2) {
21 }
22 /* LocationListener end */

3~9行,我这里只处理了onLocationChanged,这个函数在location发生变化时会调用到。

我们用了一个私有数据:private Location mLocation = null;

onLocationChanged函数中,把新的location保存到mLocation中,然后调用animateLatLng把地图移动到该位置。

=================================================================

mLocation用于记录每次更新的经纬度,建议在onPause的时候把这个数据保存到本地,我是保存在preference中的。在onResume时读出来。

这样可以避免gps不可用的时候,地图飞回非洲。

当然也可一增加一个对network provider的监听,通过网络获取不太准确的位置,这部份我没做完整。

因为火星坐标系的问题,我最后换了baidu map,google map的这个apk很多后续的优化就没做了,汗吧!

=================================================================

有时我们需要主动查询最新的Location

 1  2 private void updateCurrentLoction(){
 3     String bestProvider = getBestProvider();
 4     Location  newLoction = null;
 5 
 6     if(bestProvider != null)
 7         newLoction = mLocManager.getLastKnownLocation(bestProvider);
 8 
 9     if(mLocation == null){
10         mLocation = new Location("");
11     }
12 
13     if(newLoction != null){
14         mLocation.setLatitude(newLoction.getLatitude());
15         mLocation.setLongitude(newLoction.getLongitude());
16     }
17 }

3行,获取最优的provider

7行,获取最近一次的location

8~16行,同样的,新位置记录到mLocation中。

getBestProvider函数体如下:

private String getBestProvider(){      
    Criteria criteria = new Criteria();
    criteria.setPowerRequirement(Criteria.POWER_LOW);
    criteria.setAccuracy(Criteria.ACCURACY_FINE);
    String bestOne = mLocManager.getBestProvider(criteria, true);
    return bestOne;
}

 

上文用到的两个函数setLatLng()和animateLatLng()

 

 1 private void setLatLng(boolean marked){
 2     if(mLocation == null){
 3         Toast.makeText(this, R.string.gpserr, Toast.LENGTH_LONG).show();
 4         return;
 5     }
 6 
 7     double dLat = mLocation.getLatitude();
 8     double dLong = mLocation.getLongitude();
 9     log("setLatLng: (" + dLat + "," + dLong + ")");
10 
11     //LatLng latlng = new LatLng(31.13893, 121.39668);
12     LatLng latlng = new LatLng(dLat, dLong);
13     if((latlng.latitude == 0) && (latlng.longitude == 0)){
14         //mMapView.moveCamera(CameraUpdateFactory.newLatLng(latlng));
15     }else{
16         mMapView.moveCamera(CameraUpdateFactory.newLatLngZoom(latlng, 15));
17     }
18 }
19 
20 private void animateLatLng(boolean guide){
21     if(mLocation == null){
22         Toast.makeText(this, R.string.gpserr, Toast.LENGTH_LONG).show();
23         return;
24     }
25         
26     double dLat = mLocation.getLatitude();
27     double dLong = mLocation.getLongitude();
28     log("animateLatLng: (" + dLat + "," + dLong + ")");
29     LatLng latlng = new LatLng(dLat, dLong);
30         
31     mMapView.animateCamera(CameraUpdateFactory.newLatLng(latlng));        
32 }

 

先看第一个setLatLng()

7~8行,从mLocation中调用getLatitude()取得维度,getLongitude()取得经度。

12行,构造一个LatLng对象

16行, mMapView.moveCamera(CameraUpdateFactory.newLatLngZoom(latlng, 15));

CameraUpdateFactory.newLatLngZoom(latlng, 15) 返回一个CameraUpdate对象,入参是经纬度和zoom level;

GoogleMap的moveCamera方法把地图移动到该位置。

animateLatLng()函数

31行  基本相同,唯一的区别是最后调用的是animateCamera,我们会看到地图从原location移动到新location的过程。而moveCamera方法是瞬移过去的,不会看到移动过程。

CameraUpdate有很多中构造方法,可以单独或同时指定位置和放大倍数。指定边界等待,详见

https://developers.google.com/maps/documentation/android/reference/com/google/android/gms/maps/CameraUpdateFactory

 

 

最后,要在onPause函数中注销位置服务监听

mLocManager.removeUpdates(this);

 

 

 

posted @ 2014-01-29 20:05  馒头脸  阅读(3058)  评论(0编辑  收藏  举报