20212324 2023-2024-2 《移动平台开发与实践》第5次作业

1.实验内容和目的

  • 设计并开发一个地图应用系统。
  • 该实验需提前申请百度API Key,调用接口实现百度地图的定位功能、地图添加覆盖物和显示文本信息。

1.1项目功能

  • 本次实验我通过调用百度地图APK,顺利完成了项目。项目功能如下:
    • 地图显示的是卫星图
    • 可以实现对本机的定位
    • 程序自动在北京电子科技学院地址处标了点,妈妈再也不用担心我找不到学校地址了
    • 可以允许用户在地图上标点(覆盖物)及删除,过程中会弹出提示

2.实验过程

2.1在百度申请密钥

  • 在控制台创建应用,需要发布版的sha1,因此需要在as里创建签名文件,并用keytool来获取sha1

  • 创建release版本的签名文件:

    • 先去Build菜单下生成一个正式的.jks签名文件.Build>Generate signed APK
  • 进行release版本的签名验证:

    • file>project structure>signing
    • 此时在builde.gradle文件中就多了对正式签名文件的配置引用: 注意要在buildTypes中添加对正式签名配置的引用.
  • 3.获取sha1:

    • keytool -list -v -keystore 你的签名文件
  • 4.申请key

2.2配置开发环境

2.2.1在项目中集成BaiduMap SDK

image-20240518144314827

2.2.2添加jar、so文件
  • 在src/main/目录下新建jniLibs目录(如果的项目中已经包含该目录不用重复创建),在下载的开发包中拷贝项目中需要的CPU架构对应的so文件文件夹到jniLibs目录,如图:

image-20240518144858434

  • 在libs目录下,选中每一个jar文件(此处只有一个BaiduLbs_Android.jar)右键,选择Add As Library…
  • 此时会发现在app目录的build.gradle的dependencies块中生成了工程所依赖的jar文件的对应说明,如下所示:

image-20240518144937712

  • 最后如下图所示:

image-20240518144345240

3.编写Kotlin代码

3.1配置AndroidManifest.xml文件

  • 在中加入如下代码配置开发密钥(AK),或者通过SDKInitializer.setApiKey(“ak”)动态设置AK

    • <meta-data
          android:name="com.baidu.lbsapi.API_KEY"
          android:value="6lmYlAJwcQUNz2gGwem8VXpq0T7lDGxG"
      />
      

image-20240518145143717

  • 在外部添加如下权限声明,权限对应的代码均如下

    • <!--百度定位所需要权限,前面是LOCATE权限组的2个危险权限-->
          <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
          <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
          <!--百度定位所需要的普通权限-->
          <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
          <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
          <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
          <!--因为程序要与百度云服务交互-->
          <uses-permission android:name="android.permission.INTERNET"/>
      
3.1 MainActivity.kt
  • package com.example.mapp;
    
    import android.content.DialogInterface;
    import android.os.Bundle;
    
    import androidx.appcompat.app.AlertDialog;
    import androidx.appcompat.app.AppCompatActivity;
    import androidx.fragment.app.FragmentManager;
    
    import com.baidu.location.BDLocation;
    import com.baidu.location.BDLocationListener;
    import com.baidu.location.LocationClient;
    import com.baidu.location.LocationClientOption;
    import com.baidu.mapapi.CoordType;
    import com.baidu.mapapi.SDKInitializer;
    import com.baidu.mapapi.map.BaiduMap;
    import com.baidu.mapapi.map.BaiduMapOptions;
    import com.baidu.mapapi.map.BitmapDescriptor;
    import com.baidu.mapapi.map.BitmapDescriptorFactory;
    import com.baidu.mapapi.map.MapStatus;
    import com.baidu.mapapi.map.MapStatusUpdateFactory;
    import com.baidu.mapapi.map.MapView;
    import com.baidu.mapapi.map.Marker;
    import com.baidu.mapapi.map.MarkerOptions;
    import com.baidu.mapapi.map.MyLocationData;
    import com.baidu.mapapi.map.OverlayOptions;
    import com.baidu.mapapi.map.SupportMapFragment;
    import com.baidu.mapapi.model.LatLng;
    
    
    /*
        百度地图应用,包含定位信息和地图显示
        一般需要打开定位服务,选择高精度定位模式,有网络连接
        需要在清单文件里使用百度云服务(参见清单文件service标签)
        需要创建应用(模块)的Key,并写入清单文件(参见清单文件meta标签)
    */
    public class MainActivity extends AppCompatActivity {
        public MapView mMapView = null;
        public LocationClient mLocClient;
        public BaiduMap mBaiduMap;
        boolean isFirstLoc = true;
        
        protected void onCreate(Bundle savedInstanceState) {
            //定位监视器
            super.onCreate(savedInstanceState);
    
            SDKInitializer.initialize(getApplicationContext());//一定要先初始化,再加载布局
    
            SDKInitializer.setCoordType(CoordType.BD09LL);    //经纬坐标,使用中国国测局的。
    
            setContentView(R.layout.activity_main);  //加载布局
    
            //获取地图控件引用
            mMapView = (MapView) findViewById(R.id.bmapView);
            mBaiduMap = mMapView.getMap();
            initLocation();
    
            // 创建一个标记点
            LatLng latLng = new LatLng(39.844, 116.2855); // 北京电子科技学院的经纬度
    
            // 创建一个MarkerOptions对象,用于设置标记点的属性
            MarkerOptions markerOptions = new MarkerOptions()
                    .position(latLng) // 设置标记点的坐标
                    .icon(BitmapDescriptorFactory.fromResource(R.drawable.icon_lala)) // 设置标记点的图标
                    .anchor(0.5f, 0.5f) // 设置标记点图标的锚点
                    .rotate(30); // 设置标记点图标的旋转角度
    
            // 将MarkerOptions对象添加到地图上,并获取标记对象
            com.baidu.mapapi.map.Marker marker = (com.baidu.mapapi.map.Marker)
                    mBaiduMap.addOverlay(markerOptions);
    
            //地图长按事件监听接口
            BaiduMap.OnMapLongClickListener longClickListener = new BaiduMap.OnMapLongClickListener() {
                //point 长按的地理坐标
                @Override
                public void onMapLongClick(LatLng point) {
                    //弹出确认框
                    AlertDialog alertDialog = new AlertDialog.Builder(MainActivity.this)
                            .setTitle("创建标点")
                            .setMessage("是否创建标点?")
                            .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialogInterface, int i) {
                                    //构建Marker图标
                                    BitmapDescriptor bitmapDescriptor = BitmapDescriptorFactory.fromResource(R.drawable.icon_lala);
                                    //构建MarkerOption,用于在地图上添加Marker
                                    OverlayOptions overlayOptions = new MarkerOptions()
                                            .position(point)
                                            .icon(bitmapDescriptor);
                                    //在地图上添加Marker,并显示
                                    mBaiduMap.addOverlay(overlayOptions);
                                }
                            })
                            .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialogInterface, int i) {
                                    return;
                                }
                            }).create();
                    alertDialog.show();
                }
            };
            //设置地图长按事件监听
            mBaiduMap.setOnMapLongClickListener(longClickListener);
            mBaiduMap.setOnMarkerClickListener(new BaiduMap.OnMarkerClickListener() {
                //marker被点击时回调的方法
                //若响应点击事件,返回true,否则返回false
                //默认返回false
                @Override
                public boolean onMarkerClick(Marker marker) {
                    //弹出确认框
                    AlertDialog alertDialog = new AlertDialog.Builder(MainActivity.this)
                            .setTitle("创建标点")
                            .setMessage("是否删除标点?")
                            .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialogInterface, int i) {
                                    marker.remove();
                                }
                            })
                            .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialogInterface, int i) {
                                    return;
                                }
                            }).create();
                    alertDialog.show();
                    return true;
                }
            });
    
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            //在activity执行onResume时执行mMapView. onResume (),实现地图生命周期管理
            mMapView.onResume();
        }
        @Override
        protected void onPause() {
            super.onPause();
            //在activity执行onPause时执行mMapView. onPause (),实现地图生命周期管理
            mMapView.onPause();
        }
        @Override
        protected void onDestroy(){
            super.onDestroy();
    
            if(null!= mMapView){
                mMapView.onDestroy();
            }
        }
    
        public void initLocation(){
    // 开启定位图层
            mBaiduMap.setMyLocationEnabled(true);
    // 定位初始化
            mLocClient = new LocationClient(this);
            MyLocationListener myListener = new MyLocationListener();
            mLocClient.registerLocationListener(myListener);
            LocationClientOption option = new LocationClientOption();
    // 打开gps
            option.setOpenGps(true);
    // 设置坐标类型
            option.setCoorType("bd09ll");
    
            option.setScanSpan(1000);
    
            mLocClient.setLocOption(option);
    
            mLocClient.start();
        }
        public class MyLocationListener implements BDLocationListener {
    
            @Override
    
            public void onReceiveLocation(BDLocation location) {
    
    // MapView 销毁后不在处理新接收的位置
    
                if (location == null || mMapView == null) {
    
                    return;
    
                }
    
                MyLocationData locData = new MyLocationData.Builder()
    
                        .accuracy(location.getRadius())// 设置定位数据的精度信息,单位:米
    
                        .direction(location.getDirection()) // 此处设置开发者获取到的方向信息,顺时针0-360
    
                        .latitude(location.getLatitude())
    
                        .longitude(location.getLongitude())
    
                        .build();
    
    // 设置定位数据, 只有先允许定位图层后设置数据才会生效
    
                mBaiduMap.setMyLocationData(locData);
    
                if (isFirstLoc) {
    
                    isFirstLoc = false;
    
                    LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
    
                    MapStatus.Builder builder = new MapStatus.Builder();
    
                    builder.target(latLng).zoom(20.0f);
    
                    mBaiduMap.animateMapStatus(MapStatusUpdateFactory.newMapStatus(builder.build()));
    
                }
    
            }
    
        }
    }
    
    
activity_main.xml布局代码
  • <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">
            <com.baidu.mapapi.map.MapView
                android:id="@+id/bmapView"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:clickable="true" />
    
        </LinearLayout>
    
    </FrameLayout>
    
DemoApplication
  • 在SDK各功能组件使用之前都需要调用“SDKInitializer.initialize(getApplicationContext())”,因此我们直接在应用创建时初始化SDK引用的Context为全局变量。
import android.app.Application;
import com.baidu.mapapi.CoordType;
import com.baidu.mapapi.SDKInitializer;

public class DemoApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        //在使用SDK各组件之前初始化context信息,传入ApplicationContext
        SDKInitializer.initialize(this);
        //自4.3.0起,百度地图SDK所有接口均支持百度坐标和国测局坐标,用此方法设置您使用的坐标类型.
        //包括BD09LL和GCJ02两种坐标,默认是BD09LL坐标。
        SDKInitializer.setCoordType(CoordType.BD09LL);
    }
}
  • 在AndroidManifest.xml文件中声明该Application

(四)运行与调试

  • 运行程序,给予程序定位权限:

image-20240518152915792

  • 演示视频如下

2024-05-17 23-19-03

3.学习中遇到的困难及解决

  • 问题1:在实现标记和删除覆盖物部分功能时,需要我们自己导入素材xxx.png到/res/drawable目录

    image-20240518154307424

    问题1解决方案:一开始我想到找一个电脑上应用的图标,比较干净没有背景:

    image-20240518153837751

    谁曾想不支持.ico,最后到网上截了个图,调整大小后作为素材导入

  • 问题2:在实现自动在北京电子科技学院上标点功能时,搜索到的经纬度和地图上略有差异

    问题2解决方案:通过逐次实验(猜测及二分法),我终于将标点标到了操场上!附前后经纬度差异

    image-20240518154137412

    image-20240518154235153

  • 问题3:对本机的定位定到了非洲黄金海岸甚至是大西洋上

    问题3解决方案:多次尝试仍无解,猜测本虚拟机API版本过低(24),不能具备相应正确定位功能:(

4.学习感悟、思考

  • 本次实验通过实践操作,结合之前实践,我更加掌握了百度地图SDK及其内部的各种模块各种类的定义及使用方法,并成功实现了定位、地图添加覆盖物和显示信息。
  • 实验中还是遇到了很多问题,但好在有前人栽树,代码逻辑的实现等都比较顺利。此外,官方的参考文档让我受益颇丰,不会对着偌大的接口无能为力!

参考资料

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐