• 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);

  • 相关阅读:
    java rmi 入门实例
    flex“深拷贝”
    Cygwin 下部署Hadoop
    Hadoop学习原地
    Scribe+HDFS日志收集系统安装方法
    使用HDFS来进行线上应用的文件存储
    转:C++初始化成员列表
    转:为什么数据库选B-tree或B+tree而不是二叉树作为索引结构
    B树、B+树、B*树三者的对比详解
    转载:构造函数不能声明为虚函数,而构造函数可以。为什么?
  • 原文地址:https://www.cnblogs.com/inkheart0124/p/3536322.html
Copyright © 2020-2023  润新知