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();
            }
        }
    };

 

  添加了定位的監聽以及定位時需要的相關配置參數.就可以真正的實現定位了..

  最后附上一個源代碼:

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

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 





 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM