Android学习笔记之使用LBS实现定位

PS:最近一直在搞使用LBS实现定位.一般现在涉及到日常生活交易平台的app.貌似都需要使用定位.比如说美团外卖,我请客等app.

 

学习内容:

1.LBS定位的简单介绍.

2.在Map上添加地图覆盖物+地理编码+反地理编码

 

1.LBS定位的简单介绍

 LBS:基站定位.我这里主要还是通过使用百度地图LBS实现定位.使用百度地图LBS实现定位需要做一些相关的准备工作.需要在LBS开放平台上注册自己的AK.有了这个AK.我们的应用才能够去调用百度地图的LBS去实现定位功能.

  百度地图LBS:AK注册地址:http://lbsyun.baidu.com/apiconsole/key.

  我们注册了LBS的账号之后就可以去创建应用的AK了.这里注册需要添加数字签名.数字签名的获取我直接说一种直接了当的方式.就是通过下图去查找.

  黄圈部分就是我们需要添加的数字签名.这是最快也是最直接的方式.还有一种方式是通过cmd的方式进行获取.不过比较麻烦.我一般是使用这种方式去获取的.当输入了数字签名和包名之后.就会出现:

  我们可以看到相关应用对应的AK.有了这个AK之后我们的应用才能够去调用.否则是无法实现定位的.那么这个AK的作用是使用在AndroidManifest文件当中的..

<application
         <!--name 可以自己命名 
               value 就是我们获取的AK-->
         <meta-data
            android:name="com.baidu.lbsapi.API_KEY"
            android:value="0FFf1eth8qPtRnGakNXqAXkN"/>
</application>            

  配置的方式如上.在application标签之间进行添加即可..同时我们还需要添加相关的权限.

<!-- 百度API所需权限 -->
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    <uses-permission android:name="android.permission.USE_CREDENTIALS" />
    <uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
    <uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.BROADCAST_STICKY" />
    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />

  这是一些配置信息.我们还需要使用相关的jar包.导入了相应的jar包和.so文件之后.我们才能够真正的在自己的应用上进行相关的开发.需要使用的相关文件如下:

  这里我们可以看到使用到了(.so)文件,这个文件其实是动态函数库.只不过是属于C语言层次的.jar包是Java层的一些相关接口.而.so文件则是linux c层的函数库.这里已经不仅仅是涉及到软件层次上的东西了.已经涉及到了Android内部组件的使用.内部硬件的使用自然要通过C语言去调用.因此(.so)文件是必须要使用的.相应的jar包和(.so)文件包大家可以去网上下载.

 

 

  那么有了这些基础之后我们就可以真正的去开发我们的定位应用了.

2.在Map上添加地图覆盖物+地理编码+反地理编码

  需要明确一个概念 Poi:

  BaiDuMap API类中提供了多个类用于我们在地图上添加覆盖物: ArcOptions(弧线形覆盖物),PolygonOptions(多边形覆盖物),TextOptions(文字覆盖物),GroundOverlay(地形图图层覆盖物),PolylineOptions(折线形覆盖物),DotOptions(原点覆盖物),CircleOptions(圆形(空心)覆盖物),这些类都继承与OverlayOptions抽象类

  我们在自定义完这些覆盖物之后,通过使用Overlay中的addOverlay()函数,将相应的覆盖物添加到其中就可以完成在地图上添加覆盖物了.

 那么覆盖物有什么用?查了很多的资料都没有给我一个明确的概念.个人认为比如说显示一个区域范围内的一些相关的数据信息.那么这个范围就可以通过添加覆盖物去指定区域.从而去显示一个区域内有多少数据信息(比如:房产,某一区域的车辆数等等).

  说了这么多.我们就看看如何去添加覆盖物.

  i. 多边形覆盖物(PolygonOptions)

  覆盖物的添加需要经过几个过程,首先我们需要定义一个坐标点,不难理解.就拿多边形覆盖物来说.我们需要定义多个坐标点.这些坐标点的连线才能够构成多边形.构成多边形之后进行一些属性配置.然后使用Overlay中的addOverlay()函数.就能够成功的在地图上添加覆盖物了.

  LatLng pt1 = new LatLng(latitude+0.02,longitude); //参数:经度+纬度
  LatLng pt2 = new LatLng(latitude-0.02,longitude); //构造完多个坐标点..
  List<LatLng> points =new ArrayList<LatLng>();     //保存节点信息.
  PolygonOptions polygonoptions = new PolygonOptions(); //实例化多边形覆盖物对象.
  polygonpoints.points(points);   //添加坐标点
  polygonoptions.fillColor(0xAAFFFF00);  //多边形填充颜色
  polygonpoints.stroke(new Stroke(2,0xAAFFFF00)); //设置多边形边框信息
  Overlay polygon = bdMap.addOverlay(polygonoptions);  //添加覆盖物.

  这样就可以完成在地图上添加覆盖物.我们也可以为这些覆盖物设置相关的监听事件.监听事件的设置如下..每一个覆盖物都属于Marker的点击事件.因此通过setOnMarkerClickListener就可以实现点击时的相关操作.

bdMap.setOnMarkerClickListener(new OnMarkerClickListener() {
            
            @Override
            public boolean onMarkerClick(Marker arg0) {
                // TODO Auto-generated method stub
                final LatLng latLng = arg0.getPosition();
                if(arg0 == marker1){
                    Toast.makeText(getApplicationContext(), latLng.toString(), Toast.LENGTH_SHORT).show();
                }
                return false;
            }
        });

  PolygonOptions的其他函数

 polygonoptions.visiable(boolean visiable); //设置可见性 
 polygonoptions.zIndex(int zIndex) //设置多边形 
 polygonoptions.extraInfo(Bundle extraInfo) // 设置多边形额外信息.

   ii.TextOptions(文字覆盖物)  设置文字覆盖物需要注意文字的颜色,大小,位置和属性

LatLng latlng = new LatLng(latitude,longitude); 定义坐标点位置
TextOptions textoptions = new TextOptions(); //实例化对象.
//rotate为旋转角度. positions为显示的位置. 
textoptions.bgColor(0xAAFFFF00).fontSize(28).fontColor(0xAAFFFF00).text("").rotate(-30).position(latlng);
bdMap.addOverlay(textoptions); //在地图中进行添加

//其他函数:
textoptions.align(int ,int ) 设置文字覆盖物对其方式
textoptions.extra(Bundle); 
textoptions.typeface(Typeface); 设置字体
textoptions.zIndex(int zIndex) 
textoptions.visiable(boolean visiable)

  iii.GroundOverlay(地形图图层覆盖物)
  地形图图层可以跟随地图进行平移,深入变换,位于地图和标注图之间,不会遮挡标注图信息.定义这个覆盖物的时候,需要指定宽高.API仅仅提供了两种方法去构建:
  1.指定一个(LatLng),再用dimensions方法去指定宽度和高度.
  2.使用positionFromBounds(LatLngBounds bounds) 表示一个地理范围.指定两个角坐标构造一个矩形范围.

  这里使用到了BitmapDescripter,这个是BaiDuMap中的设置定位图标的方法.这个类主要和Overlay进行打交道,可以为Overlay设置图标信息.

    LatLng southwest = new LatLng(latitude - 0.01, longitude - 0.012);//西南  
    LatLng northeast = new LatLng(latitude + 0.01, longitude + 0.012);//东北  
    LatLngBounds bounds =new LatLngBounds.Builder().include(southwest).include(northwest).build();//构建对象.
    BitmapDescriptor bitmap = BitmapDescriptorFactory.fromResource(R.drawable.icon); //图标添加.
    GroundOverlayOptions options = new GroundOverlayOptions();
    options.image(bitmap);  //显示的图片
    options.positionFromBounds(bounds); //显示位置
    options.transparency(0.7f); //显示的透明度
    bdMap.addOverlay(options); //添加到地图中

   iv.PolylineOptions(折线覆盖物)

  折线覆盖物和多边形覆盖物的添加基本相同.需要添加多个坐标点..然后在点与点之间画线.

   LatLng pt1 = new LatLng(latitude + 0.01, longitude);
   LatLng pt2 = new LatLng(latitude, longitude - 0.01);
   LatLng pt3 = new LatLng(latitude - 0.01, longitude - 0.01);
   LatLng pt5 = new LatLng(latitude, longitude + 0.01);
   List<LatLng> points = new ArrayList<LatLng>();
   points.add(pt1);
   points.add(pt2);
   points.add(pt3);
   points.add(pt5);
   //
   PolylineOptions polylineOptions = new PolylineOptions();
   polylineOptions.points(points);
   polylineOptions.color(0xFF000000);
   polylineOptions.width(4);
   bdMap.addOverlay(polylineOptions);

  v.DotOptions(原点覆盖物)

  原点覆盖物的添加需要定义圆心坐标,以及半径.

private void addDotOptions() {
        bdMap.clear();
        DotOptions dotOptions = new DotOptions();
        dotOptions.center(new LatLng(latitude, longitude));// 设置圆心坐标
        dotOptions.color(0XFFfaa755);// 颜色
        dotOptions.radius(25);// 设置半径
        bdMap.addOverlay(dotOptions);
}

   vi.ArcOptions(弧形覆盖物)

  弧形覆盖物的添加则需要制定弧的起点,中点,终点..制定了这三个点就可以画出相关的弧线.

private void addArcOptions() {
        bdMap.clear();
        LatLng pt1 = new LatLng(latitude, longitude - 0.01);
        LatLng pt2 = new LatLng(latitude - 0.01, longitude - 0.01);
        LatLng pt3 = new LatLng(latitude, longitude + 0.01);
        ArcOptions arcOptions = new ArcOptions();
        arcOptions.points(pt1, pt2, pt3);// 设置弧线的起点、中点、终点坐标
        arcOptions.width(5);// 线宽
        arcOptions.color(0xFF000000);
        bdMap.addOverlay(arcOptions);
}

  vii.CircleOptions(圆形(空心)覆盖物)

  圆形空心覆盖物其实和原点覆盖物差不多.只不过一个是实心圆,一个是空心圆.

private void addCircleOptions() {
        bdMap.clear();
        CircleOptions circleOptions = new CircleOptions();
        circleOptions.center(new LatLng(latitude, longitude));// 设置圆心坐标
        circleOptions.fillColor(0XFFfaa755);// 圆的填充颜色
        circleOptions.radius(150);// 设置半径
        circleOptions.stroke(new Stroke(5, 0xAA00FF00));// 设置边框
        bdMap.addOverlay(circleOptions);

  viii.弹出窗覆盖物.

  弹出窗窗口布局我们可以自己去定义.然后添加到Map当中就可以了.

private void displayInfoWindow(final LatLng latLng){
        
        // 创建infowindow展示的view
        Button btn = new Button(getApplicationContext());
        btn.setBackgroundResource(R.drawable.popup);
        btn.setText("");
        BitmapDescriptor bitmapDescriptor = BitmapDescriptorFactory.fromView(btn);
        // infowindow点击事件
        OnInfoWindowClickListener infoWindowClickListener = new OnInfoWindowClickListener() {
            @Override
            public void onInfoWindowClick() {
                reverseGeoCode(latLng);
                //隐藏InfoWindow
                bdMap.hideInfoWindow();
            }
           };
        // 创建infowindow
        InfoWindow infoWindow = new InfoWindow(bitmapDescriptor, latLng, -47,
                   infoWindowClickListener);

          // 显示InfoWindow
        bdMap.showInfoWindow(infoWindow);
    }

  这些都是API为我们提供的相应接口..我们同样可以去自定义样式然后去适配..比如说一个覆盖物的Marker的样式比较复杂..想要使用这个复杂的布局去替换这个bitmap.那么我们就可以将布局转化成bitmap,然后在添加覆盖物的时候..直接添加我们转化的bitmap就可以了.

  IX.实现自定义覆盖物

  首先我们需要定义一个xml文件布局..这个布局可以非常的复杂.但是这个布局的最外层布局只允许是LinearLayout..

 <?xml version="1.0" encoding="utf-8"?>
 <LinearLayout 
       xmlns:android="http://schemas.android.com/apk/res/android"
       android:orientation="horizontal"
       android:background="@drawable/popup"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content">
       <ImageView 
           android:layout_width="35dp"
           android:layout_height="35dp"
           android:scaleType="centerCrop"
           android:padding="5dip"
           android:src="@drawable/head_1"/>

       <TextView 
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:textColor="@android :color/black"
           android:textSize="20sp"
           android:text="测试"/>
</LinearLayout>
 

  然后我们把当前这个布局转化成Bitmap.然后在直接定义一个Marker对象.在内部添加Bitmap就可以了.转化成Bitmap的函数其实也并不是特别的复杂.之所以布局文件需要使用LinearLayout进行布局,而不能够使用RelativeLayout.是因为使用了makeMeasureSpec函数.这个函数貌似只对Linearayout有效.这样就可以将我们的xml文件布局转化成bitmap.转化完之后就可以进行添加了..

private Bitmap getViewBitmap(View addViewContent) {

        addViewContent.setDrawingCacheEnabled(true);

        addViewContent.measure(
                View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
                View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
        addViewContent.layout(0, 0,
                addViewContent.getMeasuredWidth(),
                addViewContent.getMeasuredHeight());

        addViewContent.buildDrawingCache();
        Bitmap cacheBitmap = addViewContent.getDrawingCache();
        Bitmap bitmap = Bitmap.createBitmap(cacheBitmap);

        return bitmap;
    }

  说了这么多仅仅是完成了覆盖物的添加,那么如何定位还是一回事..如何根据我们的地理坐标实现定位呢?或者是根据我们的位置获取到地理坐标呢?这就需要使用到地理编码和反地理编码..

  地理编码:将我们当前的地理信息转化成相应的位置.

  反地理编码:将我们当前的坐标转化成地理信息.(注:反地理编码需要在网络链接状态的良好的情况下,才能够实现)

  那么如何去实现呢?其实非常的简单..这个函数就实现了地理信息的编码和反编码.

 private void reverseGeoCode(LatLng latLng){
        //创建地理编码检索实例
        GeoCoder geoCoder = GeoCoder.newInstance();
        //设置地理编码的监听.
        OnGetGeoCoderResultListener listener = new OnGetGeoCoderResultListener() {
            //反地理编码函数的返回结果
            @Override
            public void onGetReverseGeoCodeResult(ReverseGeoCodeResult arg0) {
                // TODO Auto-generated method stub
                if(arg0 == null || arg0.error != SearchResult.ERRORNO.NO_ERROR){
                    Toast.makeText(getApplicationContext(), "没有查找到结果", Toast.LENGTH_SHORT).show();
                }
                Toast.makeText(getApplicationContext(), "位置:"+arg0.getAddress(), Toast.LENGTH_SHORT).show();
            }
            //地理编码的返回结果
            @Override
            public void onGetGeoCodeResult(GeoCodeResult arg0) {
                // TODO Auto-generated method stub
                if(arg0 == null || arg0.error != SearchResult.ERRORNO.NO_ERROR){
                    Toast.makeText(getApplicationContext(), "没有查找到结果", Toast.LENGTH_SHORT).show();
                }
            }
        };
        //设置地理编码检索监听
        geoCoder.setOnGetGeoCodeResultListener(listener);
        //反地理编码需要传递坐标点参数.
        geoCoder.reverseGeoCode(new ReverseGeoCodeOption().location(latLng));
    }

   地理编码和反地理编码都算是很好理解..通过使用API提供的接口.我们就可以轻松实现..通过创建地理编码检索对象,然后为对象设置相关的监听就可以了.地理编码和反地理编码仅仅能够确定我们的位置..但是如果想真正完成定位需要使用到定位的核心类.LocationClient.

  X.LocationClient.

  LocationClient是实现定位的核心类.定位服务的客户端.

        locClient = new LocationClient(this);
        locClient.registerLocationListener(locListener);
        //定位模式 对象实例化
        LocationClientOption option = new LocationClientOption();
        option.setOpenGps(true);     // 打开GPS
        option.setCoorType("bd09ll");// 设置坐标类型
        option.setAddrType("all");     // 地理信息设置
        option.setScanSpan(1000);     // 设置扫描间隔
        
        locClient.setLocOption(option); //添加定位模式 
        locClient.start();                //启动定位  

  只有实例化了LocationClient对象.我们才能够真正的实现定位.实例化对象后.我们需要设置定位的监听.

  定位监听的设置:

BDLocationListener locListener = new BDLocationListener() {
        
        @Override
        public void onReceivePoi(BDLocation location) {

        }
        //定位请求回调函数
        @Override
        public void onReceiveLocation(BDLocation location) {
            if (location == null || bdMap == null) {
                return;
            }
            // 构造定位数据
            MyLocationData locData = new MyLocationData.Builder()
                    .accuracy(location.getRadius())//
                    .direction(100)// 方向
                    .latitude(location.getLatitude())//
                    .longitude(location.getLongitude())//
                    .build();
            // 设置定位数据
            bdMap.setMyLocationData(locData);
            latitude = location.getLatitude();
            longitude = location.getLongitude();
            // 第一次定位的时候,那地图中心点显示为定位到的位置
            if (isFirstLoc) {
                isFirstLoc = false;
                LatLng ll = new LatLng(location.getLatitude(),
                        location.getLongitude());
                // MapStatusUpdate描述地图将要发生的变化
                // MapStatusUpdateFactory生成地图将要反生的变化
                MapStatusUpdate msu = MapStatusUpdateFactory.newLatLng(ll);
                bdMap.animateMapStatus(msu);
                // bdMap.setMyLocationEnabled(false);
                Toast.makeText(getApplicationContext(), location.getAddrStr(),
                        Toast.LENGTH_SHORT).show();
            }
        }
    };

 

  添加了定位的监听以及定位时需要的相关配置参数.就可以真正的实现定位了..

  最后附上一个源代码:

  https://files.cnblogs.com/files/RGogoing/Map.rar

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 





 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2015-12-09 20:21  代码丶如风  阅读(7982)  评论(1编辑  收藏  举报