开发者在面对配送行业场景,诸如外卖,B2C零售,商超等需要路线规划的功能,尤其网约车行业,还需要用到计算路费、动画模拟小车在路线上行驶等功能,这个腾讯位置服务产品的小demo就可以实现定位、规划路线、计算距离和路费,以及模拟小车平滑移动等基础功能。

先看下实现效果:

新建个Android项目并新建个Activity,命名为DrivingRouteActivity,先来画一下UI布局,布局比较简单,由一个腾讯SDK包下的地图组件MapView,以及两个用于输入起始位置的输入框,两个确认路线规划的Button,一个定位当前位置的ImageView,一个用于显示行程信息的TextView组成,布局代码只是为了方便展示实现功能,所以下面直接贴出布局代码:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:app="http://schemas.android.com/apk/res-auto"
  4. xmlns:tools="http://schemas.android.com/tools"
  5. android:layout_width="match_parent"
  6. android:layout_height="match_parent"
  7. android:orientation="vertical"
  8. tools:context=".activity.DrivingRouteActivity">
  9. <com.tencent.tencentmap.mapsdk.maps.MapView
  10. android:id="@+id/mapview"
  11. android:layout_width="match_parent"
  12. android:layout_height="wrap_content"
  13. android:layout_weight="1"/>
  14. <LinearLayout
  15. android:layout_width="match_parent"
  16. android:layout_height="wrap_content"
  17. android:orientation="vertical"
  18. android:gravity="bottom"
  19. android:paddingTop="10dp">
  20. <LinearLayout
  21. android:layout_width="match_parent"
  22. android:layout_height="wrap_content"
  23. android:orientation="horizontal">
  24. <EditText
  25. android:id="@+id/from_et"
  26. android:hint="您在哪儿上车"
  27. android:layout_weight="1"
  28. android:layout_marginTop="10dp"
  29. android:layout_marginBottom="10dp"
  30. android:layout_marginLeft="10dp"
  31. android:layout_width="match_parent"
  32. android:layout_height="50dp"></EditText>
  33. <ImageButton
  34. android:id="@+id/location_ib"
  35. android:background="@drawable/sendtocar_balloon"
  36. android:layout_marginTop="10dp"
  37. android:layout_marginBottom="10dp"
  38. android:layout_marginRight="10dp"
  39. android:layout_width="50dp"
  40. android:layout_height="50dp"></ImageButton>
  41. </LinearLayout>
  42. <EditText
  43. android:id="@+id/to_et"
  44. android:hint="您要去哪儿"
  45. android:layout_width="match_parent"
  46. android:layout_height="50dp"
  47. android:layout_marginBottom="5dp"
  48. android:layout_marginLeft="10dp"
  49. android:layout_marginRight="10dp"></EditText>
  50. <TextView
  51. android:id="@+id/orderdesc_tv"
  52. android:layout_width="match_parent"
  53. android:layout_height="wrap_content"
  54. android:gravity="center"
  55. android:textSize="20sp"></TextView>
  56. <Button
  57. android:id="@+id/confirm_btn"
  58. android:text="确定"
  59. android:layout_width="match_parent"
  60. android:layout_height="50dp"
  61. android:layout_marginBottom="10dp"
  62. android:layout_marginLeft="10dp"
  63. android:layout_marginRight="10dp"
  64. android:visibility="gone"></Button>
  65. <Button
  66. android:id="@+id/order_btn"
  67. android:text="预约快车"
  68. android:layout_width="match_parent"
  69. android:layout_height="50dp"
  70. android:layout_marginBottom="10dp"
  71. android:layout_marginLeft="10dp"
  72. android:layout_marginRight="10dp"></Button>
  73. </LinearLayout>
  74. </LinearLayout>

在开发之前,我们需要到腾讯位置服务官网注册一个账号
注册后进入控制台
选择key管理,点击创建新秘钥,按照申请信息提交申请

将上面申请的key在application标签下进行如下配置(value替换成自己的key)

  1. <meta-data
  2. android:name="TencentMapSDK"
  3. android:value="XXXXX-XXXXX-XXXXX-XXXXX-XXXXX-XXXXX" />

进入Android地图SDK,下载3D版地图SDK压缩包
下载完成后打开压缩包,将libs文件夹下的jar包拷贝到app的libs目录下,右键该jar包选择add as library添加为依赖,并且在项目app\src\main路径下建立名为jniLibs的目录,把压缩包libs/jniLibs/strip文件夹下的所有包放到jniLibs目录下
引入后在AndroidManifest.xml文件下配置相关权限

  1. <!-- 访问网络获取地图服务 -->
  2. <uses-permission android:name="android.permission.INTERNET" />
  3. <!-- 检查网络可用性 -->
  4. <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
  5. <!-- 访问WiFi状态 -->
  6. <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
  7. <!-- 需要外部存储写权限用于保存地图缓存 -->
  8. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  9. <!-- 获取 device id 辨别设备 -->
  10. <uses-permission android:name="android.permission.READ_PHONE_STATE" />

配置完成,现在开始实现我们的逻辑交互,为了让实现逻辑更加清晰,我将业务逻辑代码与视图渲染代码分到了两个包中,除了activity包中的DrivingRouteActivity之外,新建了一个present包,并在包下建立一个DrivingRoutePresent类,分别由DrivingRouteActivity负责对UI组件进行视图渲染,由DrivingRoutePresent类负责业务逻辑。这里我还新建了一个contract包,并创建一个DrivingRouteContract接口,通过这个接口定义的方法,实现DrivingRoutePresent与DrivingRouteActivity之间的交互。我们在DrivingRouteContract接口中定义两个接口,一个View接口供DrivingRouteActivity实现,一个Presenter接口供DrivingRoutePresent实现,并定义一些初始化的方法

  1. public interface DrivingRouteContract {
  2. interface View{
  3. void initView();//初始化View
  4. void initOnClick();//初始化OnClickListener
  5. void setOrderDescTV(String content);//渲染订单行程信息
  6. EditText getFromET();
  7. }
  8. interface Presenter{
  9. void attachView(DrivingRouteContract.View view);//绑定View
  10. }
  11. }

接着再让DrivingRouteActivity实现DrivingRouteContract.View接口并声明UI中的组件进行初始化

  1. public class DrivingRouteActivity extends Activity implements DrivingRouteContract.View, View.OnClickListener {
  2. private MapView mapView;
  3. private TencentMap mMap;
  4. private Button confirmBtn;
  5. private Button orderBtn;
  6. private ImageButton locationIB;
  7. private EditText fromET;
  8. private EditText toET;
  9. private TextView orderDescTV;
  10. private DrivingRoutePresent drivingRoutePresent;
  11. @Override
  12. protected void onCreate(Bundle savedInstanceState) {
  13. super.onCreate(savedInstanceState);
  14. setContentView(R.layout.activity_driving_route);
  15. initView();
  16. initOnClick();
  17. }
  18. @Override
  19. public void onClick(View view) {
  20. switch (view.getId()){
  21. case R.id.order_btn:
  22. //实现行程路线规划
  23. break;
  24. case R.id.confirm_btn:
  25. //开启动画移动
  26. break;
  27. case R.id.location_ib:
  28. //定位当前位置
  29. break;
  30. }
  31. }
  32. /**
  33. * mapview的生命周期管理
  34. */
  35. @Override
  36. protected void onStart() {
  37. super.onStart();
  38. mapView.onStart();
  39. }
  40. @Override
  41. protected void onResume() {
  42. super.onResume();
  43. mapView.onResume();
  44. }
  45. @Override
  46. protected void onPause() {
  47. super.onPause();
  48. mapView.onPause();
  49. }
  50. @Override
  51. protected void onStop() {
  52. super.onStop();
  53. mapView.onStop();
  54. }
  55. @Override
  56. protected void onDestroy() {
  57. super.onDestroy();
  58. mapView.onDestroy();
  59. }
  60. @Override
  61. protected void onRestart() {
  62. super.onRestart();
  63. mapView.onRestart();
  64. }
  65. @Override
  66. public void initView() {
  67. mapView = findViewById(R.id.mapview);
  68. confirmBtn = findViewById(R.id.confirm_btn);
  69. orderBtn = findViewById(R.id.order_btn);
  70. locationIB = findViewById(R.id.location_ib);
  71. fromET = findViewById(R.id.from_et);
  72. toET = findViewById(R.id.to_et);
  73. orderDescTV = findViewById(R.id.orderdesc_tv);
  74. mMap = mapView.getMap();
  75. drivingRoutePresent = new DrivingRoutePresent();
  76. drivingRoutePresent.attachView(this);
  77. }
  78. @Override
  79. public void initOnClick() {
  80. orderBtn.setOnClickListener(this);
  81. confirmBtn.setOnClickListener(this);
  82. locationIB.setOnClickListener(this);
  83. }
  84. @Override
  85. public void setOrderDescTV(String content) {
  86. orderDescTV.setText(content);
  87. }
  88. @Override
  89. public EditText getFromET() {
  90. return fromET;
  91. }
  92. }

DrivingRoutePresent实现DrivingRouteContract.Presenter接口

  1. public class DrivingRoutePresent implements DrivingRouteContract.Presenter {
  2. private DrivingRouteContract.View drinvingRouteView;
  3. @Override
  4. public void attachView(DrivingRouteContract.View view) {
  5. drinvingRouteView = view;
  6. }
  7. }

因为我们后面在多个地方都需要用到当前应用的上下文,为了方便,需要再编写一个全局的应用上下文工具类来帮助我们获取上下文,建立一个util包并创建一个GlobalApplication类

  1. public class GlobalApplication extends Application {
  2. private static Context context;
  3. @Override
  4. public void onCreate() {
  5. super.onCreate();
  6. context = getApplicationContext();
  7. }
  8. public static Context getContext(){
  9. return context;
  10. }
  11. }

同时,在Android类文件的application标签中加入下面属性,让应用启动时加载上面的GlobalApplication

  1. android:name=".util.GlobalApplication"

到这里,我们就完成了界面与业务代码的基本设计,运行app,可以看到显示的基本地图信息。接下来我们来实现一下路线规划的功能。腾讯官方Android地图SDK开发文档对路线规划服务和地址解析都有较详细的说明。
另外还提供了调用示例Demo。如果不清楚如何调用的话可以参考官方Demo或参考下面代码。

首先我们在DrivingRouteContract.Presenter接口申明一个用于通过地址查找经纬度的geocoder方法和一个用于路线规划的routePlan方法

  1. public interface DrivingRouteContract {
  2. interface View{
  3. void initView();//初始化View
  4. void initOnClick();//初始化OnClickListener
  5. void setOrderDescTV(String content);//渲染订单行程信息
  6. EditText getFromET();
  7. }
  8. interface Presenter{
  9. void attachView(DrivingRouteContract.View view);//绑定View
  10. void geocoder(String address, Integer type);//地址解码,转经纬度
  11. void routePlan();//实现路线规划
  12. }
  13. }

通过腾讯Android地图SDK路线规划服务的开发文档,我们了解到要获得规划路线需要先获取起点和终点的经纬度,而在一般业务场景中,我们几乎不会让用户手动输入经纬度,所以我这里还需要用到地址解析服务,通过输入中文地址来获取经纬度,再通过经纬度规划路线(不过在实际业务中最好是加上关键词输入提示这个服务,方便用户找到输入的位置)。

在DrivingRoutePresent类中实现这两个方法

  1. public static final Integer FROM_TYPE = 0x100; //获取起始位置坐标
  2. public static final Integer TO_TYPE = 0x101; //获取目的位置坐标
  3. private LatLng fromLatLng;
  4. private LatLng toLatLng;
  5. /**
  6. * 地址解码
  7. * @param address 传入需要解码的地址
  8. * @param type 地址类型,起始位置、目的位置
  9. */
  10. @Override
  11. public void geocoder(String address, final Integer type) {
  12. TencentSearch tencentSearch = new TencentSearch(GlobalApplication.getContext());
  13. Address2GeoParam address2GeoParam =
  14. new Address2GeoParam(address);
  15. tencentSearch.address2geo(address2GeoParam, new HttpResponseListener<BaseObject>() {
  16. @Override
  17. public void onSuccess(int arg0, BaseObject arg1) {
  18. if (arg1 == null) {
  19. return;
  20. }
  21. Address2GeoResultObject obj = (Address2GeoResultObject)arg1;
  22. if (obj.result.latLng != null) {
  23. if (type==FROM_TYPE)
  24. fromLatLng = obj.result.latLng;
  25. else if (type==TO_TYPE)
  26. toLatLng = obj.result.latLng;
  27. routePlan();
  28. }
  29. }
  30. @Override
  31. public void onFailure(int arg0, String arg1, Throwable arg2) {
  32. Log.e("test", "error code:" + arg0 + ", msg:" + arg1);
  33. }
  34. });
  35. }
  36. private TencentSearch tencentSearch = new TencentSearch(GlobalApplication.getContext());
  37. private StringBuffer lineStringBuilder = new StringBuffer();//路线坐标
  38. private Double taxiFare = 0d;//预估打车费用
  39. private Float distance = 0f;//预计全程里程
  40. /**
  41. * 路线规划
  42. */
  43. @Override
  44. public void routePlan() {
  45. if (fromLatLng!=null&&toLatLng!=null){
  46. Toast.makeText(GlobalApplication.getContext(), "正在为您规划路线", Toast.LENGTH_SHORT).show();
  47. DrivingParam drivingParam = new DrivingParam(fromLatLng, toLatLng);
  48. drivingParam.policy(DrivingParam.Policy.TRIP);//驾车路线规划策略,网约车场景,送乘客
  49. drivingParam.setCarNumber("粤A00001");//填入车牌号,在路线规划时会避让车牌限行区域
  50. tencentSearch.getRoutePlan(drivingParam, new HttpResponseListener<DrivingResultObject>() {
  51. @Override
  52. public void onSuccess(int i, DrivingResultObject drivingResultObject) {
  53. for (DrivingResultObject.Route route : drivingResultObject.result.routes){
  54. for (LatLng latLng : route.polyline){
  55. lineStringBuilder.append(latLng.latitude + "," + latLng.longitude);
  56. lineStringBuilder.append(",");
  57. }
  58. distance += route.distance;
  59. taxiFare += route.taxi_fare.fare;
  60. }
  61. drinvingRouteView.setOrderDescTV("行程大约" + distance + "m,预计¥" + taxiFare + "元");
  62. //清空行程路线,里程,费用信息
  63. lineStringBuilder = new StringBuffer();
  64. distance = 0f;
  65. taxiFare = 0d;
  66. }
  67. @Override
  68. public void onFailure(int i, String s, Throwable throwable) {
  69. Log.d("DrivingRouteActivity", "onSuccess: " + s + i);
  70. }
  71. });
  72. fromLatLng=null;
  73. toLatLng=null;
  74. }
  75. }

其中geocoder方法用于获得我们输入的起始位置(从哪儿上车),以及输入的目的位置(到哪儿下车)的坐标经纬度,记录位置的经纬度后调用routePlan方法请求路线规划接口,并记录下里程,费用信息,路线行驶过程中经过的点的经纬度(用于后面实现小车移动)。

路线规划接口除了上面使用的几个常用参数外,还有很多接口参数,具体可以查看官方接口文档按需要加入

参考官方接口文档:https://lbs.qq.com/AndroidDocs/doc_3d/index.html

有了路线规划方法后,给”预约快车”按钮添加实现

  1. @Override
  2. public void onClick(View view) {
  3. switch (view.getId()){
  4. case R.id.order_btn:
  5. drivingRoutePresent.geocoder(fromET.getText().toString(), DrivingRoutePresent.FROM_TYPE);
  6. drivingRoutePresent.geocoder(toET.getText().toString(), DrivingRoutePresent.TO_TYPE);
  7. confirmBtn.setVisibility(View.VISIBLE);
  8. orderBtn.setVisibility(View.GONE);
  9. break;
  10. case R.id.confirm_btn:
  11. //开启动画移动
  12. break;
  13. case R.id.location_ib:
  14. //定位当前位置
  15. break;
  16. }
  17. }

此时,运行APP,输入起点和终点就可以获得驾车的规划路线了

接下来,我们再实现一下效果图上小车根据规划路线行驶的功能

在DrivingRouteContract.View接口中加入小车动画初始化方法initAnimation

  1. public interface DrivingRouteContract {
  2. interface Model{
  3. }
  4. interface View{
  5. void initView();//初始化View
  6. void initOnClick();//初始化OnClickListener
  7. void setOrderDescTV(String content);//渲染订单行程信息
  8. EditText getFromET();
  9. void initAnimation(String line);//初始化小车移动动画
  10. }
  11. interface Presenter{
  12. void attachView(DrivingRouteContract.View view);//绑定View
  13. void startLocation(boolean single);
  14. void stopLocation();
  15. void geocoder(String address, Integer type);//地址解码,转经纬度
  16. void routePlan();//实现路线规划
  17. }
  18. }

实现initAnimation方法,关于Marker其他参数同样参考上面的接口文档

  1. private Marker mCarMarker;
  2. private LatLng[] mCarLatLngArray;
  3. private MarkerTranslateAnimator mAnimator;
  4. @Override
  5. public void initAnimation(String line) {
  6. //拆分获得经纬度数组
  7. String[] linePointsStr = line.split(",");
  8. mCarLatLngArray = new LatLng[linePointsStr.length / 2];
  9. for (int i = 0; i < mCarLatLngArray.length; i++) {
  10. double latitude = Double.parseDouble(linePointsStr[i * 2]);
  11. double longitude = Double.parseDouble(linePointsStr[i * 2 + 1]);
  12. mCarLatLngArray[i] = new LatLng(latitude, longitude);
  13. }
  14. //添加小车路线
  15. mMap.addPolyline(new PolylineOptions().add(mCarLatLngArray)
  16. .color(R.color.colorLine));//这个颜色是colors.xml中自定义的颜色
  17. //添加小车
  18. LatLng carLatLng = mCarLatLngArray[0];
  19. mCarMarker = mMap.addMarker(
  20. new MarkerOptions(carLatLng)
  21. .anchor(0.5f, 0.5f)
  22. .icon(BitmapDescriptorFactory.fromResource(R.mipmap.taxi_t))//小车图标
  23. .flat(true)
  24. .clockwise(false));
  25. //创建移动动画
  26. mAnimator = new MarkerTranslateAnimator(mCarMarker, 50 * 1000, mCarLatLngArray, true);
  27. //调整最佳视野
  28. mMap.animateCamera(CameraUpdateFactory.newLatLngBounds(
  29. LatLngBounds.builder().include(Arrays.asList(mCarLatLngArray)).build(), 50));
  30. }

并在routePlan方法中调用这个方法,传入行驶路线字符串

  1. //初始化小车动画
  2. drinvingRouteView.initAnimation(lineStringBuilder.substring(0, lineStringBuilder.length()-1));

完整代码参考

  1. /**
  2. * 路线规划
  3. */
  4. @Override
  5. public void routePlan() {
  6. if (fromLatLng!=null&&toLatLng!=null){
  7. Toast.makeText(GlobalApplication.getContext(), "正在为您规划路线", Toast.LENGTH_SHORT).show();
  8. DrivingParam drivingParam = new DrivingParam(fromLatLng, toLatLng);
  9. drivingParam.policy(DrivingParam.Policy.TRIP);//驾车路线规划策略,网约车场景,送乘客
  10. drivingParam.setCarNumber("粤A00001");//填入车牌号,在路线规划时会避让车牌限行区域
  11. tencentSearch.getRoutePlan(drivingParam, new HttpResponseListener<DrivingResultObject>() {
  12. @Override
  13. public void onSuccess(int i, DrivingResultObject drivingResultObject) {
  14. for (DrivingResultObject.Route route : drivingResultObject.result.routes){
  15. for (LatLng latLng : route.polyline){
  16. lineStringBuilder.append(latLng.latitude + "," + latLng.longitude);
  17. lineStringBuilder.append(",");
  18. }
  19. distance += route.distance;
  20. taxiFare += route.taxi_fare.fare;
  21. }
  22. //初始化小车动画
  23. drinvingRouteView.initAnimation(lineStringBuilder.substring(0, lineStringBuilder.length()-1));
  24. drinvingRouteView.setOrderDescTV("行程大约" + distance + "m,预计¥" + taxiFare + "元");
  25. //清空行程路线,里程,费用信息
  26. lineStringBuilder = new StringBuffer();
  27. distance = 0f;
  28. taxiFare = 0d;
  29. }
  30. @Override
  31. public void onFailure(int i, String s, Throwable throwable) {
  32. Log.d("DrivingRouteActivity", "onSuccess: " + s + i);
  33. }
  34. });
  35. fromLatLng=null;
  36. toLatLng=null;
  37. }
  38. }

最后我们在”确定”按钮的点击事件上调用MarkerTranslateAnimator的startAnimation方法来开始动画

  1. @Override
  2. public void onClick(View view) {
  3. switch (view.getId()){
  4. case R.id.order_btn:
  5. drivingRoutePresent.geocoder(fromET.getText().toString(), DrivingRoutePresent.FROM_TYPE);
  6. drivingRoutePresent.geocoder(toET.getText().toString(), DrivingRoutePresent.TO_TYPE);
  7. confirmBtn.setVisibility(View.VISIBLE);
  8. orderBtn.setVisibility(View.GONE);
  9. break;
  10. case R.id.confirm_btn:
  11. //开启动画移动
  12. mAnimator.startAnimation();
  13. orderBtn.setVisibility(View.VISIBLE);
  14. confirmBtn.setVisibility(View.GONE);
  15. break;
  16. case R.id.location_ib:
  17. //定位当前位置
  18. break;
  19. }
  20. }

基本效果已经完成了,现在还差最后一个定位功能,要实现定位功能需要引入另一个SDK(Android定位SDK)

我们打开Android定位SDK开发文档,下载最新的SDK
将压缩包内的jar包放入app的libs包下,并添加为依赖
再把压缩包libs文件夹下的各个so文件拷贝到项目jniLibs的对应目录中
打开AndroidManifest.xml文件,加入下面权限配置

  1. <!-- 通过GPS得到精确位置 -->
  2. <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  3. <!-- 通过网络得到粗略位置 -->
  4. <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
  5. <!-- 访问网络. 某些位置信息需要从网络服务器获取 -->
  6. <uses-permission android:name="android.permission.INTERNET" />
  7. <!-- 访问WiFi状态. 需要WiFi信息用于网络定位 -->
  8. <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
  9. <!-- 修改WiFi状态. 发起WiFi扫描, 需要WiFi信息用于网络定位 -->
  10. <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
  11. <!-- 访问网络状态, 检测网络的可用性. 需要网络运营商相关信息用于网络定位 -->
  12. <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
  13. <!-- 访问网络的变化, 需要某些信息用于网络定位 -->
  14. <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
  15. <!-- 访问手机当前状态, 需要device id用于网络定位 -->
  16. <uses-permission android:name="android.permission.READ_PHONE_STATE" />
  17. <!-- 支持A-GPS辅助定位 -->
  18. <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
  19. <!-- 用于 log 日志 -->
  20. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

配置完成后,我们在DrivingRouteContract.Presenter接口中加入一个开始定位的startLocation和一个结束定位的stopLocation方法

  1. void startLocation(boolean single);
  2. void stopLocation();

再实现一下DrivingRoutePresent的方法

  1. private boolean IS_SINGLE_LOCATION_MODE = false;//是否连续定位
  2. private TencentLocationManager mLocationManager = TencentLocationManager.getInstance(GlobalApplication.getContext());
  3. private TencentLocationRequest locationRequest;
  4. @Override
  5. public void startLocation(boolean single) {
  6. IS_SINGLE_LOCATION_MODE = single;//因为这里只需要定位一次,所以加了个参数
  7. locationRequest = TencentLocationRequest.create();
  8. locationRequest.setInterval(5000);//定位间隔
  9. //根据用户获取的位置信息的详细程度,REQUEST_LEVEL_ADMIN_AREA:包含经纬度,位置所处的中国大陆行政区划
  10. locationRequest.setRequestLevel(TencentLocationRequest.REQUEST_LEVEL_ADMIN_AREA);
  11. locationRequest.setAllowGPS(true);//是否允许使用GPS定位
  12. mLocationManager.requestLocationUpdates(locationRequest, this);//连续定位
  13. }
  14. @Override
  15. public void stopLocation() {
  16. mLocationManager.removeUpdates(this);
  17. }

除此之外,为了获得定位的位置信息,我们还需要让DrivingRoutePresent额外实现TencentLocationListener接口,实现onLocationChanged(用于接收定位结果)和onStatusUpdate(用于接收GPS,WiFi,Cell的状态码)方法。

  1. @Override
  2. public void onLocationChanged(TencentLocation tencentLocation, int i, String s) {
  3. if (IS_SINGLE_LOCATION_MODE)
  4. stopLocation();
  5. switch (i){
  6. case TencentLocation.ERROR_OK:
  7. //定位成功
  8. drinvingRouteView.setLocation(tencentLocation);
  9. //渲染定位信息
  10. if (drinvingRouteView.getFromET()!=null&&drinvingRouteView.getFromET().getText().toString().trim().equals(""))
  11. drinvingRouteView.getFromET().setText(tencentLocation.getAddress());
  12. // Toast.makeText(GlobalApplication.getContext(), "定位成功", Toast.LENGTH_SHORT).show();
  13. break;
  14. case TencentLocation.ERROR_NETWORK:
  15. Toast.makeText(GlobalApplication.getContext(), "网络问题引起的定位失败", Toast.LENGTH_SHORT).show();
  16. break;
  17. case TencentLocation.ERROR_BAD_JSON:
  18. Toast.makeText(GlobalApplication.getContext(), "GPS, Wi-Fi 或基站错误引起的定位失败", Toast.LENGTH_SHORT).show();
  19. break;
  20. case TencentLocation.ERROR_WGS84:
  21. Toast.makeText(GlobalApplication.getContext(), "无法将WGS84坐标转换成GCJ-02坐标时的定位失败", Toast.LENGTH_SHORT).show();
  22. break;
  23. case TencentLocation.ERROR_UNKNOWN:
  24. Toast.makeText(GlobalApplication.getContext(), "未知原因引起的定位失败", Toast.LENGTH_SHORT).show();
  25. break;
  26. }
  27. }
  28. @Override
  29. public void onStatusUpdate(String s, int i, String s1) {
  30. //TencentLocationListener回调此方法传入的GPS,WiFi,Cell状态码,具体状态码查看Android定位SDK开发文档
  31. }

最后,我们再把给定位的小按钮绑定的点击事件加上实现,在onResume和onPause方法调用一下startLocation和stopLocation方法让app在开启或切换回当前Activity时自动定位

  1. @Override
  2. public void onClick(View view) {
  3. switch (view.getId()){
  4. case R.id.order_btn:
  5. drivingRoutePresent.geocoder(fromET.getText().toString(), DrivingRoutePresent.FROM_TYPE);
  6. drivingRoutePresent.geocoder(toET.getText().toString(), DrivingRoutePresent.TO_TYPE);
  7. confirmBtn.setVisibility(View.VISIBLE);
  8. orderBtn.setVisibility(View.GONE);
  9. break;
  10. case R.id.confirm_btn:
  11. //开启动画移动
  12. mAnimator.startAnimation();
  13. orderBtn.setVisibility(View.VISIBLE);
  14. confirmBtn.setVisibility(View.GONE);
  15. break;
  16. case R.id.location_ib:
  17. //定位一次
  18. drivingRoutePresent.startLocation(true);
  19. break;
  20. }
  21. }
  22. @Override
  23. protected void onResume() {
  24. super.onResume();
  25. mapView.onResume();
  26. drivingRoutePresent.startLocation(true);
  27. }
  28. @Override
  29. protected void onPause() {
  30. super.onPause();
  31. mapView.onPause();
  32. drivingRoutePresent.stopLocation();
  33. }

写到这里,效果图上所有的功能就基本完成了,总的来说,功能还是十分强大的,对于有相关需求的企业来说开发起来非常省时省力。另外开发文档和接口文档也比较详细。由于时间有限,暂时只体验了其中的几个服务,有更多需求的同学可以自行到官网探索。

版权声明:本文为Yi-Xiu原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/Yi-Xiu/p/15291538.html