读书笔记——基于位置的服务(LBS)

    • 简介
    • 获取自己的位置LocationManager
      • LocationManager 的基本用法
      • 实例
    • 反向地理编码看懂位置信息经纬度到具体位置
      • 直接使用Geocoding API

        • 实例
      • 使用百度地图
        • 实践
        • 使用覆盖物来增加更多功能
          • 常用覆盖物MyLocationOverlay标记当前位置选定经纬度
          • PopupOverlay

简介

1、工作原理

利用无线电通讯网络或 GPS 等定位方式来确定出移动设备所在的位置

获取自己的位置——LocationManager

LocationManager 的基本用法

1、获取LocationManager

LocationManager 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 对象,第三个参数是覆盖物在垂直方法上的偏移距离。

时间: 2024-10-18 13:18:21

读书笔记——基于位置的服务(LBS)的相关文章

一张图让你了解LBS基于位置的服务

LBS--基于位置的服务.LBS作为移动互联网时代的基础服务,已成为人们日常生活中不可或缺的部分.据统计将近80%的应用与LBS有关,LBS已经成为移动互联网应用的标配功能.作为一个LBS应用开发者,你了解大家都在用什么平台吗?哪些功能是同道中人最看重的?又该如何选择LBS开放平台呢? 您可能还会对这些文章感兴趣! 怎样安排时间读书 张图让你知道如何提升网站的第一眼印象 一张图看懂财务报表分析 一图读懂马云余额宝的商业玩法 一组图让你看懂阿里巴巴 一张图看懂微博与Twitter到底有何不同! 一

Android学习之基础知识十四 — Android特色开发之基于位置的服务

一.基于位置的服务简介 LBS:基于位置的服务.随着移动互联网的兴起,这个技术在最近的几年里十分火爆.其实它本身并不是什么时髦的技术,主要的工作原理就是利用无线电通讯网络或GPS等定位方式来确定出移动设备所在的位置,而这种技术早在很多年前就已经出现了. 那么为什么LBS技术直到最近几年才开始流行呢?这主要是因为,在过去移动设备的功能及其有限,即使定位到了设备所在的位置,也就仅仅只是定位到了而已,我们并不能在位置的基础上进行一些其他的操作.而现在就大大不同了,有了Android系统作为载体,我们可

读书笔记-基于IP的物联网架构技术与应用

最近在看<基于IP的物联网架构,技术与应用>这边书,将自己的读书笔记,记录于此. 一.什么是智能物件? 定义:智能物件是装备了传感器,微处理器,通信装置和电源的设备. 重要属性:与现实世界的交互 和 通信能力 面临挑战: 节点级挑战:能耗.体积大小.成本.资源限制,电源效率,计算能力 网络级挑战:规模大数据量多,网络大小影响(smart object networks)的路由协议设计.路由可以集中生成,即由一个中央服务器为整个网络计算路由图,也可以是分布式的,即每个节点独立决定每条消息发送到哪

Android特色——基于位置的服务

一 使用百度地图 1.申请api key 在申请百度地图api key时,需要两个SHA1,一个是发布版的SHA1,一个是开发版SHA1.我们目前可以两个都填写开发版SHA1. 在as中右侧的属性栏中: 其中在run中就会显示出SHA1开发版指纹,如下: 2.配置相关文件 在下载文件解压后,主要分为两部分,一部分是文件夹中包含的.so文件,一部分是java的jar包. 配置中,将所有的jar包复制到目录中app/libs中.将所有的so文件直接复制到app/src/main中新建的一个jniLi

WCF服务编程 读书笔记——第2章 服务契约

操作重载诸如 C++ 和 C# 等编程语言都支持方法重载,即允许具有相同名称的两个方法可以定义不同的参数.例如,如下的 C# 接口就是有效的定义: interface ICalculator { int Add(int arg1,int arg2); double Add(double arg1,double arg2); } 然而,基于 WSDL 的操作却不支持操作重载.因此,在编译如下的契约定义时,装载服务宿主就会抛出 InvalidOperationException异常: // 无效的契

Android实战--基于位置的服务(获取自己位置的经纬度+百度地图)

需要借助LocationManager类实现,下面直接看代码: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="

题记 《推荐系统实践》读书笔记

<推荐系统实践>是一本入门级书籍,全书不到200页,通熟易懂,非常适合初学者.记不起上次阅读该书是什么时候,可以确定的是很定不超过三个月,今天回想梳理全书结构,甚是模糊,而是打算重读一遍.并在这里留下些许痕迹,以帮助日后回忆之用.对本笔记内容感兴趣的读者还请购买正版书籍,尊重作者权益! 作者介绍如下: 项亮,毕业于中国科学技术大学和中国科学院自动化所,研究方向为机器学习和推荐系统,现任职于北京Hulu软件技术开发有限公司,从事视频推荐的研究和开发.2009年参加Netflix Prize推荐系

《NoSQL精粹》读书笔记

NoSQL数据库数据模型的一般分类: 1. 键值数据模型 2. 文档数据模型 3. 列族数据模型 4. 图数据模型 常见NoSQL数据库: Redis, Cassandra, MongoDB, Neo4J, Riak... 数据库应用趋势: 1. 由于数据量越来越大,大型系统的扩展方式由数据库在单一计算机上的纵向扩展->在计算机集群中的横向扩展 2. 混合持久化(关系型数据库 + NoSQL数据库) 第一部分 第1章 为什么使用NoSQL * 关系型数据库和应用程序之间的“阻抗不匹配”.关系模型

Android 读书笔记

<Android开发艺术探索> 一.Activity 的生命周期和启动模式 1. 当前 Activity 为 A,此时打开 Activity B:A.onPause() → B.onCreate() → B.onStart() → B.onResume() → A.onStop(),故不能在 onPause 中做重量级操作,使新 Activity 尽快显示出来并切换到前台. 2. 当系统内存不足时,系统会按照 [ 后台 Activity → 可见但非前台 Activity → 前台 Activ