读书笔记——基于位置的服务(LBS)
2016-06-22 16:44
344 查看
简介
获取自己的位置LocationManager
LocationManager 的基本用法
实例
反向地理编码看懂位置信息经纬度到具体位置
直接使用Geocoding API
实例
使用百度地图
实践
使用覆盖物来增加更多功能
常用覆盖物MyLocationOverlay标记当前位置选定经纬度
PopupOverlay
利用无线电通讯网络或 GPS 等定位方式来确定出移动设备所在的位置
2、选择一个位置提供器来确定设备当前的位置——GPS_PROVIDER、NETWORK_PROVIDER 和 PASSIVE_PROVIDER
优缺点:前两种使用的比较多,分别表示使用 GPS 定位和使用网络定位。这两种定位方式各有特点,GPS 定位的精准度比较高,但是非常耗电,而网络定位的精准度稍差,但耗电量比较少。GPS在室内几乎挂~
定位功能必须要由用户主动去启用才行,不然任何应用程序都无法获取到手机当前的位置信息。(定位服务中的使用无线网络和使用GPS卫星。)
3、将选择好的位置提供器传入到getLastKnownLocation()方法中,得到Location对象。
这个 Location 对象中包含了经度、纬度、海拔等一系列的位置信息
4、如果想使用GPS位置提供器,确认GPS定位功能是都以及开启?先判断有哪些位置提供器可用。
getProviders()方法接收一个布尔型参数,传入 true 就表示只有启用的位置提供器才会被返回。之后再从 providerList 中判断是否包含 GPS 定位的功能就行了。
5、实时更新位置信息——requestLocationUpdates()
LocationManager 还提供了一个 requestLocationUpdates()方法,只要传入一个 LocationListener 的实例,并简单配置几个参数就可以实现更新位置信息的获取了。
第一个参数是位置提供器的类型,第二个参数是监听位置变化的时间间隔,以毫秒为单位,第三个参数是监听位置变化的距离间隔,以米为单位,第四个参数则是 LocationListener 监听器。这样的话,LocationManager 每隔5 秒钟会检测一下位置的变化情况,当移动距离超过 10 米的时候,就会调用 LocationListener的 onLocationChanged()方法,并把新的位置信息作为参数传入。
当程序关闭时,我们还需要调用 removeUpdates()方法来将位置监听器移除,以保证不会继续耗费手机的电量。
所需权限
优点:可以非常简单地完成正向和反向的地理编码功能,从而轻松地将一个经纬值转换成看得懂的位置信息。
缺点:GeoCoder 长期存在着一些较为严重的 bug,在反向地理编码的时候会有一定的概率不能解析出位置的信息,这样就无法保证位置解析的稳定性
2、新的一套 Geocoding API
用法稍微复杂了一些,但稳定性要比 GeoCoder 强得多。
工作原理:
在手机端我们可以向谷歌的服务器发起一条 HTTP 请求,并将经纬度的值作为参数一同传递过去,服务器帮我们将这个经纬值转换成看得懂的位置信息,再将这些信息返回给手机端,最后手机端去解析服务器返回的信息,并进行处理就可以了。
查看官网:https://developers.google.com/maps/documentation/geocoding/start。
得到的数据再用解析方式解析出来。
加上权限
1、申请 API Key
2、创建应用
填写安全码:数字签名+;+包名
数字签名指的是我们打包程序时所用 keystore 的 SHA1指纹,可以在 Eclipse 中查看到。点击 Eclipse 导航栏的 Window→Preferences→Android→Build,
注意,目前我们使用的是 debug.keystore 所生成的指纹,这是 Android 自动生成的一个用于测试的keystore。而当你的应用程序发布时还需要创建一个正式的 keystore,如果要得到它的指纹,就需要在 cmd 中输入如下命令:
keytool -list -v –keystore
(4)显示地图
代码分析:先需要创建一个 BMapManager 对象,然后调用它的 init()方法来进行初始化操作。init()方法接收两个参数,第一个参数就API Key , 第 二 个 参 数 传 入 null 即 可 。 注 意 初 始 化 操 作 一 定 要 在setContentView()方法前调用,不然的话就会出错。接下来我们获取到了 MapView 的实例,然后调用它的 setBuiltInZoomControls()方法并传入 true,表示启用内置的缩放控制功能。
另外还需要重写 onResume()、onPause()和 onDestroy()这三个方法,在这里对百度地图的 API 进行管理,以保证资源能够及时地得到释放。
(5)显示想要的位置而不是世界地图(比如自己所在位置)——MapController
(6)让地图定位到经纬度上——GeoPoint类
使用方式:GeoPoint 并没有什么太多的用法,主要就是用于存放经纬度值的,它的构造方法接收两个参数,第一个参数是纬度值,第二参数是经度值。但是需要注意, GeoPoint 是以微度为单位的,因此我们还要把经纬度的值乘以 10 的 6 次方再传给 GeoPoint。之后调用 MapController 的setCenter()方法,并把 GeoPoint 的实例传入就可以了
常用覆盖物MyLocationOverlay——标记当前位置(选定经纬度)
1、作用:
在地图中添加一个图层,以标注出设备当前的位置
2、用法:
首先是创建了一个 MyLocationOverlay 的实例,然后通过 LocationData对 象 指 定 了 当 前 的 经 纬 度 数 据 , 并 调 用 setData() 方 法 将 LocationData 存 放 到 了MyLocationOverlay 中。之后通过 MapView 的 getOverlays()方法可以得到一个用于管理覆盖物的集合,再调用 add()方法将 MyLocationOverlay 这个覆盖物添加到集合中。最后,还需要调用一下 MapView 的 refresh()方法使新增的覆盖物生效。
PopupOverlay
允许我们自己指定覆盖物上显示的图片,并且还可以响应图片的点击事件,每个 PopupOverlay 上最多可以显示三张图片。
showPopup()方法
接收三个参数,第一个参数就是前面创建的 Bitmap 数组,第二个参数是一个用于指定地理位置的 GeoPoint 对象,第三个参数是覆盖物在垂直方法上的偏移距离。
获取自己的位置LocationManager
LocationManager 的基本用法
实例
反向地理编码看懂位置信息经纬度到具体位置
直接使用Geocoding API
实例
使用百度地图
实践
使用覆盖物来增加更多功能
常用覆盖物MyLocationOverlay标记当前位置选定经纬度
PopupOverlay
简介
1、工作原理利用无线电通讯网络或 GPS 等定位方式来确定出移动设备所在的位置
获取自己的位置——LocationManager
LocationManager 的基本用法
1、获取LocationManagerLocationManager locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
2、选择一个位置提供器来确定设备当前的位置——GPS_PROVIDER、NETWORK_PROVIDER 和 PASSIVE_PROVIDER
优缺点:前两种使用的比较多,分别表示使用 GPS 定位和使用网络定位。这两种定位方式各有特点,GPS 定位的精准度比较高,但是非常耗电,而网络定位的精准度稍差,但耗电量比较少。GPS在室内几乎挂~
定位功能必须要由用户主动去启用才行,不然任何应用程序都无法获取到手机当前的位置信息。(定位服务中的使用无线网络和使用GPS卫星。)
3、将选择好的位置提供器传入到getLastKnownLocation()方法中,得到Location对象。
这个 Location 对象中包含了经度、纬度、海拔等一系列的位置信息
String provider = LocationManager.NETWORK_PROVIDER; Location location = locationManager.getLastKnownLocation(provider);
4、如果想使用GPS位置提供器,确认GPS定位功能是都以及开启?先判断有哪些位置提供器可用。
List<String> providerList = locationManager.getProviders(true);
getProviders()方法接收一个布尔型参数,传入 true 就表示只有启用的位置提供器才会被返回。之后再从 providerList 中判断是否包含 GPS 定位的功能就行了。
5、实时更新位置信息——requestLocationUpdates()
LocationManager 还提供了一个 requestLocationUpdates()方法,只要传入一个 LocationListener 的实例,并简单配置几个参数就可以实现更新位置信息的获取了。
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 5000, 10, new LocationListener() { @Override public void onStatusChanged(String provider, int status, Bundle extras) { } @Override public void onProviderEnabled(String provider) { } @Override public void onProviderDisabled(String provider) { } @Override public void onLocationChanged(Location location) { } });
第一个参数是位置提供器的类型,第二个参数是监听位置变化的时间间隔,以毫秒为单位,第三个参数是监听位置变化的距离间隔,以米为单位,第四个参数则是 LocationListener 监听器。这样的话,LocationManager 每隔5 秒钟会检测一下位置的变化情况,当移动距离超过 10 米的时候,就会调用 LocationListener的 onLocationChanged()方法,并把新的位置信息作为参数传入。
实例
public class MainActivity extends Activity { private TextView positionTextView; private LocationManager locationManager; private String provider; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); positionTextView = (TextView) findViewById(R.id.position_text_view); locationManager = (LocationManager) getSystemService(Context. LOCATION_SERVICE); // 获取所有可用的位置提供器 List<String> providerList = locationManager.getProviders(true); if (providerList.contains(LocationManager.GPS_PROVIDER)) { provider = LocationManager.GPS_PROVIDER; } else if (providerList.contains(LocationManager.NETWORK_PROVIDER)) { provider = LocationManager.NETWORK_PROVIDER; } else { // 当没有可用的位置提供器时,弹出Toast提示用户 Toast.makeText(this, "No location provider to use", Toast.LENGTH_SHORT).show(); return; } Location location = locationManager.getLastKnownLocation(provider); if (location != null) { // 显示当前设备的位置信息 showLocation(location); } locationManager.requestLocationUpdates(provider, 5000, 1, locationListener); } protected void onDestroy() { super.onDestroy(); if (locationManager != null) { // 关闭程序时将监听器移除 locationManager.removeUpdates(locationListener); } } LocationListener locationListener = new LocationListener() { @Override public void onStatusChanged(String provider, int status, Bundle extras) { } @Override public void onProviderEnabled(String provider) { } @Override public void onProviderDisabled(String provider) { } @Override public void onLocationChanged(Location location) { // 更新当前设备的位置信息 showLocation(location); } }; private void showLocation(Location location) { String currentPosition = "latitude is " + location.getLatitude() + "\n" + "longitude is " + location.getLongitude(); positionTextView.setText(currentPosition); } }
当程序关闭时,我们还需要调用 removeUpdates()方法来将位置监听器移除,以保证不会继续耗费手机的电量。
所需权限
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
反向地理编码,看懂位置信息(经纬度到具体位置)
直接使用Geocoding API
1、GeoCoder类优点:可以非常简单地完成正向和反向的地理编码功能,从而轻松地将一个经纬值转换成看得懂的位置信息。
缺点:GeoCoder 长期存在着一些较为严重的 bug,在反向地理编码的时候会有一定的概率不能解析出位置的信息,这样就无法保证位置解析的稳定性
2、新的一套 Geocoding API
用法稍微复杂了一些,但稳定性要比 GeoCoder 强得多。
工作原理:
在手机端我们可以向谷歌的服务器发起一条 HTTP 请求,并将经纬度的值作为参数一同传递过去,服务器帮我们将这个经纬值转换成看得懂的位置信息,再将这些信息返回给手机端,最后手机端去解析服务器返回的信息,并进行处理就可以了。
查看官网:https://developers.google.com/maps/documentation/geocoding/start。
得到的数据再用解析方式解析出来。
实例
public class MainActivity extends Activity { public static final int SHOW_LOCATION = 0; ...... private void showLocation(final Location location) { new Thread(new Runnable() { @Override public void run() { try { // 组装反向地理编码的接口地址 StringBuilder url = new StringBuilder(); url.append("http://maps.googleapis.com/maps/api/geocode/json?latlng="); url.append(location.getLatitude()).append(",") url.append(location.getLongitude()); url.append("&sensor=false"); HttpClient httpClient = new DefaultHttpClient(); HttpGet httpGet = new HttpGet(url.toString()); // 在请求消息头中指定语言,保证服务器会返回中文数据 httpGet.addHeader("Accept-Language", "zh-CN"); HttpResponse httpResponse = httpClient.execute(httpGet); if (httpResponse.getStatusLine().getStatusCode() == 200) { HttpEntity entity = httpResponse.getEntity(); String response = EntityUtils.toString(entity, "utf-8"); JSONObject jsonObject = new JSONObject(response); // 获取results节点下的位置信息 JSONArray resultArray = jsonObject.getJSONArray("results"); if (resultArray.length() > 0) { JSONObject subObject = resultArray. getJSONObject(0); // 取出格式化后的位置信息 String address = subObject.getString("formatted_address"); Message message = new Message(); message.what = SHOW_LOCATION; message.obj = address; handler.sendMessage(message); } } } catch (Exception e) { e.printStackTrace(); } } }).start(); } private Handler handler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case SHOW_LOCATION: String currentPosition = (String) msg.obj; positionTextView.setText(currentPosition); break; default: break; } } }; }
加上权限
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.INTERNET" />
使用百度地图
自己做过,毕竟谷歌的服务在中国支持还不是很给力,而且百度这个接口做的比较方便。1、申请 API Key
2、创建应用
填写安全码:数字签名+;+包名
数字签名指的是我们打包程序时所用 keystore 的 SHA1指纹,可以在 Eclipse 中查看到。点击 Eclipse 导航栏的 Window→Preferences→Android→Build,
注意,目前我们使用的是 debug.keystore 所生成的指纹,这是 Android 自动生成的一个用于测试的keystore。而当你的应用程序发布时还需要创建一个正式的 keystore,如果要得到它的指纹,就需要在 cmd 中输入如下命令:
keytool -list -v –keystore
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_SETTINGS" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" />
(4)显示地图
//百度SDK自定义控件,所以使用时候要加上类的全路径 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <com.baidu.mapapi.map.MapView android:id="@+id/map_view" android:layout_width="match_parent" android:layout_height="match_parent" android:clickable="true" /> </LinearLayout>
public class MainActivity extends Activity { private BMapManager manager; private MapView mapView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); manager = new BMapManager(this); manager.init("SHVPoTtIpzfonPD3HCkc5sIt", null); setContentView(R.layout.activity_main); mapView = (MapView) findViewById(R.id.map_view); mapView.setBuiltInZoomControls(true); } @Override protected void onResume() { mapView.onResume(); if (manager != null) { manager.start(); } super.onResume(); } @Override protected void onPause() { mapView.onPause(); if (manager != null) { manager.stop(); } super.onPause(); } @Override protected void onDestroy() { mapView.destroy(); if (manager != null) { manager.destroy(); manager = null; } super.onDestroy(); } }
代码分析:先需要创建一个 BMapManager 对象,然后调用它的 init()方法来进行初始化操作。init()方法接收两个参数,第一个参数就API Key , 第 二 个 参 数 传 入 null 即 可 。 注 意 初 始 化 操 作 一 定 要 在setContentView()方法前调用,不然的话就会出错。接下来我们获取到了 MapView 的实例,然后调用它的 setBuiltInZoomControls()方法并传入 true,表示启用内置的缩放控制功能。
另外还需要重写 onResume()、onPause()和 onDestroy()这三个方法,在这里对百度地图的 API 进行管理,以保证资源能够及时地得到释放。
(5)显示想要的位置而不是世界地图(比如自己所在位置)——MapController
//用 MapView的 getController()方法就能获取到 MapController 的实例。 //MapController地图的总控制器 MapController controller = mapView.getController(); //设置地图的缩放级别就可以这样写,取指范围3~19.级别越高,地图显示的信息越精细。 controller.setZoom(12);
(6)让地图定位到经纬度上——GeoPoint类
使用方式:GeoPoint 并没有什么太多的用法,主要就是用于存放经纬度值的,它的构造方法接收两个参数,第一个参数是纬度值,第二参数是经度值。但是需要注意, GeoPoint 是以微度为单位的,因此我们还要把经纬度的值乘以 10 的 6 次方再传给 GeoPoint。之后调用 MapController 的setCenter()方法,并把 GeoPoint 的实例传入就可以了
//将地图定位到北纬 39.915 度、东经 116.404 度这个位置 GeoPoint point = new GeoPoint((int) (39.915 * 1E6), (int) (116.404 * 1E6)); mMapController.setCenter(point);
实践
public class MainActivity extends Activity { ...... private LocationManager locationManager; private String provider; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); manager = new BMapManager(this); manager.init("SHVPoTtIpzfonPD3HCkc5sIt", null); setContentView(R.layout.activity_main); mapView = (MapView) findViewById(R.id.map_view); mapView.setBuiltInZoomControls(true); locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); // 获取所有可用的位置提供器 List<String> providerList = locationManager.getProviders(true); if (providerList.contains(LocationManager.GPS_PROVIDER)) { provider = LocationManager.GPS_PROVIDER; } else if (providerList.contains(LocationManager.NETWORK_PROVIDER)) { provider = LocationManager.NETWORK_PROVIDER; } else { // 当没有可用的位置提供器时,弹出Toast提示用户 Toast.makeText(this, "No location provider to use", Toast.LENGTH_SHORT).show(); return; } Location location = locationManager.getLastKnownLocation(provider); if (location != null) { navigateTo(location); } } private void navigateTo(Location location) { MapController controller = mapView.getController(); controller.setZoom(16); // 设置缩放级别 GeoPoint point = new GeoPoint((int) (location.getLatitude() * 1E6), (int) (location.getLongitude() * 1E6)); controller.setCenter(point); // 设置地图中心点 } ...... }
使用覆盖物来增加更多功能
所有叠加或覆盖到地图上的内容都被统称为地图覆盖物,如标注、矢量图形元素、定位图标等。覆盖物拥有自己的地理坐标,当我们拖动或缩放地图时,它们会自动进行相应地移动。常用覆盖物MyLocationOverlay——标记当前位置(选定经纬度)
1、作用:
在地图中添加一个图层,以标注出设备当前的位置
2、用法:
MyLocationOverlay myLocationOverlay = new MyLocationOverlay(mapView); LocationData locationData = new LocationData(); // 指定我的位置 locationData.latitude = location.getLatitude(); locationData.longitude = location.getLongitude(); myLocationOverlay.setData(locationData); mapView.getOverlays().add(myLocationOverlay); mapView.refresh(); // 刷新使新增覆盖物生效
首先是创建了一个 MyLocationOverlay 的实例,然后通过 LocationData对 象 指 定 了 当 前 的 经 纬 度 数 据 , 并 调 用 setData() 方 法 将 LocationData 存 放 到 了MyLocationOverlay 中。之后通过 MapView 的 getOverlays()方法可以得到一个用于管理覆盖物的集合,再调用 add()方法将 MyLocationOverlay 这个覆盖物添加到集合中。最后,还需要调用一下 MapView 的 refresh()方法使新增的覆盖物生效。
PopupOverlay
允许我们自己指定覆盖物上显示的图片,并且还可以响应图片的点击事件,每个 PopupOverlay 上最多可以显示三张图片。
public class MainActivity extends Activity { ...... private void navigateTo(Location location) { MapController controller = mapView.getController(); // 设置缩放级别 controller.setZoom(16); GeoPoint point = new GeoPoint((int) (location.getLatitude() * 1E6), (int) (location.getLongitude() * 1E6)); // 设置地图中心点 controller.setCenter(point); ...... PopupOverlay pop = new PopupOverlay(mapView, new PopupClickListener() { @Override public void onClickedPopup(int index) { // 相应图片的点击事件 Toast.makeText(MainActivity.this, "You clicked button " + index, Toast.LENGTH_SHORT).show(); } }); // 创建一个长度为3的Bitmap数组 Bitmap[] bitmaps = new Bitmap[3]; try { // 将三张图片读取到内存中 bitmaps[0] = BitmapFactory.decodeResource(getResources(), R.drawable.left); bitmaps[1] = BitmapFactory.decodeResource(getResources(), R.drawable.middle); bitmaps[2] = BitmapFactory.decodeResource(getResources(), R.drawable.right); } catch (Exception e) { e.printStackTrace(); } pop.showPopup(bitmaps, point, 18); } ...... }
showPopup()方法
接收三个参数,第一个参数就是前面创建的 Bitmap 数组,第二个参数是一个用于指定地理位置的 GeoPoint 对象,第三个参数是覆盖物在垂直方法上的偏移距离。
相关文章推荐
- atexit()函数
- bootstrap - 表格(条纹、边框、压缩)
- 浅谈操作系统的四个特征
- 10-1-直接插入排序-内部排序-第10章-《数据结构》课本源码-严蔚敏吴伟民版
- Citrix XenServer 6.1特性介绍之存储和VDI在线迁移—-- 简介篇
- 深度学习之(八)决策树与迭代决策树(GBDT)
- 百度地图(一)
- CUDA计时差别
- [转+整理]关于linux静态库和动态库的分析
- 简单的邮箱开发1----Java
- C++之离港篇学习笔记之const
- 欢迎使用CSDN-markdown编辑器
- java.lang.UnsatisfiedLinkError: No implementation found for long com.baidu.platform.comjni.map.commo
- Citrix ICA协议简介及与RDP协议对比—-- 理论篇
- protobuf的Required,Optional,Repeated限定修饰符
- 链表建立,插入,删除,输出
- Android TextView格式化文本
- Android NDK开发Crash错误定位
- xenserver常见问题汇总
- SqlServer数据库全角转换成半角