用百度 API 高仿微信定位 demo

2,251 阅读3分钟
原文链接: www.jianshu.com

前言

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上:BaiduWeChatPosition