2017-05-26 18:13:35 raykwok1150 阅读数 1370
  • Android 开发 第三方SDK 百度定位SDK

    百度地图Android定位SDK是为Android移动端应用提供的一套简单易用的LBS定位服务接口,专注于为广大开发者提供好的综合定位服务,通过使用百度定位SDK,开发者可以轻松为应用程序实现智能、、高效的定位功能。 主要内容包括简介 密钥申请 环境配置、定位SDK使用,获取当前位置信息 等知识

    4855 人正在学习 去看看 Frank Lee

最近有客户需要在Android添加谷歌框架,但是GSMcore经常弹出一个窗口,


无法使用位置信息

所有应用的设备位置信息均已关闭。万一您的设备丢失,您可能无法定位设备。


网上找了一些资料,说是要添加NetworkLocation.apk.
比如:
手机定位折腾记(1):安卓手机的网络定位与NetworkLocation.apk
【android】网络定位服务NetworkLocationProvider

于是,满世界的找NetworkLocation.apk,终于在github上觅到了它的身影
android_packages_apps_UnifiedNlp

将它push到板子的system/priv-app下以后GSM还是无法定位。
随后注意到一句话:

Make sure that no Google geolocation tool is installed (it is usually listed as Google Play Services in Apps)

好吧,看起来GSM自己有定位功能,把它加进去:

diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index ee626d6..2156b81 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -777,6 +777,7 @@
     <string-array name="config_locationProviderPackageNames" translatable="false">
         <!-- The standard AOSP fused location provider -->
                <item>com.google.android.location</item>
+               <item>com.google.android.gms</item>
         <item>com.android.location.fused</item>
     </string-array>

OK,搞定!

2016-01-21 09:28:49 qq979418391 阅读数 707
  • Android 开发 第三方SDK 百度定位SDK

    百度地图Android定位SDK是为Android移动端应用提供的一套简单易用的LBS定位服务接口,专注于为广大开发者提供好的综合定位服务,通过使用百度定位SDK,开发者可以轻松为应用程序实现智能、、高效的定位功能。 主要内容包括简介 密钥申请 环境配置、定位SDK使用,获取当前位置信息 等知识

    4855 人正在学习 去看看 Frank Lee

Android设备开启保护

简介-为什么要设备保护?

         随着Android手机越来越得到大众的欢迎以及Android的开源性,手机开发厂商为了提高手机体验尝试着各种定制化的服务,包括对每一个Android的硬件设备的改动。同时,为了降低成产成本、打造面向大众的低端机,部分硬件不支持的情况也会时有发生,如闪光灯(对普通手机用户来说,闪光灯并不是一件必需品)。

那么,针对以上的硬件设备问题,“我们该如何做出相应的处理来保证我们程序代码的健壮性”成了我们要关注的焦点问题。

Android设备有哪些?

        相机设备--摄像头

        闪光灯设备

        传感器设备

        定位设备--GPS/Network

        蓝牙设备

        Wifi设备

        振动器设备

怎么保护?

        下面我们将针对各个Android硬件设备,提出简单基础的开启保护。

相机设备--摄像头

        做过硬件设备开发的都知道,相机设备的开启不一定会成功,这里失败的因素有很多:

                1.系统没有检测到摄像头设备

                2.没有前置摄像头(类型不匹配)

        所以我们必须在使用相机之前做一下设备检测工作。对于相机,我们可以做那些设备检测呢?

        保护策略:

                1.判断是否存在摄像头

                我可以通过下面的函数判断前置和后置摄像头是否存在:

                         

       
               2.判断开启是否成功(camera是否为null

               执行camera.open()或者camera.open(int cameraId)函数,如果启动相机失败,camera会为null,所以我们需要对camera进行判断是否为null,然后进行后续的操作。

                       

               3.开启默认前置摄像头的方法

               另外,根据默认打开后置摄像头的camera.open()方法,我们提供一种默认打开前置摄像头的方法:

                          

 

 

 

闪光灯设备

        市场上,部分低端手机为了节约成本是不配置闪光灯的,如联想部分机型和vivo部分机型,所以我们在使用闪光灯时,同样需要进行相关的设备检测工作:

       保护策略:

               1.判断是否存在闪光灯

               存在两种方式:

                       方法一:hasSystemFeature();

                       

                       方法二:getSupportedFlashModes();

                       

 

 

传感器设备

        目前为止,Android5.0 API中传感器的种类已经达到25种,其中部分还没有得到支持,他们在不同API上,不同机型上的差异,决定着我们必须要进行设备保护。

               (1)传感器的个数在API上存在的差异如下:

                       

               (2)不同的手机厂商采用不同种类、不同数量的传感器,同样导致了传感器不支持的问题:

                       

 

               保护策略:

               1)判断是否存在此类传感器

               具体代码:

                        

               2)获取指定一个传感器的方法

               函数代码:

                       

 

 

定位设备--GPS/Network

        对于目前的手机市场,部分机型不支持GPS的问题屡见不鲜,作为开发者,不能盲目的使用GPS API,可能出现crash的状况。以下是我们需要注意的几点:

       保护策略:

               1)判断是否支持GPS定位、Network定位

               可以在使用定位前,通过LocationManager.isProviderEnabled(String Type) 判断手机是否支持该定位方式,避免出现异常: 

                        

               2)必须判断返回的Location对象是否为null

               用getLastKnownLocation()方法是取上一次得到的位置信息,不一定返回结果,所以必须对Location对象进行判空操作,以免空指针异常;应该用requestLocationUpdates请求最新的位置信息,然后在LocationListener中的onLocationChanged处理接收到的位置信息。

               判空操作:

                       

蓝牙设备

        蓝牙通讯是手机应用软件、游戏软件常用的硬件设备模块,使用它的过程也需要反复确认设备状态的:

       保护策略:

               (1)手机是否存在蓝牙设备

               (2)当前蓝牙设备是否已打开

               代码如下:

                       


WIFI设备

        WIFI与蓝牙比较相似,检测的方向也是一致的,wifi设备开启不成功的原因有:

               1.手机硬件不支持Wifi;

               2.由于厂商对部分机型的修改,在飞行模式下,执行开启wifi功能的API失效;

       保护策略:

               1)判断手机是否支持WIFI

               代码:

                       

               2)判断WIFI是否打开

               代码:

                       

 

振动器设备

        振动是手机app不可或缺的提醒服务之一,为了保证程序健壮性,我们也需要进行判空操作:

               1)检测系统是否支持振动

               代码:

                      

// 如果觉得不错,记得顶我哦! 顶我!顶我!顶我!



2013-12-26 13:50:30 hebeind100 阅读数 24
  • Android 开发 第三方SDK 百度定位SDK

    百度地图Android定位SDK是为Android移动端应用提供的一套简单易用的LBS定位服务接口,专注于为广大开发者提供好的综合定位服务,通过使用百度定位SDK,开发者可以轻松为应用程序实现智能、、高效的定位功能。 主要内容包括简介 密钥申请 环境配置、定位SDK使用,获取当前位置信息 等知识

    4855 人正在学习 去看看 Frank Lee

地理信息服务

1 Android的定位服务

通过获取移动设备上的GPS信息,基站信息,Wifi信息等与当前位置修改的信息,用来判断用户所处的具体位置,位置信息用经纬度表示。

    定位服务是地理位置服务的基础。Android提供了多种定位手段。

定位服务框架

Android的位置信息,是通过不同的位置信息源来提供的,表示位置信息源的对象派生自LocationProvider。通过硬件收集信息,转换成位置信息。

    Android的位置信息服务LocationProviderService,用来管理所有的位置信息源,并通过这些信息源向请求者提供当前的位置信息。位置信息服务运行在系统核心进程的独立线程中,在服务初始化时,根据配置信息实例化系统中预设的定位信息源对象。

    调用组件可以使用LocationManager获取当前的位置信息,LocationManager.getLastKnownLocation获取最近一次系统进行定位保存的信息。如果需要获取最新的位置信息,则要请求更新并监听当前位置信息的变化LOcationListener

    更新并监听当前位置信息的变化一般在Activity.onResume进行。注销监听在Activity.onPause进行。

    位置信息变更事件的注册需要调用LocationManager.requestLocationUpdates函数。

 

位置信息源

定位服务依托于多个不同的位置信息源,每个位置信息源对象都在独立的线程中运行。与位置服务通过Socket通信,并传递位置信息。

    最基本的位置信息源,是依托GPS信息来确定设备的位置。GSP的获取需要底层设备的支持,但受硬件约束和抗干扰差。因此Android提供了另一种定位服务。

    基于网络的定位服务。定位信息源对象会手机移动设备周边WIfi和基站信息,并通过网络发送至Google的定位服务。Google服务根据收集来的海量Wifi地址,基站地址和经纬度关系计算出当前的位置信息并返回用户。

 

定位的选择

选择位置信息源进行定位的依据是依照预设的标准,从众多定位信息源选择一个最好的提供定位。

利用LocationManager.getBestProvider得到name,再用LocationManager.getProvidename)得到LocationProvider

 

 

另一种方式是动态定位

2014-04-11 14:20:45 deng0zhaotai 阅读数 4093
  • Android 开发 第三方SDK 百度定位SDK

    百度地图Android定位SDK是为Android移动端应用提供的一套简单易用的LBS定位服务接口,专注于为广大开发者提供好的综合定位服务,通过使用百度定位SDK,开发者可以轻松为应用程序实现智能、、高效的定位功能。 主要内容包括简介 密钥申请 环境配置、定位SDK使用,获取当前位置信息 等知识

    4855 人正在学习 去看看 Frank Lee
现在很多app都会自动定位当前位置,比如团购网站、招聘网站、天气app等等。定位可以使用GPS、基站、Wi-Fi来完成定位,百度地图Android定位SDK是利用设备当前的GPS信息(GPS定位),基站信息(基站定位)和Wi-Fi信息(Wi-Fi定位)完成定位的。开发者在应用中成功集成百度定位SDK以后,既可以方便的通过定位SDK的接口向百度定位服务请求位置信息。

定位SDK会根据设备当前的实际情况(如是否开启GPS,是否连接网络,是否扫描到Wi-Fi信息等)生成定位依据,并根据开发者设置的实际定位策略(包括三种:高精度模式,低功耗模式,仅用设备模式)进行定位。

关于百度SDK更详细的定位原理可以参考百度的文档:http://developer.baidu.com/map/geosdk.htm

什么是LBS可以参考:http://baike.baidu.com/link?url=QyoQddAxcacf6YHoPhxNK8omWn3HxZyG3Hm5Wf1--36T5bT2lRoYBo7-JIpLRESoMgx8hZqeqbUyED0kHp6_3rwi2H7GAjyDoPhdu5mig5iyNbtPTNLvCCTlSXecyG-a

要使用百度定位SDK首先要注册成为开发者:http://developer.baidu.com/map/

下载定位SDK


申请密钥  按照http://developer.baidu.com/map/geosdk-android-key.htm上的说明去做就OK了


我得到的密钥是


前面的条件都具备了就是新建工程,导入SDK

目录结构


定位后的效果


程序配置文件AndroidManifest.xml定义权限和声明服务,这些都可以在百度的文档中找到

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.dzt.weather"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />

    <!-- 这个权限用于进行网络定位 -->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" >
    </uses-permission>
    <!-- 这个权限用于访问GPS定位 -->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" >
    </uses-permission>
    <!-- 用于访问wifi网络信息,wifi信息会用于进行网络定位 -->
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" >
    </uses-permission>
    <!-- 获取运营商信息,用于支持提供运营商信息相关的接口 -->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" >
    </uses-permission>
    <!-- 这个权限用于获取wifi的获取权限,wifi信息会用来进行网络定位 -->
    <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" />
    <!-- SD卡读取权限,用户写入离线定位数据 -->
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" >
    </uses-permission>
    <!-- 允许应用读取低级别的系统日志文件 -->
    <uses-permission android:name="android.permission.READ_LOGS" >
    </uses-permission>

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <service
            android:name="com.baidu.location.f"
            android:enabled="true"
            android:process=":remote" >
        </service>

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

        <activity
            android:name="com.dzt.weather.WeatherActivity"
            android:label="@string/app_name"
            android:screenOrientation="portrait" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
其中

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

的value是你申请的AK,可以在代码中设置也可以在清单文件中设置,代码设置如下

mLocationClient.setAccessKey("8mrnaFzKu3DoduLnWuB5Lt2w"); //V4.1

Activity中的代码

package com.dzt.weather;

import com.baidu.location.BDLocation;
import com.baidu.location.BDLocationListener;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

/**
 * 百度基站定位错误返回码
 */
// 61 : GPS定位结果
// 62 : 扫描整合定位依据失败。此时定位结果无效。
// 63 : 网络异常,没有成功向服务器发起请求。此时定位结果无效。
// 65 : 定位缓存的结果。
// 66 : 离线定位结果。通过requestOfflineLocaiton调用时对应的返回结果
// 67 : 离线定位失败。通过requestOfflineLocaiton调用时对应的返回结果
// 68 : 网络连接失败时,查找本地离线定位时对应的返回结果
// 161: 表示网络定位结果
// 162~167: 服务端定位失败
// 502:KEY参数错误
// 505:KEY不存在或者非法
// 601:KEY服务被开发者自己禁用
// 602: KEY Mcode不匹配,意思就是您的ak配置过程中安全码设置有问题,请确保: sha1正确,“;”分号是英文状态;且包名是您当前运行应用的包名
// 501-700:KEY验证失败

public class WeatherActivity extends Activity implements OnClickListener {

	private static final String TAG = "dzt";
	private TextView mText;
	private TextView mTextPoi;
	private LocationClient mLocationClient = null;
	private BDLocationListener myListener = new MyLocationListener();

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_weather);
		mLocationClient = new LocationClient(getApplicationContext()); // 声明LocationClient类
		// mLocationClient.setAccessKey("8mrnaFzKu3DoduLnWuB5Lt2w"); //V4.1
		// mLocationClient.setAK("8mrnaFzKu3DoduLnWuB5Lt2w"); //V4.0
		mLocationClient.registerLocationListener(myListener); // 注册监听函数
		setLocationOption();
		mLocationClient.start();// 开始定位
		initWidgets();
	}

	private void initWidgets() {
		mText = (TextView) findViewById(R.id.tv_text);
		mTextPoi = (TextView) findViewById(R.id.tv_text_poi);
		Button btn = (Button) findViewById(R.id.btn_request);
		btn.setOnClickListener(this);
		btn = (Button) findViewById(R.id.btn_request_poi);
		btn.setOnClickListener(this);
	}

	@Override
	protected void onDestroy() {
		// TODO Auto-generated method stub
		super.onDestroy();
		mLocationClient.stop();// 停止定位
	}

	/**
	 * 设置相关参数
	 */
	private void setLocationOption() {
		LocationClientOption option = new LocationClientOption();
		option.setOpenGps(true);
		option.setIsNeedAddress(true);// 返回的定位结果包含地址信息
		option.setAddrType("all");// 返回的定位结果包含地址信息
		option.setCoorType("bd09ll");// 返回的定位结果是百度经纬度,默认值gcj02
		option.setScanSpan(5000);// 设置发起定位请求的间隔时间为5000ms
		option.disableCache(true);// 禁止启用缓存定位
		option.setPoiNumber(5); // 最多返回POI个数
		option.setPoiDistance(1000); // poi查询距离
		option.setPoiExtraInfo(true); // 是否需要POI的电话和地址等详细信息
		mLocationClient.setLocOption(option);
	}

	public class MyLocationListener implements BDLocationListener {
		@Override
		public void onReceiveLocation(BDLocation location) {
			if (location == null)
				return;
			StringBuffer sb = new StringBuffer(256);
			sb.append("当前时间 : ");
			sb.append(location.getTime());
			sb.append("\n错误码 : ");
			sb.append(location.getLocType());
			sb.append("\n纬度 : ");
			sb.append(location.getLatitude());
			sb.append("\n经度 : ");
			sb.append(location.getLongitude());
			sb.append("\n半径 : ");
			sb.append(location.getRadius());
			if (location.getLocType() == BDLocation.TypeGpsLocation) {
				sb.append("\n速度 : ");
				sb.append(location.getSpeed());
				sb.append("\n卫星数 : ");
				sb.append(location.getSatelliteNumber());
			} else if (location.getLocType() == BDLocation.TypeNetWorkLocation) {
				sb.append("\n地址 : ");
				sb.append(location.getAddrStr());
			}
			mText.setText(sb.toString());
			Log.d(TAG, "onReceiveLocation " + sb.toString());
		}

		public void onReceivePoi(BDLocation poiLocation) {
			// 将在下个版本中去除poi功能
			if (poiLocation == null) {
				return;
			}
			StringBuffer sb = new StringBuffer(256);
			sb.append("Poi time : ");
			sb.append(poiLocation.getTime());
			sb.append("\nerror code : ");
			sb.append(poiLocation.getLocType());
			sb.append("\nlatitude : ");
			sb.append(poiLocation.getLatitude());
			sb.append("\nlontitude : ");
			sb.append(poiLocation.getLongitude());
			sb.append("\nradius : ");
			sb.append(poiLocation.getRadius());
			if (poiLocation.getLocType() == BDLocation.TypeNetWorkLocation) {
				sb.append("\naddr : ");
				sb.append(poiLocation.getAddrStr());
			}
			if (poiLocation.hasPoi()) {
				sb.append("\nPoi:");
				sb.append(poiLocation.getPoi());
			} else {
				sb.append("noPoi information");
			}
			mTextPoi.setText(sb.toString());
			Log.d(TAG, "onReceivePoi " + sb.toString());
		}
	}

	@Override
	public void onClick(View v) {
		// TODO Auto-generated method stub
		switch (v.getId()) {
		case R.id.btn_request:
			if (mLocationClient != null && mLocationClient.isStarted())
				mLocationClient.requestLocation();
			else
				Log.d(TAG, "locClient is null or not started");
			break;
		case R.id.btn_request_poi:
			// 请求POI数据
			if (mLocationClient != null && mLocationClient.isStarted())
				mLocationClient.requestPoi();
			break;
		default:
			break;
		}
	}
}
完整Demo http://download.csdn.net/detail/deng0zhaotai/7177379

需要说明的是我这里到的是V4.1版本,在V4.1版本中必须设置AK,要不会提示空指针异常,在V4.0中可以不设置AK都能定位,但还不清楚有没有其它隐患,V4.1在代码中设置AK的函数为setAccessKey,V4.0设置AK的函数为setAK

还有网页的文档一直没有调用mLocationClient.start();// 开始定位,如果没有调用是定不了位的,百度网页文档还有很多不准确的地方,在使用时一定要注意。

也可以单独获取省或市


sb.append("\n省份 : ");
sb.append(location.getProvince());
sb.append("\n城市 : ");
sb.append(location.getCity());
sb.append("\n区/县 : ");
sb.append(location.getDistrict());
sb.append("\n街道: ");
sb.append(location.getStreet());
sb.append("\n街道号码: ");
sb.append(location.getStreetNumber());
sb.append("\n地址 : ");
sb.append(location.getAddrStr());



2016-01-04 14:02:46 FearlessChen 阅读数 721
  • Android 开发 第三方SDK 百度定位SDK

    百度地图Android定位SDK是为Android移动端应用提供的一套简单易用的LBS定位服务接口,专注于为广大开发者提供好的综合定位服务,通过使用百度定位SDK,开发者可以轻松为应用程序实现智能、、高效的定位功能。 主要内容包括简介 密钥申请 环境配置、定位SDK使用,获取当前位置信息 等知识

    4855 人正在学习 去看看 Frank Lee

概述:

使用设备上的传感器可以为APP增加丰富的定位和运动能力, 从GPS或者网络定位到加速度计, 陀螺仪, 温度, 气压计等.

定位和地图:

注意, 这里介绍的是Android framework中android.location包中的定位API. Google Location Services API, 是Google Play提供的服务, 提供了更加强大高级的框架可以自动计算任务比如定位提供选择和电源管理. 定位服务也提供了新的功能, 比如framework API中不支持的activity识别. 使用framework API的开发者以及那些只是向APP中添加位置感知的开发者, 应该认真考虑使用Location Services API. 更多关于Location ServiceAPI的信息可以参考GoogleLocation Services for Android.

定位和基于地图的APP为移动设备提供了丰富的体验. 我们可以在APP内使用android.location包和Google Maps Android API创建这些功能, 下面的小节将会简单介绍如何使用这些功能.

定位服务(LocationServices):

Android通过android.location为APP访问定位服务. 定位框架的核心组件是LocationManager系统服务, 它提供API来确定底层设备的位置和方向(如果可用的话).

跟其它的系统服务一样, 我们不能直接实例化一个LocationManager. 而是通过getSystemService(Context.LOCATION_SERVICE)方法来从系统请求一个实例.该方法返回一个LocationManager实例的句柄. 一旦我们的APP拥有了一个LocationManager, 就可以做这三件事:

l  查询所有的最后已知的用户位置的LocationProvider的列表.

l  注册/注销从locationprovider定期更新用户当前位置(被标准或者名字指定).

l  为一个给定的intent注册/注销一个给定经纬度的邻近范围.

更多信息将在下面介绍.

GoogleMaps Android API:

通过GoogleMaps Android API, 我们可以为APP添加基于Google Maps数据的地图. 该API会自动处理对Google Maps服务器的访问, 数据下载, 地图显示和地图上的点击手势. 我们可以使用API来增加标记, 多边形和覆盖图, 并更改特定地图区域用户的视角.

Google Maps Android API中的关键类是MapView.一个MapView可以通过从Google Maps服务器获得的数据显示一个地图. 当MapView有一个焦点的时候, 它将会捕捉按键和点击手势来自动平移和扩展地图, 包括处理额外的地图片段的网络需求. 它还提供了所有用户控制地图用到的UI元素. 我们的APP还可以使用MapView类方法来控制地图编程并绘制一些重叠区.

Google Maps Android API不包括在Android平台中, 但是可以在任何GooglePlay Store中的APP上运行(Android 2.2及以上版本). 想要集成Google Maps到APP中, 我们需要安装Google Play服务库到Android SDK. 更多信息可以参考Google Playservice.

定位策略:

了解用户的位置可以让我们的APP更加聪明和人性化. 当开发一个可定位的APP的时候, 我们可以利用GPS和Android的Network Location Provider来获得用户的位置. 尽管GPS是最准确的, 但是它只能工作在户外, 而且非常费电, 也没有用户期待的那么快的反应速度. Android的Network Location Provider使用手机信号塔和WiFi信号定位, 可以在室内和户外获取到位置信息, 响应迅速, 而且也消耗更少的电量. 如果在APP中想要获取用户的位置, 我们可以合作使用GPS和Network Location Provider, 也可以只使用其中一个.

定位要面临的挑战:

从一个移动设备获取用户位置可以很复杂. 有几个原因导致读取位置可能包含错误和误差. 这些问题有:

1.      位置源众多: GPS, 通信塔ID, WiFi都可以提供用户位置的线索. 确定要用哪个源需要权衡多种因素, 比如精确度, 速度和电池效率.

2.      用户移动: 因为用户的坐标会变, 我们必须每隔一段时间就刷新用户的位置.

3.      变化的精确度: 每个源提供的精确度都可能不一致. 一个10秒钟之前从一个源取得的位置可能比最新的从其它源获取的位置(或者同一个源)更准确.

这些问题导致想要获取一个靠谱的用户位置变得很复杂. 该文档将会提供一些信息来帮助我们面对这些挑战. 它也提供了我们可以用来使APP变得更加流畅和精确的点子供我们参考.

请求位置更新:

在Android上获取用户位置信息的原理是回调方式. 想要获取用户位置需要使用LocationManager的requestLocationUpdates(), 并传给它一个LocationListener作为参数. 我们的LocationListener必须实现一些回调方法给LocationManager在用户位置发生变化或者服务状态发生变化的时候调用. 比如下面这段代码演示了如何定义一个LocationListener并请求更新位置信息:

// Acquire a reference to the system Location Manager
LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);

// Define alistener that responds to location updates
LocationListener locationListener = new LocationListener() {
    public void onLocationChanged(Location location) {
      // Called when a new location is found by the network location provider.
      makeUseOfNewLocation(location);
    }

    public void onStatusChanged(String provider, int status, Bundle extras) {}

    public void onProviderEnabled(String provider) {}

    public void onProviderDisabled(String provider) {}
  };

// Register thelistener with the Location Manager to receive location updates
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);

requestLocationUpdates()的第一个参数是要使用的locationprovider的类型(在这里使用的是Network Location Provider, 表示手机信号塔和WiFi). 我们可以用第二个和第三个参数来控制监听器接收更新的频率 – 第二个参数是两次提示的最小时间间隔, 第三个参数是两次提示的最小改变距离– 如果两个都被设置为0的话, 则表示用可用的最快频率. 最后一个参数是LocationListener, 用于接收回调方法.

想要通过GPS Provider请求位置更新, 需要使用GPS_PROVIDER替代NETWORK_PROVIDER. 我们还可以通过调用requestLocationUpdates()两次来同时请求GPS和NetworkLocation Provider, 一次用NETWORK_PROVIDER, 一次用GPS_PROVIDER.

请求用户权限:

为了从NETWORK_PROVIDER或者GPS_PROVIDER接收位置更新, 我们必须在manifest中分别声明ACCESS_COARSE_LOCATION或者ACCESS_FINE_LOCATION权限来获取用户权限, 栗子:

<manifest ... >
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    ...
</manifest>

如果没有这些权限的话, APP会在请求位置更新的时候失败. 如果我们一起使用了NETWORK_PROVIDER和GPS_PROVIDER, 那么只需要请求ACCESS_FINE_LOCATION权限, 因为它包含这两种provider的权限(ACCESS_COARSE_LOCATION则只包括NETWORK_PROVIDER的权限).

定义一个最佳性能模型:

基于位置的APP现在十分的常见, 但是由于要获取最佳的精确度, 用户位置变化, 还有多种获取位置的方法, 以及考虑电池消耗, 这些让获取用户位置变得复杂起来. 想要获得最佳的用户位置并保持电池的电量, 我们必须定义一个统一的模型来指定APP如何获取用户位置. 这个模型包括什么时候启动和停止监听位置变化和什么时候使用缓存位置数据.

获取用户位置的流程:

这是典型的获取用户位置的流程:

1.      启动APP.

2.      过会儿之后启动监听器来从Location provider获取更新.

3.      通过过滤掉较新但是不精确的数据保留一个”当前最佳的预计位置(current best estimate)”.

4.      停止监听位置更新.

5.      使用最后最佳的预计位置.

下图在一个时间轴上用可视化的时段展示了这种模型, 它包含了这段时间监听到的位置更新事件:


这个图片展示了很多我们在使用定位APP的时候需要做的决定.

决定什么时候启动位置更新监听:

我们可能想要在APP刚启动的时候就启动位置更新的监听器, 或者仅在用户激活功能之后才启动. 长时间的监听会消耗大量的电量, 但是短时间的监听又不能保证精确度. 我们可以通过requestLocationUpdates()方法启动监听:

String locationProvider = LocationManager.NETWORK_PROVIDER;
// Or, use GPSlocation data:
// StringlocationProvider = LocationManager.GPS_PROVIDER;

locationManager.requestLocationUpdates(locationProvider, 0, 0, locationListener);

使用最后一次已知位置获取快速修正:

通常获取第一次位置修正都会消耗很多时间. 在取得更加精确的位置信息之前, 可以使用getLastKnownLocation(String)方法获得一个缓存的位置信息:

String locationProvider = LocationManager.NETWORK_PROVIDER;
// Or useLocationManager.GPS_PROVIDER

Location lastKnownLocation = locationManager.getLastKnownLocation(locationProvider);

决定何时停止监听:

决定停止监听的逻辑根据APP的需求可能很简单也可能很复杂. 同时还要记得定位会消耗很多电量, 应该在取得需要的信息之后就停止监听, 停止监听的方法是removeUpdates(PendingIntent), 栗子:

// Remove the listener you previously added
locationManager.removeUpdates(locationListener);

维护当前最佳的估计数:

我们可能会觉得最近获取的位置信息是最准确的. 但是因为定位精确度的变化, 最近的信息不见得总是最好的. 我们应该根据多个标准来选择最佳位置. 这些标准应该经过用例和现场测试. 这里是几个可以验证精确度的步骤:

1.      检查检索到的位置是否比之前的估计有明显的更新.

2.      检查精度是比以前的更好还是更差.

3.      检查新的位置从哪个provider获取并决定它是否更加值得信任.

实现这一逻辑的栗子大概长这样:

private static final int TWO_MINUTES = 1000 * 60 * 2;

/** Determineswhether one Location reading is better than the current Location fix
  * @param location  The new Location that you want to evaluate
  * @param currentBestLocation  The current Location fix, to whichyou want to compare the new one
  */

protected boolean isBetterLocation(Location location, Location currentBestLocation) {
    if (currentBestLocation == null) {
        // A new location is always better than no location
        return true;
    }

    // Check whetherthe new location fix is newer or older
    long timeDelta = location.getTime() - currentBestLocation.getTime();
    boolean isSignificantlyNewer = timeDelta > TWO_MINUTES;
    boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES;
    boolean isNewer = timeDelta > 0;

    // If it's beenmore than two minutes since the current location, use the new location
    // because theuser has likely moved
    if (isSignificantlyNewer) {
        return true;
    // If the newlocation is more than two minutes older, it must be worse
    } else if (isSignificantlyOlder) {
        return false;
    }

    // Check whetherthe new location fix is more or less accurate
    int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation.getAccuracy());
    boolean isLessAccurate = accuracyDelta > 0;
    boolean isMoreAccurate = accuracyDelta < 0;
    boolean isSignificantlyLessAccurate = accuracyDelta > 200;

    // Check if theold and new location are from the same provider
    boolean isFromSameProvider = isSameProvider(location.getProvider(),
            currentBestLocation.getProvider());

    // Determinelocation quality using a combination of timeliness and accuracy
    if (isMoreAccurate) {
        return true;
    } else if (isNewer && !isLessAccurate) {
        return true;
    } else if (isNewer && !isSignificantlyLessAccurate &&isFromSameProvider) {
        return true;
    }
    return false;
}

/** Checkswhether two providers are the same */
private boolean isSameProvider(String provider1, String provider2) {
    if (provider1 == null) {
      return provider2 == null;
    }
    return provider1.equals(provider2);
}

调整模型来节省电量和数据交换:

当我们测试APP的时候, 可能会发现我们的模型如果想要既提供好的定位又提供高性能, 可能需要一些调整. 这里是一些我们权衡两者可能要修改的东西:

l  减小窗口的大小: 一个更小的窗口意味着与GPS和网络定位服务更少的交互,所以会节省电池寿命. 但是它也会导致有更少的位置信息可以选择.

l  设置locationproviders来用更低的频率更新: 减少刷新位置信息的频率也可以节省电池的寿命, 但是会牺牲一定的精确度. 如何权衡取决于我们的APP逻辑. 我们可以通过减少requestLocationUpdates()的参数值来降低刷新的频率.

l  约束一组providers:根据APP的应用场景或者需要的精确度等级, 我们可以选择只使用Network Location Provider和GPS中的一个, 而不是全用. 这样可以降低电池消耗, 但是同样会降低精度.

常见应用案例:

有很多我们想要获取用户的位置信息的理由. 下面是两个我们可以用它们来丰富自己的APP的使用场景. 每个场景也描述了何时启动和停止监听器, 以及如何节省电池寿命.

通过位置标记用户创建的内容:

我们可能会需要创建一个APP, 允许用户通过位置信息标记一些内容. 比如分享本地体验, 共享一家餐厅的美食, 或者记录一些包括当前位置的信息. 一个描述这些交互如何发生的模型, 大概长这样:


为了获取最佳的精度, 我们可能选择在用户开始创建它们的内容甚至当应用启动的时候就开始获取用户的位置信息, 而在内容准备发送或者记录的时候停止更新位置信息. 我们可能需要考虑创建内容的任务时间大概多长, 然后决定什么时候开始启动位置信息更新.

帮助用户决定去哪儿:

我们可能会创建一个尝试提供一系列选项建议用户去哪的APP. 比如帮助用户找附近的餐馆, 商店, 娱乐设施并根据用户位置提供推荐的顺序. 要完成这些我们可能会用到:

l  当取得一个新的最佳位置信息的时候, 重新排列推荐目标.

l  如果推荐目标稳定了, 就停止监听位置更新.

该模型如下图所示:


提供模拟位置数据:

如果我们正在开发自己的APP, 那么我们可能会需要测试自己的定位模型工作的如何. 使用真实的Android设备是最简单的方法. 但是如果我们没有一个设备的话, 还是有方法可以测试基于位置功能的APP的, 只需要使用Android模拟器提供模拟位置数据就可以了. 有三种不同的方法发送APP模拟数据: 使用Android Studio, DDMS或者在模拟器终端使用”geo”命令. 详情可以参考这里.

 

总结:

定位是我们在移动设备上常用的功能, Android开发者可以使用android.location或者Google Location Services for Android来开发相关的APP.Android.location中的核心组件是LocationManager, 基本用法就是通过LocationManager查询可用的Location Providers, 包括手机基站, GPS, WiFi, 然后开启或者关闭位置更新监听器来获取位置数据. 在开发的时候, 通常会根据APP逻辑在精度和耗电量之间做权衡.


参考: https://developer.android.com/guide/topics/location/index.html

https://developer.android.com/guide/topics/location/strategies.html

Android 定位

阅读数 975

没有更多推荐了,返回首页