虽然现在第三方的定位非常强大,非常方便,但是我们在只需要很简单的定位,且不想用第三方的时候,我们可以自己动动手,基于GPS卫星定位和LBS基站定位的方式获取当前位置。
GPS定位
1.权限申请
首先我们需要申请权限,6.0以下系统在mainfest文件申请,因为需要通过网络获取经纬度对应的详细地址,所以需要INTERNET权限。代码如下:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.INTERNET"/>
6.0以上系统需要在Activity里面动态申请权限,首先判断定位权限是否被用户允许,如果没有允许,就需要申请定位权限。
//检查定位权限是否已经允许
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
//申请定位权限
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
PERMISSIONS_FINE_LOCATION);
} else {
//定位权限已经被允许
}
当申请权限的时候,会弹出提示用户是否允许申请的权限:
2.通过LocationManager获取定位
LocationManager的使用还是非常简单的,首先拿到他的实例,然后通过public void requestLocationUpdates(String provider, long minTime, float minDistance, LocationListener listener);方法设置监听并请求定位。
LocationManager locationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
/**
* GPS定位监听器
*/
LocationListener locationListener = new LocationListener() {
/**
* 位置信息变化时触发
*/
@Override
public void onLocationChanged(Location location) {
//位置信息变化时触发
LogUtils.i(TAG, "纬度:" + location.getLatitude() + " 经度:" + location.getLongitude()
+ " 海拔:" + location.getAltitude() + " 时间:" +
TimeUtils.milliseconds2String(location.getTime(), TimeUtils.TimeFormat.yyyy_MM_dd_HH$mm$ss));
GPSLocation.this.location = location;
}
/**
* GPS状态变化时触发
*/
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
LogUtils.i(provider);
switch (status) {
//GPS状态为可见时
case LocationProvider.AVAILABLE:
LogUtils.i(TAG, "当前GPS状态为可见状态");
break;
//GPS状态为不在服务区
case LocationProvider.OUT_OF_SERVICE:
LogUtils.i(TAG, "当前GPS状态为不在服务区状态");
location = null;
break;
//GPS状态为暂停服务时
case LocationProvider.TEMPORARILY_UNAVAILABLE:
LogUtils.i(TAG, "当前GPS状态为暂停服务状态");
location = null;
break;
}
}
/**
* 被用户开启后调用
*/
@Override
public void onProviderEnabled(String provider) {
LogUtils.i(TAG, "用户打开了GPS");
}
/**
* 被用户关闭后调用
*/
@Override
public void onProviderDisabled(String provider) {
LogUtils.i(TAG, "用户关闭了GPS");
location = null;
}
};
/**
* 绑定监听
* 参数1,设备:有GPS_PROVIDER和NETWORK_PROVIDER两种,前者是GPS,后者是GPRS以及WIFI定位
* 参数2,位置更新的最小时间间隔,以毫秒为单位
* 参数3,位置变化最小距离:当位置距离变化超过此值时,将更新位置信息,单位米
* 参数4,监听
* 备注:参数2和3,如果参数3不为0,则以参数3为准;参数3为0,则通过时间来定时更新;两者为0,则随时刷新
*/
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 10 * 1000, 100, locationListener);
通过上面的代码我们可以看到,定位的信息都是通过LocationListener监听回调的onLocationChanged(Location location)方法的参数传递回来,Location里面保存了经纬度以及海拔等信息。如果我们需要将经纬度转换为详细地理位置,则需要再想办法;
通过免费接口http://api.cellocation.com/regeo/?lat=34.232525&lon=108.91308166666667&output=json 可以将经纬度以详细地理位置返回给我们。
LBS基站定位
同样需要权限许可,有上面的权限即可
基站定位需要LBS数据仓库提供支持,我这里使用http://www.cellocation.com/interfac/提供的免费接口。
基站定位需要
* MCC: 国家代码:中国代码 460
* MNC,移动设备网络代码(Mobile Network Code,MNC),中国移动 = 00,中国联通 = 01, 中国电信 = 03 05 11
* LAC,Location Area Code,位置区域码;
* CID,Cell Identity,基站编号,是个16位的数据(范围是0到65535)。
所以我们先将这几个参数获取到,通过TelephonyManager可以获取我们需要的基站信息。具体代码如下:
/**
* 基站信息
* MCC: 国家代码:中国代码 460
* MNC,移动设备网络代码(Mobile Network Code,MNC),中国移动 = 00,中国联通 = 01, 中国电信 = 03 05 11
* LAC,Location Area Code,位置区域码;
* CID,Cell Identity,基站编号,是个16位的数据(范围是0到65535)。
*/
public static class StationInfo{
private int MCC;
private int MNC;
private int LAC;
private int CID;
get and set...
}
/**
* 获取基站信息
*/
private StationInfo getCellInfo() {
StationInfo stationInfo = new StationInfo();
/** 调用API获取基站信息 */
TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
if (!hasSimCard(mContext)){ //判断有没有sim卡,如果没有安装sim卡下面则会异常
Toast.makeText(mContext,"请安装sim卡",Toast.LENGTH_LONG).show();
return null;
}
String operator = telephonyManager.getNetworkOperator();
LogUtils.e("operator","operator="+operator);
int mcc = Integer.parseInt(operator.substring(0, 3));
int mnc = Integer.parseInt(operator.substring(3));
//参考http://www.cellocation.com/interfac/
int cid = 0;
int lac = 0;
if (mnc == 11 || mnc == 03 || mnc == 05){ //03 05 11 为电信CDMA
CdmaCellLocation location = (CdmaCellLocation) telephonyManager.getCellLocation();
//这里的值可根据接口需要的参数获取
cid = location.getBaseStationId();
lac = location.getNetworkId();
mnc = location.getSystemId();
} else {
GsmCellLocation location = (GsmCellLocation) telephonyManager.getCellLocation();
cid = location.getCid();
lac = location.getLac();
}
/** 将获得的数据放到结构体中 */
stationInfo.setMCC(mcc);
stationInfo.setMNC(mnc);
stationInfo.setLAC(lac);
stationInfo.setCID(cid);
return stationInfo;
}
接下来将获取到的 MCC, MNC, LAC, CID 数据通过接口请求获取经纬度和详细位置:
/**
* 通过此方法请求定位信息
*/
public void request() {
String url = "http://api.cellocation.com/cell/?mcc=%1$s&mnc=%2$s&lac=%3$s&ci=%4$s&output=json";
StationInfo info = getCellInfo();
if (info == null) {
listener.onFailed();
return;
}
LogUtils.i(info.toString());
url = String.format(url, info.getMCC(), info.getMNC(), info.getLAC(), info.getCID());
//通过网络请求获取经纬度和详细位置
getLocation(url);
}
下面我们看一下效果图:
其实我这里测试LBS定位比GPS定位出来的详细信息更加准确,GPS定位超级费电,可能是我这手机比较low,打开一会儿手机就发热,电池掉的也飞快。