Android Studio+百度地图API实现简单gis移动端App
Posted 你们瞎搞
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Studio+百度地图API实现简单gis移动端App相关的知识,希望对你有一定的参考价值。
由于很多内容网上都是详细说明,但是我在帮助同学们解决问题过程遇到许多奇怪的问题,花了很多时间去解决,网上查不到,所以值得我记录下来,让后面的学弟学妹节省大部分时间!!同时我也会将该文章发布到我的csdn账号中,大家也可以直接查找噢。涉及到的代码文件下载链接我放在文末了。
1.Android Studio环境配置
下载地址:
Download Android Studio and SDK tools | Android Developers
android Studio环境配置具体教程:
Android Studio安装教程(AS教程)(超级全,包括JDK,SDK,AVD虚拟机的下载安装)_是阿熊呀的博客-CSDN博客_as安装教程
as安装结尾中有一个时勾选下载android SDK的选项无法勾选!!!!但是一样可以安装完,只不过后面打开as根本无法点击运行程序,所以这个sdk必须下载。
在那个页面等待5分钟后再点击即可勾选下载对应SDK!!!!
其他方法,比如卸载重装as多次或者参考网上的方法另外安装android SDK后打开as配置sdk指定到安装android SDK的文件夹也没有用。
2.Android Studio模拟器/真机选择
2.1模拟器
由于是安卓开发,要查看开发效果需要手机支撑,可以选择安装夜神模拟器,下载链接:
夜神安卓模拟器-安卓模拟器电脑版下载_安卓手游模拟器_手机模拟器_官网
即使打开了夜神模拟器,有时候AS也不会自动连接上夜神模拟器,如下图所示:
2.1.1解决方法
1.需要我们找到夜神模拟器安装路径中的bin文件夹路径,如下图所示:
nox_adb.exe connect 127.0.0.1:62001
命令行出现如下信息,这时候as会自动连接到夜神模拟器,如果等了10秒钟还不行就在复制代码运行一遍,如下图所示:
提示:夜神模拟器很占内存,运行起来电脑会发烫。
2.2手机真机
当然也可以使用通过手机原装充电线连接到电脑进行真机测试,不同手机打开开发者模式不同,具体可百度查找,我的是VIVO双击【关于手机】->【版本信息】->【软件版本号】,这时候开发者选项就会出现,将【开发者选项】和【USB调试】都打开,这时候手机会弹出【允许USB调试吗?】,点击允许即可。这时候as会自动连接到你的手机,如下图所示:
有的同学手机(比如华为)在测试时安装app即使无视风险也无法安装,但我的手机(vivo)权限开完可无视风险完成安装,如下图所示:
解决方法:
参考这个链接:AirtestIDE连接安卓真机及常见问题 - ☆星空物语☆ - 博客园,实在不行就用夜神模拟器吧。
3.实习内容
如下图所示,主要是利用Android Studio结合百度地图SDK开发一款简单的GIS移动端App,基本功能包括地图显示,地图切换,定位和路线规划。具体可参考Android 地图SDK官网:https://lbsyun.baidu.com/index.php?title=androidsdk。
3.1开发准备
3.1.1获取密钥(遇到非常多问题,最耗时,最复杂!)
如何获取看下图:
我由于已经申请成功,跳转界面如下所示:
具体申请这个AK的方法在下面这个链接:
Android 百度地图SDK 自动定位、标记定位_初学者-Study的博客-CSDN博客_地图定位标记
1.如果在这个申请过程中终端命令行出现
请输入申请密钥库口令:
这个时候你输入的东西是不会显示的,确保输入正确后直接点回车键即可。
2.输入的命令行出现如下报错(很多同学遇到这个问题):
'keytool' 不是内部或外部命令,也不是可运行的程序 或批处理文件。
这个你首先复制到百度参考网上的方法,绝大部分是因为同学们电脑没有安装好java运行环境jdk,所以下载安装好这个jdk,并且主要到电脑环境变量中配置好相关环境这个务必做到位,不然还是会出现那个报错!!!!
3.1.2下载SDK本地依赖
注意选择基础定位,基础地图,检索(用于poi检索),开发包格式:JAR,应用发布平台:标准开发。
3.1.3 Android Studio配置
参考官网即可,如下图所示:
注意:第二步中添加so文件建议使用第二种方式:
3.2正式实现功能
activity_main.xml文件中标签和MainActivity类变量可能比较难搞明白放在那个标签内,可以直接参考我最后面的activity_main.xml和MainActivity类变量的截图,简单明了。
代码粘贴进去肯定很多报错,都是红色,把鼠标放上去导入类即可。
3.2.1显示地图
跟着官网进行即可。
注意:这里第三步地图初始化中意思是在MainActivity类同级目录下新建一个名为DemoApplication的java类,如下图所示:
遇到的问题5:
代码没有任何问题,但地图显示运行起来闪退!!!
解决方法:
在DemoApplication类中添加如下一行代码,官网没有直接写出来,但是没有这行app运行起来会闪退(问题困扰我很久,请教了其他同学知道这个方法的)。
官网在【开发注意事项】中提到了,但我们没在意。
3.2.2地图定位
注意确保前面的地图显示可以正常显示的情况下进行地图定位功能的开发,地图定位的代码除了第1、2步配置.xml文件外的其他代码都放在MainActivity类中!!!!
1.配置AndroidManifest.xml文件
//加入如下权限使用声明
<!-- 这个权限用于进行网络定位 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- 这个权限用于访问GPS定位 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
2.在AndroidManifest.xml的Application标签中中声明定位的service组件
<service android:name="com.baidu.location.f"
android:enabled="true"
android:process=":remote"/>
3.在MainActivity类中定义如下变量:
private MapView mMapView=null;
private BaiduMap mBaiduMap =null;
private LocationClient mLocationClient=null;
private boolean isFirstLocate = true;
private boolean isFirstLoc=true;
4.在MainActivity类onCreate函数中填写以下代码:
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LocationClient.setAgreePrivacy(true);
mMapView = (MapView) findViewById(R.id.bmapView);
mBaiduMap = mMapView.getMap();
mBaiduMap.clear();
try
//定位方法
InitLocation();
catch (Exception e)
e.printStackTrace();
5.上述代码中,InitLocation()函数设置为如下(放在onCreate函数外面):
public void InitLocation() throws Exception
mBaiduMap.setMyLocationEnabled(true);
//定位初始化
mLocationClient = new LocationClient(this);
MyLocationListener myListener = new MyLocationListener();
mLocationClient.registerLocationListener(myListener);
//通过LocationClientOption设置LocationClient相关参数
LocationClientOption option = new LocationClientOption();
option.setOpenGps(true); // 打开gps
option.setCoorType("bd09ll"); // 设置坐标类型
option.setScanSpan(1000);
//设置locationClientOption
mLocationClient.setLocOption(option);
//开启地图定位图层
mLocationClient.start();
6.紧接着InitLocation()函数后面新建MyLocationListener类通过继承抽象类BDAbstractListener并重写其onReceieveLocation方法来获取定位数据,并将其传给MapView。
public class MyLocationListener extends BDAbstractLocationListener
@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();
latitude = locData.latitude;
longitude = locData.longitude;
// 设置定位数据, 只有先允许定位图层后设置数据才会生效
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(18.0f);
mBaiduMap.animateMapStatus(MapStatusUpdateFactory.newMapStatus(builder.build()));
遇到的问题6:
即使是手机真机或者夜神模拟器都打开了定位,但还是定位到几内亚湾或者国内其他地方。
解决方法:
在夜神模拟器定位中搜索湖南科技大学,主动定位到真实位置。
3.2.3地图切换
1.在activity_main.xml中声明地图切换监听器组件
<RadioGroup
android:id="@+id/mapleixing0"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:orientation="horizontal"
android:background="@color/teal_200"
>
<RadioButton
android:id="@+id/mapleixing2"
android:layout_width="134dp"
android:layout_height="match_parent"
android:text="卫星地图" />
<RadioButton
android:id="@+id/mapleixing1"
android:layout_width="140dp"
android:layout_height="wrap_content"
android:text="普通地图" />
</RadioGroup>
2.在MainActivity类中定义局部变量用于切换地图监听器:
private RadioGroup mapleixing;
3.在MainActivity类onCreate函数中填写以下代码:
mapleixing = findViewById(R.id.mapleixing0);
setListeners();
4.上述代码中,setListeners()监听器切换地图方法设置为如下(放在onCreate函数外面):
protected void setListeners()
mapleixing.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener()
@SuppressLint("NonConstantResourceId")
@Override
public void onCheckedChanged(RadioGroup radioGroup, int i)
switch (i)
case R.id.mapleixing1:
mBaiduMap.setMapType(BaiduMap.MAP_TYPE_NORMAL);
break;
case R.id.mapleixing2:
mBaiduMap.setMapType(BaiduMap.MAP_TYPE_SATELLITE);
break;
);
3.2.4 POI检索
1.MainActivity类中定义如下变量:
private String cityName;
private EditText keyWords_et;
private PoiNearbySearchOption nearbySearchOption;
private PoiCitySearchOption citySearchOption;
private PoiSearch mPoiSearch = null;
private Button nearsearch = null;
private Button citysearch = null;
private double latitude;
private double longitude;2地图定位
2.在activity_main.xml中使用线性布局POI点击按钮
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<EditText
android:id="@+id/keywords_et"
android:layout_width="150dp"
android:layout_height="wrap_content" />
<Button
android:id="@+id/nearsearch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="城内搜索" />
<Button
android:id="@+id/citysearch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="附近搜索" />
</LinearLayout>
3.把PoiOverlay.java、OverlayManager.java拷贝到项目中如下位置:
4.将POI图标拷贝放到如下位置:
5.在之前定位功能中的InitLocation()函数添加如下一行代码,用于查找周围POI:
option.setIsNeedAddress(true);
6.在之前定位功能中的MyLocationListener类添加如下一行代码,用于查找所属城市名称
cityName = location.getCity();
7.在MainActivity类onCreate函数中填写以下代码:
//这是所需变量
citysearch = findViewById(R.id.citysearch);
nearsearch = findViewById(R.id.nearsearch);
keyWords_et = findViewById(R.id.keywords_et);
//mPoiSearch是检索的执行对象,这里将它实例化
mPoiSearch = PoiSearch.newInstance();
//为poi检索注册监听器#####################
OnGetPoiSearchResultListener poiListener = new OnGetPoiSearchResultListener()
@Override
public void onGetPoiResult(PoiResult poiResult)
if (poiResult == null || poiResult.error == SearchResult.ERRORNO.RESULT_NOT_FOUND)
Toast.makeText(MainActivity.this, "未搜索到结果", Toast.LENGTH_SHORT).show();
return;
if (poiResult.error == SearchResult.ERRORNO.NO_ERROR)
mBaiduMap.clear();
PoiOverlay overlay = new PoiOverlay(mBaiduMap);
overlay.setData(poiResult);
overlay.addToMap();
overlay.zoomToSpan();
return;
@Override
public void onGetPoiDetailResult(PoiDetailResult poiDetailResult)
@Override
public void onGetPoiDetailResult(PoiDetailSearchResult poiDetailResult)
if (poiDetailResult.error != SearchResult.ERRORNO.NO_ERROR)
Toast.makeText(MainActivity.this, "抱歉,未找到结果", Toast.LENGTH_SHORT).show();
else
Toast.makeText(MainActivity.this, "成功,查看详情界面", Toast.LENGTH_SHORT).show();
@Override
public void onGetPoiIndoorResult(PoiIndoorResult poiIndoorResult)
;
//注册附近搜索检索poi按钮点击事件
nearsearch.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View view)
mPoiSearch.setOnGetPoiSearchResultListener(poiListener);
searchNearBy(keyWords_et.getText().toString());
);
//注册城内搜索检索poi按钮点击事件
citysearch.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View view)
mPoiSearch.setOnGetPoiSearchResultListener(poiListener);
searchInCity(keyWords_et.getText().toString());
);
8.在MainActivity类onCreate函数外写按钮的时间回调函数:
//城内搜索POI方法#########################
public void searchInCity(String keyWord)
citySearchOption = new PoiCitySearchOption();
citySearchOption.city(cityName).keyword(keyWord).pageNum(10);
mPoiSearch.searchInCity(citySearchOption);
//搜索附近POI方法#########################
public void searchNearBy(String keyWord)
nearbySearchOption = new PoiNearbySearchOption();
nearbySearchOption.keyword(keyWord).location(new LatLng(latitude, longitude))
.radius(500) //半径 米
.pageCapacity(50);//默认条数
mPoiSearch.searchNearby(nearbySearchOption);
遇到的问题7:
代码完全正确,可以运行出来,但是无论点击城内搜索还是附近搜索按钮都没有结果显示。
解决方法:
打开运行选项,可以看到这个报错,其实在实现POI搜索这个功能之前,地图显示、定位和地图切换也都出现过这个错误对吧,但是没有影响功能的实现,外面也就没有搭理它,但是现在不行了,需要解决它,不然poi搜索功能无法实现!!把下面这个sha1代码复制:
打开之前申请的AK界面,点击设置:
将开发版SHA1替换为刚才复制的sha1代码后点击提交,这时候再运行App发现poi检索按钮可以实现对应的功能了。
3.2.5 路线规划
1.将WalkingRouteOverlay.java文件拖进项目如下位置中:
2.在布局文件中添加一个路径规划按钮(紧接着之前的POI查询按钮)
<Button
android:id="@+id/routeplan"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="路线规划" />
private RoutePlanSearch mRoutePlanSearch = null;
private Button routeplan = null;
4.在MainActivity类onCreate函数中填写以下代码:
//路径规划
routeplan = findViewById(R.id.routeplan);
mRoutePlanSearch = RoutePlanSearch.newInstance();
//创建路径规划结果监听器#####################################
OnGetRoutePlanResultListener routePlanResultListener = new OnGetRoutePlanResultListener()
@Override
public void onGetWalkingRouteResult(WalkingRouteResult result)
if (result == null || result.error != SearchResult.ERRORNO.NO_ERROR)
if (result == null)
System.out.println("error1");
if (result.error != SearchResult.ERRORNO.NO_ERROR)
System.out.println("error2");
Toast.makeText(MainActivity.this, "抱歉未找到结果", Toast.LENGTH_SHORT).show();
return;
if (result.error == SearchResult.ERRORNO.NO_ERROR)
if (result.getRouteLines().size() >= 1)
try
RouteLine route = result.getRouteLines().get(0);
mBaiduMap.clear();
WalkingRouteOverlay overlay = new WalkingRouteOverlay(mBaiduMap);
overlay.setData((WalkingRouteLine) route);
overlay.addToMap();
overlay.zoomToSpan();
catch (Exception e)
e.printStackTrace();
@Override
public void onGetTransitRouteResult(TransitRouteResult transitRouteResult)
@Override
public void onGetMassTransitRouteResult(MassTransitRouteResult massTransitRouteResult)
@Override
public void onGetDrivingRouteResult(DrivingRouteResult drivingRouteResult)
@Override
public void onGetIndoorRouteResult(IndoorRouteResult indoorRouteResult)
@Override
public void onGetBikingRouteResult(BikingRouteResult bikingRouteResult)
;
//为路线规划按钮注册点击事件
routeplan.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
PlanNode stNode = PlanNode.withLocation(new LatLng(latitude, longitude));
PlanNode edNode = PlanNode.withLocation(new LatLng(27.88291, 112.85986));
/**/
mRoutePlanSearch.setOnGetRoutePlanResultListener((OnGetRoutePlanResultListener) routePlanResultListener);
mRoutePlanSearch.walkingSearch(new WalkingRoutePlanOption().from(stNode).to(edNode));
);
activity_main.xml文件截图
MainActivity类变量的截图
功能实现效果图
其他功能可以自己实现,比如我实现绘制科大地图,但是由于百度地图坐标系特殊,我采集的坐标点是WGS84的经纬度,所以会出现整体的偏差。
Android Studio 配置使用百度api (附带简单样例)
还是和同学开发的那个课程作业项目的app, 要使用到百度地图的api
但是,官方文档貌似只有Eclipse的例子,对Android Studio似乎没有说明. 难道,是因为后者是 "Doodle" 的产品 ? 呵呵
api的使用很简单。 类Field和方法,官方文档已经给得很详细了。
而且在你的app使用api之前,需要在baidu map开发者官网上申请一个密钥,绑定你的应用,否则服务器不会理你。这些官方文档都有了,就不赘述了。
http://developer.baidu.com/map/index.php?title=android-locsdk/geosdk-android-download
在上面的sdk中,随便挑一个版本下载,我下的是最新的版本5.1
得到一个文件夹 BaiduLBS_AndroidSDK_Lib,目录结构如下所示:
这样剩下两个问题:
1. 怎么把下载下来的sdk里面的 jar文件和 so文件配置入 Android Studio
2. 怎么配置 Manifest
解决方法:
1. 把 jar 文件放到Project structure的 libs目录下:
右键这个jar文件,把它加到库里面去 (add as libraries)
然后,在libs下创建一个子目录:armeabi,把so文件放进这个子目录中
2. AndroidManifest.xml的配置,官方文档的demo里面就有。但如果你懒得下,那就往下看,变化的不多。
在manifest中,添加子元素:
<uses-permission android:name="android.permission.BAIDU_LOCATION_SERVICE"></uses-permission>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"></uses-permission>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"></uses-permission>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"></uses-permission>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"></uses-permission>
<uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"></uses-permission>
<uses-permission android:name="android.permission.READ_LOGS"></uses-permission>
在application中,添加子元素:
<service
android:name="com.baidu.location.f"
android:enabled="true"
android:process=":remote" >
<intent-filter>
<action android:name="com.baidu.location.service_v2.2" >
</action>
</intent-filter>
</service>
<!-- meta-data需要写在application中 -->
<meta-data
android:name="com.baidu.lbsapi.API_KEY"
android:value="请输入申请的key" />
是不是感觉配置文件有一点奇怪? But it worked.
现在,你就可以正常地使用api编写代码了.
这里,给出我的一个简单的例子,它的功能是每点击一次按钮,获取当前的经纬度.
xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MyActivity"
>
<TextView
android:id="@+id/show_position"
android:text="@string/hello_world"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_horizontal"
>
<Button
android:id="@+id/control_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="get pos per click"
android:layout_marginLeft="100dp"
/>
</LinearLayout>
</LinearLayout>
Java:
package com.example.user.testmap;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.baidu.location.BDLocation;
import com.baidu.location.BDLocationListener;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
public class MyActivity extends Activity {
public TextView show_position;
public Button getPositionOnce;
private LocationClient mLocationClient;
private LocationClientOption mOption;
public double Latitude, Longitude;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
show_position = (TextView) findViewById(R.id.show_position);
getPositionOnce = (Button) findViewById(R.id.control_button);
mLocationClient = new LocationClient(this);
mOption = new LocationClientOption();
/* 设置选项 */
mOption.setOpenGps(true);
mOption.setCoorType("bd09ll");
mOption.setScanSpan(100); //每隔0.1s, 扫描一次 (应该就是卫星定位的意思)
/* 本地取址Client 端设置 Option选项 */
mLocationClient.setLocOption(mOption);
/* 设置监听器,监听服务器发送过来的地址信息 */
mLocationClient.registerLocationListener(new BDLocationListener() {
@Override
public void onReceiveLocation(BDLocation bdLocation) {
if(bdLocation == null)
return;
StringBuffer sb = new StringBuffer(256);
/* 获取经纬度 */
Latitude = bdLocation.getLatitude();
Longitude = bdLocation.getLongitude();
sb.append("latitude: "+Latitude+"\n");
sb.append("longitude: "+Longitude);
show_position.setText(sb.toString());
mLocationClient.stop();
}
});
getPositionOnce.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(mLocationClient == null)
return;
mLocationClient.start();
}
});
}
@Override
public void onDestroy() {
if(mLocationClient != null && mLocationClient.isStarted()) {
mLocationClient.stop();
mLocationClient=null;
}
super.onDestroy();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.my, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
以上是关于Android Studio+百度地图API实现简单gis移动端App的主要内容,如果未能解决你的问题,请参考以下文章
详细教程论android studio中如何申请百度地图新版Key中SHA1值