Android Studio 实现地图定位(移动开发技术作业)

文章正文
发布时间:2024-11-12 20:37

一、项目要求

1.根据百度地图提供的开发者文档,创建项目实现地图。
2.可以提供地图显示,定位具体位置的功能。

二、项目功能展示

因为我进行了两次实验,两个项目都成功运行,只是界面有少许偏差

在这里插入图片描述


在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

三、项目具体实现方法 1.创建项目及Android studio基础配置

在android studio 中创建一个新的空白项目

在这里插入图片描述

在这里插入图片描述

打开浏览器搜索百度地图进入开放平台,然后点开开发文档选择地图SDK

在这里插入图片描述

在文档底部根据提示完成前两个步骤,如果已有百度账号可以跳过注册直接申请称为百度地图开发者

在这里插入图片描述


完成前两步的注册,申请开发者之后选择获取服务密钥(如果之前之前做过相关开发项目已经成为百度地图开发者可以在首页控制台选择创建应用)
应用名称根据需要自取,应用类型选择android sdk 应用服务根据需要选择,如果只是最基础的显示地图可以在只选择Android地图SDK和定位SDK

在这里插入图片描述


包名打开项目的中的manifests 复制粘贴

在这里插入图片描述

在这里插入图片描述


获取SHA1,SHA1为每个android studio中独有的(图片中进行了马赛克处理)具体获取方式如下
(1)打开项目的gradle,点击tasks文件下的signingReport即可获取

在这里插入图片描述


在这里插入图片描述


最新版本的Android studio 中gradle下面的文件是空的,没有Tasks文件夹,我们可以打开设置,将下图选型中的对钩取消选中然后同步即可

在这里插入图片描述

(2)如果因为android studio的版本问题 实在无法找到可以通过另一种方式进行查询 找到sdk 安装路径 (我的是D:\app-s3\as\jre)
在Terminal 控制台cd进入此路径,在c盘用户内android安装路径下面发现存在dubug.keystore即输入命令
keytool -list -v -keystore C:\Users\12828.android\ debug.keystore (debug.keystore所在路径)-alias androiddebugkey
密钥口令为 android 输入完成后即可获得SHA1

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述

在这里插入图片描述


在这里插入图片描述


在浏览器百度地图页面中下载相关开发包

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


打开开发包中文件夹将文件复制到android studio的项目中
将android界面改为project界面,将开发包文件复制到app下面的libs文件中

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


打开build.gradle,复制如下代码进去,注意放置的位置是在android闭包中,然后Sync,保存修改配置文件

在这里插入图片描述


在这里插入图片描述

在这里插入图片描述


我们将libs文件下的包添加到build中(此处我已经添加过了,首次使用的直接点击添加即可)
点开build中发现添加成功即可

在这里插入图片描述


在这里插入图片描述


我们记住我们之前创建应用的密钥AK(AK复制到manifest中)

在这里插入图片描述

2.将地图进行显示以及定位(代码实现)

新建java class 文件继承application类进行地图初始化

package com.example.lbsgwl; import android.app.Application; import com.baidu.mapapi.CoordType; import com.baidu.mapapi.SDKInitializer; public class gwlLbs 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); } }

修改manifest文件
在application标签中添加刚才新建的java class项目名

在这里插入图片描述

在application 外面中添加权限

<!-- 访问网络,进行地图相关业务数据请求,包括地图数据,路线规划,POI检索等 --> <uses-permission android:name="android.permission.INTERNET" /> <!-- 获取网络状态,根据网络状态切换进行数据请求网络转换 --> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <!-- 读取外置存储。如果开发者使用了so动态加载功能并且把so文件放在了外置存储区域,则需要申请该权限,否则不需要 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <!-- 写外置存储。如果开发者使用了离线地图,并且数据写在外置存储区域,则需要申请该权限 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!-- 这个权限用于进行网络定位 --> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <!-- 这个权限用于访问GPS定位 --> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

在application 标签中写入代码密钥配置 value中的值为AK即上图在百度中申请所得

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

在application标签中放入定位权限

<service android:name="com.baidu.location.f" android:enabled="true" android:process=":remote"/>

mainactivity java文件

package com.example.lbsgwl; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import android.Manifest; import android.content.pm.PackageManager; import android.os.Bundle; import com.baidu.location.BDAbstractLocationListener; import com.baidu.location.BDLocation; import com.baidu.location.LocationClient; import com.baidu.location.LocationClientOption; import com.baidu.mapapi.map.BaiduMap; import com.baidu.mapapi.map.MapStatus; import com.baidu.mapapi.map.MapStatusUpdateFactory; import com.baidu.mapapi.map.MapView; import com.baidu.mapapi.map.MyLocationData; import com.baidu.mapapi.model.LatLng; public class MainActivity extends AppCompatActivity { private MapView mapView; private BaiduMap baiduMap; private LocationClient mLocationClient; boolean isFirstLoc = true ; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mapView = findViewById(R.id.bmapView); baiduMap = mapView.getMap(); initLocation(); } public class MyLocationListener extends BDAbstractLocationListener { @Override public void onReceiveLocation(BDLocation location) { //mapView 销毁后不在处理新接收的位置 if (location == null || mapView == null){ return; } MyLocationData locData = new MyLocationData.Builder() .accuracy(location.getRadius()) // 此处设置开发者获取到的方向信息,顺时针0-360 .direction(location.getDirection()).latitude(location.getLatitude()) .longitude(location.getLongitude()).build(); baiduMap.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); baiduMap.animateMapStatus(MapStatusUpdateFactory.newMapStatus(builder.build())); } } } public void initLocation(){ // 开启定位图层 baiduMap.setMyLocationEnabled(true); // 定位初始化 mLocationClient = new LocationClient(this); MyLocationListener myListener = new MyLocationListener(); mLocationClient.registerLocationListener(myListener); LocationClientOption option = new LocationClientOption(); // 打开gps option.setOpenGps(true); // 设置坐标类型 option.setCoorType("bd09ll"); option.setScanSpan(1000); mLocationClient.setLocOption(option); mLocationClient.start(); } @Override protected void onResume() { super.onResume(); mapView.onResume(); //可以显示地图类型,type里面的参数决定 // mapView.getMap().setMapType(BaiduMap.MAP_TYPE_SATELLITE); } @Override protected void onPause() { super.onPause(); mapView.onPause(); } @Override protected void onDestroy() { super.onDestroy(); mLocationClient.stop(); baiduMap.setMyLocationEnabled(false); mapView.onDestroy(); // mapView = null; } }

activity.xml文件中添加地图控件

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="" xmlns:app="" xmlns:tools="" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <com.baidu.mapapi.map.MapView android:id="@+id/bmapView" android:layout_width="match_parent" android:layout_height="match_parent" android:clickable="true" /> </LinearLayout>

到此为止我们已经完成了初步的地图显示及定位,但是简单的定位没有经纬度,定位图标在放大缩小的过程中还会消失。所以我们需要对其进行完善。实现地图切换之后,点击重新定位,显示具体的经纬度以及位置等。完整的Mainactivity代码如下

package com.example.gwlbaid; import androidx.appcompat.app.AppCompatActivity; import android.Manifest; import android.app.Activity; import android.os.Build; import android.os.Bundle; import android.view.View; import android.widget.ImageButton; import android.widget.Toast; import com.baidu.location.BDLocation; import com.baidu.location.BDLocationListener; import com.baidu.location.LocationClient; import com.baidu.location.LocationClientOption; import com.baidu.mapapi.map.BaiduMap; import com.baidu.mapapi.map.BitmapDescriptor; import com.baidu.mapapi.map.BitmapDescriptorFactory; import com.baidu.mapapi.map.MapPoi; 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.model.LatLng; import com.tbruyelle.rxpermissions2.RxPermissions; public class MainActivity extends AppCompatActivity { private MapView mMapView; private LocationClient mLocClient; private BaiduMap mBaiduMap; private BitmapDescriptor bitmap;//标点的图标 private double markerLatitude = 0;//标点纬度 private double markerLongitude = 0;//标点经度 private ImageButton ibLocation;//重置定位按钮 private Marker marker;//标点也可以说是覆盖物 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView();//视图初始化 checkVersion();//检查版本 mapOnClick();//地图点击 } private void checkVersion() { if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.M){ RxPermissions rxPermissions = new RxPermissions(this); rxPermissions.request(Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.READ_PHONE_STATE, Manifest.permission.WRITE_EXTERNAL_STORAGE) .subscribe(granted -> { if (granted) {//申请成功 //发起连续定位请求 initLocation();// 定位初始化 } else {//申请失败 Toast.makeText(MainActivity.this,"权限未开启",Toast.LENGTH_SHORT).show(); } }); }else { initLocation();// 定位初始化 } } private void initView() { // 地图初始化 mMapView = (MapView) findViewById(R.id.bmapView); //回到当前定位 ibLocation = (ImageButton) findViewById(R.id.ib_location); mMapView.showScaleControl(true); // 设置比例尺是否可见(true 可见/false不可见) //mMapView.showZoomControls(false); // 设置缩放控件是否可见(true 可见/false不可见) mMapView.removeViewAt(1);// 删除百度地图Logo mBaiduMap = mMapView.getMap(); mBaiduMap.setOnMarkerClickListener(new BaiduMap.OnMarkerClickListener() { @Override public boolean onMarkerClick(Marker marker) { final String info = (String) marker.getExtraInfo().get("info"); Toast.makeText(MainActivity.this, info, Toast.LENGTH_SHORT).show(); return true; } }); } /** * 地图点击 */ private void mapOnClick() { // 设置marker图标 bitmap = BitmapDescriptorFactory.fromResource(R.drawable.icon_marka); mBaiduMap.setOnMapClickListener(new BaiduMap.OnMapClickListener() { @Override public void onMapPoiClick(MapPoi mapPoi) { } //此方法就是点击地图监听 @Override public void onMapClick(LatLng latLng) { //获取经纬度 markerLatitude = latLng.latitude; markerLongitude = latLng.longitude; //先清除图层 mBaiduMap.clear(); // 定义Maker坐标点 LatLng point = new LatLng(markerLatitude, markerLongitude); // 构建MarkerOption,用于在地图上添加Marker MarkerOptions options = new MarkerOptions().position(point) .icon(bitmap); // 在地图上添加Marker,并显示 //mBaiduMap.addOverlay(options); marker = (Marker) mBaiduMap.addOverlay(options); Bundle bundle = new Bundle(); bundle.putSerializable("info", "纬度:" + markerLatitude + " 经度:" + markerLongitude); marker.setExtraInfo(bundle);//将bundle值传入marker中,给baiduMap设置监听时可以得到它 //点击地图之后重新定位 initLocation(); } }); } /** * 定位初始化 */ public void initLocation() { // 开启定位图层 mBaiduMap.setMyLocationEnabled(true); // 定位初始化 mLocClient = new LocationClient(this); MyLocationListener myListener = new MyLocationListener(); mLocClient.registerLocationListener(myListener); LocationClientOption option = new LocationClientOption(); option.setOpenGps(true);// 打开gps option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);// 设置高精度定位 option.setCoorType("bd09ll");//可选,默认gcj02,设置返回的定位结果坐标系 option.setScanSpan(0);//可选,默认0,即仅定位一次,设置发起定位请求的间隔需要大于等于1000ms才是有效的 option.setIsNeedAddress(true);//可选,设置是否需要地址信息,默认不需要 option.setOpenGps(true);//可选,默认false,设置是否使用gps option.setIsNeedLocationDescribe(true);//可选,默认false,设置是否需要位置语义化结果,可以在BDLocation.getLocationDescribe里得到,结果类似于“在北京天安门附近” option.setIsNeedLocationPoiList(true);//可选,默认false,设置是否需要POI结果,可以在BDLocation.getPoiList里得到 option.setIgnoreKillProcess(false);//可选,默认false,定位SDK内部是一个SERVICE,并放到了独立进程,设置是否在stop的时候杀死这个进程,默认杀死 option.SetIgnoreCacheException(false);//可选,默认false,设置是否收集CRASH信息,默认收集 option.setEnableSimulateGps(false);//可选,默认false,设置是否需要过滤gps仿真结果,默认需要 mLocClient.setLocOption(option); mLocClient.start();//开始定位 } /** * 点切换到其他标点位置时,重置定位显示,点击之后回到自动定位 */ public void resetLocation(View view) { markerLatitude = 0; initLocation(); marker.remove();//清除标点 } /** * 定位SDK监听函数 */ public class MyLocationListener implements BDLocationListener { @Override public void onReceiveLocation(BDLocation location) { Toast.makeText(MainActivity.this,location.getAddrStr(),Toast.LENGTH_SHORT).show(); // MapView 销毁后不在处理新接收的位置 if (location == null || mMapView == null) { return; } double resultLatitude; double resultLongitude; if (markerLatitude == 0) {//自动定位 resultLatitude = location.getLatitude(); resultLongitude = location.getLongitude(); ibLocation.setVisibility(View.GONE); } else {//标点定位 resultLatitude = markerLatitude; resultLongitude = markerLongitude; ibLocation.setVisibility(View.VISIBLE); } MyLocationData locData = new MyLocationData.Builder() .accuracy(location.getRadius())// 设置定位数据的精度信息,单位:米 .direction(location.getDirection()) // 此处设置开发者获取到的方向信息,顺时针0-360 .latitude(resultLatitude) .longitude(resultLongitude) .build(); mBaiduMap.setMyLocationData(locData);// 设置定位数据, 只有先允许定位图层后设置数据才会生效 LatLng latLng = new LatLng(resultLatitude, resultLongitude); MapStatus.Builder builder = new MapStatus.Builder(); builder.target(latLng).zoom(20.0f); mBaiduMap.animateMapStatus(MapStatusUpdateFactory.newMapStatus(builder.build())); } } @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(); // 退出时销毁定位 mLocClient.stop(); // 关闭定位图层 mBaiduMap.setMyLocationEnabled(false); // 在activity执行onDestroy时必须调用mMapView.onDestroy() mMapView.onDestroy(); } } 四、遇到的问题解决方法及总结

在实验过程中,首次利用虚拟机定位发现了定位出错的情况,地图定位到了非洲的几内亚海湾,界面被蓝色海洋界面覆盖,缩小视图过程中发现了定位图标消失的情况。通过查看开发文档、课程ppt以及网上资料之后**添加了动态申请权限,以及检查手机权限是否正确打开。

在这里插入图片描述


但是仍然出现了定位错误的问题,考虑可能是某一步骤出现问题或者开发包以及应用服务出错,我又新建项目重新写了一遍,每一步都仔细检查过后运行发现定位到了谷歌公司的总部,经纬度显示,重定位功能等正常只有实时定位出错。我意识到可能不是项目代码或者权限的问题。查询资料以及一些开发者的博客意识到可能是采用虚拟机运行的问题,(也可能是官方对开发包做出修改)**最后换成真机调试运行成功,并且我创建的两个定位项目都正常定位。**再次验证项目本身没有问题。不过在进行真机调试过程中,出现了安装app失败情况!在gradle.properties中添加android.injected.testOnly=false 然后同步即可解决

在这里插入图片描述

五、项目源代码链接

Gitee项目源代码

首页
评论
分享
Top