安卓不使用第三方SDK怎么开发街景地图
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了安卓不使用第三方SDK怎么开发街景地图相关的知识,希望对你有一定的参考价值。
百度地图 android SDK是一套基于Android 2.1(v1.3.5及以前版本支持android 1.5以上系统)及以上版本设备的应用程序接口可以使用该套 SDK开发适用于Android系统移动设备的地图应用,通过调用地图SDK接口,您可以轻松访问百度地图服务和数据,构建功能丰富、交互性强的 LBS(地图类)应用程序。
百度地图Android SDK提供的所有服务是免费的,接口使用无次数限制。您需申请密钥(key)后,才可使用百度地图Android SDK。任何非营利性产品请直接使用。这弦外之音就是盈利的产品必须帮百度给钱。
一、百度地图api平台。
百度地图API网址:http://developer.baidu.com/map/sdk-android.htm
百度地图开发步骤是
①获取密钥
②申请新密钥及查看原先申请的密钥
③开发指南 在安卓平台上使用百度地图的开发指南
④类参考 地图库所提供的类及方法说明相关下载
⑤开发所使用的相关包及说明示例下例
哝,这就是百度地图的apk平台的界面:
首先,我们来申请key。
步骤也非常的简单:
①点击获取密钥 ②进入密钥申请页并阅读相关的使用条款 ③勾选 已阅读并同意条款 ④填写应用名称 填写一下应用的相应功能及描述 ⑤输入验证码确定后 ⑥密钥即可申请成功
我申请的key如下图所示:
如何把申请下来的jar包导入到项目中了。
一、在工程里新建libs文件夹(若不存在的话),将开发包里的baidumapapi_v2_1_1.jar 拷贝到libs根目录下,将libapp_BaiduMapApplib_v2_1_1.so和libvi_voslib.so 拷贝到libsarmeabi目录下。
二、项目属性中Java Build Path->Order and Export中,确定Android Private Libaries与Android Dependencies这两项前面的选择框被选上后,
三、点确定 菜单Project->clean重新编译项目后就可以正常使用地图中的功能进行编程了。
四、上图包中的liblockSDK3.1.jar及对应的so文件是用于定位与搜索功能的,如果不需要可以不 加入到项目当中
jar包的架构如下图所示:
到入jar包的样子也如下图所示:
在清单文件下,要添加一下的权限。
<supports-screens android:anyDensity="true" android:largeScreens="true" android:normalScreens="true" android:resizeable="true" android:smallScreens="true" />
对需要加载地图的Activity进行属性设置
<activity android:name="com.dfrz.map.DFRZMapActivity" android:configChanges="orientation|keyboardHidden|screenSize" android:label="@string/app_name" android:screenOrientation="sensor" > </activity>
这些准备工作做好以后,我们需要到入相应的map控件
<com.baidu.mapapi.map.MapView android:id="@+id/bmapsView" android:layout_ android:layout_ android:layout_weight="1" android:clickable="true" />
上述xml的源代码就是这个就是加载百度地图的控件框,这个布局你可以根据自己的需要进行调整,或是放置到你的Activity需要的地方去。此控 件需要接收到点击事件,所以需要把clickable设置成true。
百度的地图的原理就是这样的。。。。。。。。。。。
地图、定位、搜索功能都需要用BMapManager对象来管理, BMapManager提供四个接口:init()、start()、stop()、destroy()。在应用程序里生成BMapManager 对象并初始化,在程序退出时调用destroy(),在需要使用sdk功能的Activity的onCreate()方法里调用start()方 法,onDestroy()方法里调用stop()方法,或者onResume()/onPause()分别调用start()和stop()。 常用方法: destroy() : 在程序退出前调用 boolean init(java.lang.String strKey, MKGeneralListener listener) 初始化地图引擎,需要送入申请的百度地图Key boolean start() :开启百度地图API boolean stop(): 终止百度地图API,调用此函数后,不会再发生回调。
MapView——百度地图的显示者。
一个显示地图的视图控件,当被焦点选中时,它能捕获按键事件和触摸手势去平移和缩放地图 setBuiltInZoomControls(boolean on):设置是否启用内置的缩放控件 getController():返回地图的MapController,这个对象可用于控制和驱动平移和缩放 setDoubleClickZooming(boolean bDoubleClickZooming) : 设置mapview是否支持双击放大效果 getOverlays():获取当时地图控件中的已有图层 refresh(): 刷新此地图控件。
怎么用百度地图实现了定位了,这就需要LocationClient
定位处理功能的核心类 registerLocationListener(BDLocationListener)接收到定位数据后可由指定监听器中的 onReceiveLocation(BDLocation)的方法来接收相关的数据并做相关的处理 构造: new LocationClient(getApplicationContext()) setLocOption(LocationClientOption)设置定位的参数 start()启动定位功能,此功能是持续的,可以定义间隔刷新时间 stop()结束定位功能,但前面设置的定位参数不会消失,可以再启动 requestLocation() 发起异步定位请求,如果位置没有变化,不会发起网络请求,直接返回上次的位置。(2次间隔需要大于1秒)
LocationClientOption 用于定位的操作的类。
设置定位功能的定位方式 disableCache(boolean) 真表示禁用缓存定位 setOpenGPS(boolean) 是否使用GPS定位,前提是手机打开了GPS定位 setAddrType(String) 当字串为"all"时返回此位置地址信息,其它不返回 setCoorType(String) 设置返回坐标的格式 gcj02 - 国测局 bd09百度墨卡托 bd0911百度经纬坐标(手机默认) setScanSpan(int) 定时定位的时间间隔(ms) 此值大于1000时,每隔此值指定的时间就会发起一次定位 此值小于1000时或不设置此值时,调用一次requestLocation()方法则定位一次
这是我们需要定义mainactivity的类。相应源代码如图所示:
protected void onDestroy() mapView.destroy(); if (mapManager != null) mapManager.destroy(); mapManager = null; super.onDestroy();
有了这些准备以后,相应运行的效果如下:
这就是android下百度地图应用的大概步骤。追问
不使用第三放SDK
参考技术A 有轮子,何必自己造轮子! 参考技术B 666,研发地图啊你 参考技术C 先融资个几个亿 参考技术D 街景的估计不可以,高德新出的h5的,可以去官网看看,接入app很简单仿百度地图街景实现
使用过百度地图的同学知道,它有个街景功能,可以看到许多地方的实景。这里就其街景内容的实现,进行下学习。
在百度地图SDK的官网上可以看到,百度对开发者提供了很多相关的内容,方便我们进行学习。关于SDK的使用方法,包括jar包导入,*.so 动态库的添加位置及AndroidManifest文件的配置不做为我们这里讨论的内容,官方文档已经介绍的很详细,不做无聊的搬运工。
效果图
这里我们首先预览下,今天最终要实现的效果图
如图所示,我们这里的实现,就是两个页面的内容,一个是基础的地图MapView,一个是街景地图PanoView。接下来,就这两个页面(Activity)分别展开来说。(由于GIF图片大小限制,效果不是很理想,文章结尾有源码地址,可以自己跑一下看一下效果先)
地图MapView实现
地图MapView的简单显示
布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.baidu.mapapi.map.MapView
android:id="@+id/bmapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true" />
</LinearLayout>
Application
一般情况下,我们的应用程序都会有一个继承自Application的类,用于实现一些初始化的方法,这里可以在Application里执行一些百度地图初始化的工作,这也是官方提倡的方式。
public void onCreate() {
super.onCreate();
mInstance = this; SDKInitializer.initialize(getApplicationContext());
}
Activity
在Activity的OnCreate方法中实现
setContentView(R.layout.activity_mapview);
mMapView = (MapView) findViewById(R.id.bmapView);
上面这样一段简单的代码,就可以在Activity中显示出一个MapView,也就是我们最熟悉的地图页面,是不是很简单,就像我们显示一个TextView一样。
这里说明写一下,按照官方的API指导文档,使用MapView等百度地图SDK所提供的各种实现,是需要去申请相关的key的,申请的方法在官网有着详细的介绍,这里就不再粘贴复制了;很多同学在使用MapView的时候发现,程序运行后地图没有显示,显示的都是一些方格子,这往往是由于key没有申请,或申请的方式不当造成的
MapView显示到当前位置
每次打开百度地图,都会自动定位到我们当前所在的位置,或者是我们搜索某个特定的地方作为新的位置,整个地图所呈现的区域都是新位置周边的环境。这里,关于地图的定位和搜索的相关实现内容,就不展开来说,不当做此次的重点。
假设我们已通过定位(或者是搜索),定位了到了一个位置
**
* 假设我们当前的位置在此
*/
private final double latitude = 39.963175;
private final double longitude = 116.400244;
这个位置按照新闻里常听到的说法就是,东经116.40度,北纬39.96度,位于北京市东城区旧鼓楼大街丙1号。
接下来,我们要做的就是将MapView的视图更新到我们“定位”的位置,这个位置周边的地图才是我们关心的。
mBaiduMap = mMapView.getMap();
//定义Maker坐标点
point = new LatLng(latitude, longitude);
//定义地图状态
final MapStatus mMapStatus = new MapStatus.Builder()
.target(point)
.zoom(18)
.build();
//定义MapStatusUpdate对象,以便描述地图状态将要发生的变化
MapStatusUpdate mMapStatusUpdate = MapStatusUpdateFactory.newMapStatus(mMapStatus);
//改变地图状态
mBaiduMap.setMapStatus(mMapStatusUpdate);
这里的mBaiduMap 是一个BaiduMap的实例,通过MapView的getMap方法即可获得。我们对地图的各种操作,设置属性都是基于这个实例进行。
通过上面的代码,我们就可以将MapView的视图更新到我们所想要的位置了。
添加View到MapView
添加Marker
按照百度地图API的说法,我们添加到地图上的小图标统一称为Marker。
//构建Marker图标
bitmap = BitmapDescriptorFactory
.fromResource(R.drawable.icon_markc);
//构建MarkerOption,用于在地图上添加Marker
option = new MarkerOptions()
.position(point)
.icon(bitmap);
//在地图上添加Marker,并显示
mBaiduMap.addOverlay(option);
通过上面的实现,我们就可以将一个小图标添加到地图层,作为标记。我们日常使用地图时,所搜周边后呈现的一系列小圆点就是如此(如下图)
ShowInfoWindow使用
最后一步,实现显示街景缩略图的那个小弹框。
这里首先自定义一下我们要添加到地图层的View。
view = LayoutInflater.from(mContext).inflate(R.layout.pano_overlay, null);
pic = (ImageView) view.findViewById(R.id.panoImageView);
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(mContext, PanoDemoMain.class);
intent.putExtra("latitude", latitude);
intent.putExtra("longitude", longitude);
startActivity(intent);
}
});
这里pic这个ImageView用于显示我们要展示的街景缩略图。pano_overlay是整个弹框的布局,很简单,这里就不贴代码了。
同时,我们为这个自定义View设置点击事件,方便我们跳转到PanoView街景地图页面,并且将当前位置传递过去。
由于祖国地大物博,所以街景的覆盖并非百分之百,所以说,不是每个地方都有街景可以显示,有些鸟不拉屎的地方是看不到的。那我们怎么知道什么地方有街景呢?API为我们提供了很好的检测方法
new Thread(new Runnable() {
@Override
public void run() {
PanoramaRequest request = PanoramaRequest.getInstance(mContext);
BaiduPanoData locationPanoData = request.getPanoramaInfoByLatLon(longitude, latitude);
//开发者可以判断是否有外景(街景)
if (locationPanoData.hasStreetPano()) {
String url = baseUrl + locationPanoData.getPid();
Message message = new Message();
message.what = 0x01;
message.obj = url;
handler.sendMessage(message);
}
}
}).start();
这样,我们就可以根据当前位置,先检测一下是否有街景可以显示。这里,如果当前位置有街景,我们就通过Handler通知主线程去更新UI
private class myHandler extends Handler {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == 0x01) {
String url = (String) msg.obj;
Glide.with(mContext).load(url).into(pic);
InfoWindow mInfoWindow = new InfoWindow(view, point, -57);
//显示InfoWindow
mBaiduMap.showInfoWindow(mInfoWindow);
}
}
}
这里看一下,InfoWindow的说明及其构造函数
public class InfoWindow extends java.lang.Object
在地图中显示一个信息窗口,可以设置一个View作为该窗口的内容,也可以设置一个 BitmapDescriptor 作为该窗口的内容。
public InfoWindow(View view, LatLng position, int yOffset)
/**
通过传入的 view 构造一个 InfoWindow, 此时只是利用该view
生成一个Bitmap绘制在地图中,监听事件由开发者实现。
Parameters:
view - InfoWindow 展示的 view
position - InfoWindow 显示的地理位置
yOffset - InfoWindow Y 轴偏移量
*/
在Handler的handleMessage方法中,我们通过返回的url加载图片,并将自定义的弹框View显示到之前一步添加的marker偏上一点的地方(这就是InfoWindow的构造函数中-57的意义)
关于这个加载图片的URL,可以参考这里静态图API。
这样,就实现了MapView页面所有的内容。通过点击InfoWindow,就可以跳转到PanoView所在的界面去查看街景地图。
接下来,我们将介绍PanoView街景地图的实现。
街景地图PanoViewActivity实现
街景地图PanoView基础
街景地图PanoView的显示和基础地图MapView十分相似
首先是在布局文件中定义view
<com.baidu.lbsapi.panoramaview.PanoramaView
android:id="@+id/panorama"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
android:visibility="visible" />
在Activity的OnCreate方法中
PanoDemoApplication app = (PanoDemoApplication) this.getApplication();
if (app.mBMapManager == null) {
app.mBMapManager = new BMapManager(app);
app.mBMapManager.init(new PanoDemoApplication.MyGeneralListener());
}
mPanoView = (PanoramaView) findViewById(R.id.panorama);
mPanoView.setPanorama(longitude, latitude);
这里同样需要的是在Application类中做一些初始化工作;对我们所使用key的有效性进行检测。
public void initEngineManager(Context context) {
if (mBMapManager == null) {
mBMapManager = new BMapManager(context);
}
if (!mBMapManager.init(new MyGeneralListener())) {
Toast.makeText(PanoDemoApplication.getInstance().getApplicationContext(), "BMapManager 初始化错误!",
Toast.LENGTH_LONG).show();
}
}
// 常用事件监听,用来处理通常的网络错误,授权验证错误等
static class MyGeneralListener implements MKGeneralListener {
@Override
public void onGetPermissionState(int iError) {
// 非零值表示key验证未通过
if (iError != 0) {
// 授权Key错误:
Toast.makeText(PanoDemoApplication.getInstance().getApplicationContext(),
"请在AndoridManifest.xml中输入正确的授权Key,并检查您的网络连接是否正常!error: " + iError, Toast.LENGTH_LONG).show();
} else {
Toast.makeText(PanoDemoApplication.getInstance().getApplicationContext(), "key认证成功", Toast.LENGTH_LONG)
.show();
}
}
}
同时在Activity里也需要做一些初始化的工作,最后就是通过PanoView的setPanorama()方法实现街景的显示。
关于这里用到的setPanorama(),根据API我们可以看到
public void setPanorama(java.lang.String pid)
//根据全景pid值切换全景场景
public void setPanorama(int x,int y)
//根据百度墨卡托投影坐标切换全景场景
public void setPanorama(double longitude,double latitude)
//根据百度经纬度坐标切换全景场景
public void setPanoramaByUid(java.lang.String uid,
int panoType)
//根据uid值切换全景场景
也就是说,不仅通过经纬度,而且可以通过别的方式实现街景地图的功能。这里我们就使用了大家最熟悉的经纬度,对于别的实现方式有兴趣的同学,可以自己去探索一下。
将地图MapView展示在街景PanoView上面
如图所示,将一个MapView显示在PanoView之上;很自然的我们会写出下面的布局方式:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.baidu.lbsapi.panoramaview.PanoramaView
android:id="@+id/panorama"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
android:visibility="visible" />
<LinearLayout
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:background="#00ffffff">
<com.baidu.mapapi.map.MapView
android:id="@+id/bmapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
android:padding="20dp" />
</LinearLayout>
</RelativeLayout>
这样,我们在整个PanoView的左下角定义一个60x60大小的view用于显示一个MapView。
实现对街景视图操作的监听
街景SDK为我们提供了PanoramaViewListener这个接口,可以实现对从街景视图开始绘制到完成绘制,对街景地图的操作(如点击,旋转)的监听。
这里我们重点看一下onMessage(String msgName, int msgType)这个回调方法。
public void onMessage(String msgName, int msgType) {
Log.e(LTAG, "msgName--->" + msgName + ", msgType--->" + msgType);
switch (msgType) {
case 8213:
//旋转
Log.e(PanoViewActivity.class.getSimpleName(), "now,the heading is " + mPanoView.getPanoramaHeading());
Message message = new Message();
message.what = ACTION_DRAG;
message.arg1 = (int) mPanoView.getPanoramaHeading();
handler.sendMessage(message);
break;
case 12302:
//点击
Log.e(PanoViewActivity.class.getSimpleName(), "clicked");
Message msg = new Message();
msg.what = ACTION_CLICK;
handler.sendMessage(msg);
break;
default:
break;
}
}
这里不得不吐槽一下,官方所提供的API文档,对这个onMessage回调方法中的参数居然没有任何有价值的解释。这里的8213及12302完全是通过打印日志自己总结出的规律。
这样,我们对于不同的操作,就可以通过Handler实现不同的UI效果。我们看一下handler的实现:
private class MyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case ACTION_CLICK:
if (titleVisible) {
titleVisible = false;
textTitle.startAnimation(animationHide);
textTitle.setVisibility(View.GONE);
sv.setVisibility(View.GONE);
} else {
titleVisible = true;
textTitle.startAnimation(animationShow);
textTitle.setVisibility(View.VISIBLE);
sv.setVisibility(View.VISIBLE);
}
break;
case ACTION_DRAG:
float heading = (float) msg.arg1;
mBaiduMap.clear();
//构建MarkerOption,用于在地图上添加Marker
option = new MarkerOptions()
.position(point)
.rotate(360-heading)
.icon(bitmap);
//在地图上添加Marker,并显示
mBaiduMap.addOverlay(option);
break;
default:
break;
}
}
}
这里的处理就分两种情况:
- 点击事件
我们仿照百度地图的样式,实现标题栏及MapView的隐藏,并添加动画,这样可以方便用户全屏更清晰的观察街景内容。
- 旋转事件
上面我们说过对MapView添加Marker的方法,这里就派上用场了。随着我们对PanoView的不断拖拽旋转,通过其getPanoramaHeading() 可以得到当前视角的偏航角。
在UI线程中,我们可以通过不断移除和添加Marker,并设置不同的marker的偏转角度,从而实现一种在左下方小地图上呈现我们当前视角的效果。
好了,这样就简单模仿了一下百度地图街景的部分实现功能,由于UI资源所限制,部分效果并非完全一致,这里只是学习下而已。
代码已上传至github,点这里即可查看。
以上是关于安卓不使用第三方SDK怎么开发街景地图的主要内容,如果未能解决你的问题,请参考以下文章