1. 程式人生 > >用百度API高仿微信定位demo

用百度API高仿微信定位demo

前言

demo使用Android 地圖 SDK v4.1.1。
解決android6.0以上定位失敗的問題(定位到非洲或者大海的問題)。

先放個效果:
定位頁面.png

搜尋頁面.png

配置

  • 首先要在百度地圖,先下載需要的包:基礎定位、基礎地圖和檢索功能。下載
  • 然後按照官方介紹如何使用百度地圖API。
    android地圖SDK
    android定位SDK
    裡面介紹的很詳細,需要仔細觀看每一行介紹。
    申請金鑰,配置環境和釋出後,就可以使用百度地圖的定位、地圖和檢索功能了。
    需要注意的是,由於android6.0以上新增了執行時許可權動態檢測。下面這三個許可權需要特殊處理。
ACCESS_COARSE_LOCATION
ACCESS_FINE_LOCATION
READ_PHONE_STATE

我將許可權的判斷和使用放在歡迎頁面。

    /**
     * 仿微信歡迎頁面,在此處處理 android6.0 許可權
     *
     * @author chenjunxu
     * @date 16/12/26
     */
    public class WelcomeActivity extends Activity {
        /**
         * 需要 android6.0 以上處理的許可權
          */
        private String[] PERMISSIONS = {
                Manifest.permission.ACCESS_COARSE_LOCATION,
                Manifest.permission.ACCESS_FINE_LOCATION,
                Manifest.permission.READ_PHONE_STATE};

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_welcome);
            // android 系統大於等於 6.0 時需要處理時許可權
             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                requestNeedPermission();
            } else {
                goToMain();
            }
        }

        /**
         * 進入首頁面
          */
        private void goToMain() {
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    Intent intent = new Intent(WelcomeActivity.this, MainActivity.class);
                    startActivity(intent);
                    WelcomeActivity.this.finish();
                }
            }, 1200);
        }

        /**
         * 判斷是否需要進行許可權的請求
          */
        private void requestNeedPermission() {
            boolean temp = false;
            for (String permission : PERMISSIONS) {
                if (!hasPermissionGranted(permission)) {
                    temp = true;
                    break;
                }
            }
            // 需要許可權則請求許可權
            if (temp) {
                ActivityCompat.requestPermissions(this, PERMISSIONS, 0);
            } else {
                goToMain();
            }
        }

        /**
         * 判斷該許可權是否已經授權
         *
         * @param permission
         * @return
         */
        private boolean hasPermissionGranted(String permission) {
            return ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED;
        }

        @Override
        public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
            if (requestCode == 0) {
                boolean temp = false;
                for (int i = 0; i < grantResults.length; i++) {
                    if (grantResults[i] == PackageManager.PERMISSION_DENIED) {
                        Toast.makeText(WelcomeActivity.this, " 拒絕 " + grantResults[i] + " 許可權會導致定位失敗!", Toast.LENGTH_LONG).show();
                        temp = true;
                        break;
                    }
                }

                // 再次請求許可權
                if (temp) {
                    requestNeedPermission();
                } else {
                    goToMain();
                }
            }
        }
    }

基礎地圖和定位功能

  1. 設定百度地圖的縮放比例 (500 米)

    MapStatusUpdate msu = MapStatusUpdateFactory.zoomTo(15.0f);
    mBaiduMap.setMapStatus(msu);
    
  2. 地圖動畫效果

    //引數latLng是指百度的經緯度類
    MapStatusUpdate u = MapStatusUpdateFactory.newLatLng(latLng);
    mBaiduMap.animateMapStatus(u);
    
  3. 百度地圖有兩個編碼方式:正向編碼和反向編碼。程式碼中,我們使用反向編碼。
    正向地理編碼:指的是由地址資訊轉換為座標點的過程;
    反向地理編碼:指的是由座標點轉換成地址資訊的過程;

    呼叫反向地理編碼

    mSearch.reverseGeoCode((new ReverseGeoCodeOption()).location(latLng));
    

    處理反向地理編碼後的結果

    @Override
    public void onGetReverseGeoCodeResult(ReverseGeoCodeResult result) {
        if (result == null || result.error != SearchResult.ERRORNO.NO_ERROR) {
            return;
        }
        // 獲取反向地理編碼結果
        PoiInfo mCurrentInfo = new PoiInfo();
        mCurrentInfo.address = result.getAddress();
        mCurrentInfo.location = result.getLocation();
        mCurrentInfo.name = result.getAddress();
        // result是定位到當前位置的資訊
        if (!TextUtils.isEmpty(mCurrentInfo)) {
            datas.add(mCurrentInfo);
        }
        // result.getPoiList()是當前位置附近的資訊
        if (result.getPoiList() != null && result.getPoiList().size() > 0) {
            datas.addAll(result.getPoiList());
        }
    }
    
  4. 百度定位

    /**
     * 定位 SDK 監聽函式
     */
    public class MyLocationListener implements BDLocationListener {
    
        @Override
        public void onReceiveLocation(BDLocation location) {
            // map view 銷燬後不在處理新接收的位置
             if (location == null || bmapView == null) {
                return;
            }
            MyLocationData locData = new MyLocationData.Builder()
                    .accuracy(location.getRadius())
                    .latitude(location.getLatitude())
                    .longitude(location.getLongitude()).build();
            mBaiduMap.setMyLocationData(locData);
    
            Double mLatitude = location.getLatitude();
            Double mLongitude = location.getLongitude();
    
            // 是否第一次定位。第一次定位需要移動地圖
             if (isFirstLoc) {
                isFirstLoc = false;
                LatLng currentLatLng = new LatLng(mLatitude, mLongitude);
                // 實現動畫跳轉
                 MapStatusUpdate u = MapStatusUpdateFactory
                        .newLatLng(currentLatLng);
                mBaiduMap.animateMapStatus(u);
                // 反向地理編碼
                mSearch.reverseGeoCode((new ReverseGeoCodeOption())
                        .location(currentLatLng));
                return;
            }
        }
    
        public void onReceivePoi(BDLocation poiLocation) {
        }
    }
    

搜尋

  1. 微信定位的搜尋部分,我用了百度地圖的建議查詢。百度API用OnGetSuggestionResultListener監聽獲取的查詢結果。

    OnGetSuggestionResultListener mSuggestionResultListener = new OnGetSuggestionResultListener() {
    
        // 獲得結果
        public void onGetSuggestionResult(SuggestionResult res) {
            if (res == null || res.getAllSuggestions() == null) {
                Toast.makeText(mContext, " 沒找到結果 ", Toast.LENGTH_LONG).show();
                return;
            }
            // 獲取線上建議檢索結果
            if (datas != null) {
                datas.clear();
                for (SuggestionResult.SuggestionInfo suggestionInfos : res.getAllSuggestions()) {
                    datas.add(suggestionInfos);
                }
                locatorAdapter.notifyDataSetChanged();
            }
        }
    };
    
  2. listview的item點選時,需要將LatLng返回到微信定位頁面,再通過反向編碼獲取位置資訊。

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position,
                            long id) {
        Intent intent = new Intent();
        // 設定座標
        intent.putExtra("LatLng", datas.get(position).pt);
        setResult(RESULT_OK, intent);
        SearchPositionActivity.this.finish();
    }
    

結尾

還有很多細節問題沒有在此處介紹,需要的朋友請在git上拉下來檢視。
程式碼已經上傳到git上: