Android LBS相关

##Android定位/LBS

刚刚写完一个定位的小需求,小记一下。

需求:

获取当前手机所在城市/国家

当看到这个需求的时候,我打算用百度、高德或者QQ的地图SDK的,但是考虑到国外定位的准确性,BOSS说用Google地图。可是国内Android手机基本都是太监(阉割了谷歌服务),所以只能放弃了。

原本已经打算用高德好了,但是发现了一个谷歌地图的API,即:

maps.google.cn/maps/api/geocode/json?language=zh-CN&sensor=true&latlng=-33.86984542,151.20689392

用浏览器访问这个地址,你会得到当前经纬度的定位信息,这里的-33.86984542,151.20689392对应的是悉尼。

那么就好办了,完成上面的需求只需要一下几个步骤了:

0.简略了解谷歌地图的api 1.获取手机的经纬度 2.根据经纬度访问谷歌地图的api 3.解析返回的数据


####0.谷歌地图的API 在开始之前,先解释一下上面的API地址,官方文档很详细,这里我简要记载一些基本的。

1.language=zh-CN 代表返回的是中文,当然language=en就是英文了。 2.用.cn而不是.com是因为伟大的GFW。 3.json 代表返回的是json数据,这里还可以是xml。 4.sensor 顾名思义,是否支持传感器。 5.latlng 就是经纬度了,用逗号隔开。

####1.获取手机当前位置的经纬度

....

private long locationRefreshMinTime = 5000;
private long locationRefreshMinDistance = 0;

....

private void getLocalInformation() {
	//获取LocationManager实例
	LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
	
	if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
		//如果GPS可用
		locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, locationRefreshMinTime, locationRefreshMinDistance, locationListener);
	} else {
		//如果GPS不可用
		locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, locationRefreshMinTime, locationRefreshMinDistance, locationListener);
	}
}

通过LocationManager的requestLocationUpdates()方法去请求当前的Location信息,requestLocationUpdates()接收四个参数:

1.provider,供应者,即Location的信息从谁那里获取,这里有两个供应者: LocationManager.GPS_PROVIDER ,LocationManager.NETWORK_PROVIDER。 2.minTime,最小时间,其实就是更新的间隔时间,单位是毫秒。 3.minDistance,最小距离,其实就是更新的最小偏移距离,即当手机的偏移位置超过了这个值,才进行更新。 4.listener,LocationListener,Location信息变化时调用的接口。

下面去实现LocationListener,代码如下:

private LocationListener locationListener = new LocationListener() {

	@Override
	public void onStatusChanged(String provider, int status, Bundle extras) {
		// 当Location信息供应者发生变化的时候调用
	}

	@Override
	public void onProviderEnabled(String provider) {
		// Provider被disable时调用,比如GPS被关闭   
	}

	@Override
	public void onProviderDisabled(String provider) {
		//  Provider被enable时调用,比如GPS被打开   
	}

	@Override
	public void onLocationChanged(Location location) {
		// 当坐标改变时调用
		if (location != null) {
			latitude = location.getLatitude() + "";
			longitude = location.getLongitude() + "";

			LogUtil.e(tag, "经度:" + latitude + "\n" + "纬度:" + longitude);

			editor.putString(SharedPreferencesConst.LOCATION_INFORMATION_LATITUDE, latitude);
			editor.putString(SharedPreferencesConst.LOCATION_INFORMATION_LONGITUDE, longitude);
			editor.commit();

			thisTime = location.getTime();
			LogUtil.e(tag, "thisTime = " + thisTime);
			LogUtil.e(tag, "lastTime = " + lastTime);
			LogUtil.e(tag, "thisTime - lastTime = " + (thisTime - lastTime));
			if (thisTime - lastTime > intervalTime || locality.equals(" ") || country.equals(" ")) {
				lastTime = thisTime;
				editor.putLong(SharedPreferencesConst.LOCATION_INFORMATION_UPDATE_LAST_TIME, thisTime);
				editor.commit();
				if (isAnalyzeJson) {

				} else {
					analyzeJson();
				}
			}
		}
	}
};

有些地方加了注释,是因为我实际开发需求才需要这些代码,与本文的探讨无关,所以先注释掉。

如上代码,我们分别实现了LocationListener的四个接口,在相应的状态下去处理事务,当位置信息发生变化时,调用了onLocationChanged(Location location),如果location不为空,即获取到了当前手机的地理位置信息。


####1.根据经纬度访问谷歌地图的api

在上面的代码中,我们获取了信息之后,我调用了我自己写的”analyzeJson()”方法去获取并解析数据,代码如下:

private void analyzeJson() {
	isAnalyzeJson = true;
	LogUtil.e(tag, "analyzeJson()");
	//格式化访问的地址
	String urlString = String.format(iNFOMATION_URL, Double.valueOf(latitude), Double.valueOf(longitude));
	parseJsonString(getJsonStringFromUrl(urlString));

	for (int i = 0; i < loactions.size(); i++) {
		ArrayList<String> typesList = loactions.get(i).typesList;
		int typesListSize = typesList.size();
		for (int j = 0; j < typesListSize; j++) {
			if (typesList.get(j).equals("country")) {
				hasCountry = true;
				country = loactions.get(i).formatted_address;
				editor.putString(SharedPreferencesConst.LOCATION_INFORMATION_COUNTRY, loactions.get(i).formatted_address);
				editor.commit();
			}
		}

		ArrayList<ADDRESS_COMPONENTS> address_components_list = loactions.get(i).address_components_list;
		int address_components_list_size = address_components_list.size();
		for (int k = 0; k < address_components_list_size; k++) {
			ADDRESS_COMPONENTS address_components = address_components_list.get(k);
			ArrayList<String> address_components_typesList = address_components.typesList;
			int address_components_typesListSize = address_components_typesList.size();
			for (int j = 0; j < address_components_typesListSize; j++) {
				if (address_components_typesList.get(j).equals("locality")) {
					hasLocality = true;
					locality = address_components.long_name;
					editor.putString(SharedPreferencesConst.LOCATION_INFORMATION_LOCALITY, address_components.long_name);
					editor.commit();
				}

				if (address_components_typesList.get(j).equals("country")) {
					hasCountry = true;
					country = address_components.long_name;
					editor.putString(SharedPreferencesConst.LOCATION_INFORMATION_COUNTRY, address_components.long_name);
					editor.commit();
				}
			}
		}
	}

	if (!hasCountry) {
		country = " ";
		editor.putString(SharedPreferencesConst.LOCATION_INFORMATION_COUNTRY, country);
		editor.commit();
	}

	if (!hasLocality) {
		locality = " ";
		editor.putString(SharedPreferencesConst.LOCATION_INFORMATION_LOCALITY, locality);
		editor.commit();
	}

	LogUtil.e(tag, "analyzeJson(),locality = " + locality);
	LogUtil.e(tag, "analyzeJson(),country = " + country);
	
	isAnalyzeJson = false;
	hasCountry = false;
	hasLocality = false;
}

首先根据location.getLatitude()location.getLongitude()获取到的经纬度去组织API访问地址:

private static final String iNFOMATION_URL = "http://maps.google.cn/maps/api/geocode/json?language=zh-CN&sensor=true&latlng=%1$s,%2$s";
...
String urlString = String.format(iNFOMATION_URL, Double.valueOf(latitude), Double.valueOf(longitude));//组织Url地址

接着调用getJsonStringFromUrl(String url)去访问API地址:

private String getJsonStringFromUrl(String url) {
	LogUtil.e(tag, "getJsonStringFromUrl(),url = " + url);

	//设置线程的策略,获取log信息
	StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectDiskReads().detectDiskWrites().detectNetwork().penaltyLog().build());
	StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectLeakedSqlLiteObjects().penaltyLog().penaltyDeath().build());

	URL cityInfoUrl;
	byte[] data = new byte[] {};
	try {
		cityInfoUrl = new URL(url);
		HttpURLConnection connection = (HttpURLConnection) cityInfoUrl.openConnection();
		connection.setReadTimeout(5 * 1000);
		connection.setRequestMethod("GET");
		InputStream inStream = connection.getInputStream();
		data = readInputStream(inStream);
		return (new String(data));
	} catch (Exception e) {
		e.printStackTrace();
	}
	return (new String(data));
}

####2.解析数据 上面调用getJsonStringFromUrl(String url)去访问API地址后,返回了当前手机经纬度的地理信息,接着就要解析这一大坨信息了。 调用parseJsonString()方法去解析获取到的joson数据:

private ArrayList<LOCATION> loactions = new ArrayList<LOCATION>();
....
private void parseJsonString(String jsonString) {
	try {
		JSONObject json = new JSONObject(jsonString);
		JSONArray results = json.getJSONArray("results");
		int resultsLength = results.length();
		for (int i = 0; i < resultsLength; i++) {
			JSONObject results_item = results.getJSONObject(i);
			loactions.add(LOCATION.fromJson(results_item));
		}
	} catch (JSONException e) {
		e.printStackTrace();
	}
}

下面是用于解析返回Json数据的实体类。 因为是实际开发的项目,这里我使用了开源的ActiveAndroid

###LOCATION类: @Table(name = “LOCATION”) public class LOCATION extends Model implements Serializable { private static final long serialVersionUID = 1L;

	@Column(name = "formatted_address")
	public String formatted_address;
	@Column(name = "place_id")
	public String place_id;

	public ArrayList<ADDRESS_COMPONENTS> address_components_list = new ArrayList<ADDRESS_COMPONENTS>();
	public ArrayList<GEOMETRY> geometry_list = new ArrayList<GEOMETRY>();
	public ArrayList<String> typesList = new ArrayList<String>();

	public static LOCATION fromJson(JSONObject jsonObject) throws JSONException {
		if (null == jsonObject) {
			return null;
		}

		LOCATION localItem = new LOCATION();
		localItem.formatted_address = jsonObject.optString("formatted_address");
		localItem.place_id = jsonObject.optString("place_id");

		JSONArray address_components = jsonObject.optJSONArray("address_components");
		if (address_components != null) {
			for (int i = 0; i < address_components.length(); i++) {
				if (localItem.address_components_list != null) {
					localItem.address_components_list.add(ADDRESS_COMPONENTS.fromJson(address_components.getJSONObject(i)));
				}
			}
		}

		JSONArray geometry = jsonObject.optJSONArray("geometry");
		if (geometry != null) {
			for (int i = 0; i < geometry.length(); i++) {
				if (localItem.geometry_list != null) {
					localItem.geometry_list.add(GEOMETRY.fromJson(geometry.getJSONObject(i)));
				}
			}
		}

		JSONArray types = jsonObject.optJSONArray("types");

		if (types != null) {
			for (int i = 0; i < types.length(); i++) {
				if (localItem.typesList != null) {
					localItem.typesList.add(types.getString(i));
				}
			}
		}

		return localItem;
	}
}

###ADDRESS_COMPONENTS类:

public class ADDRESS_COMPONENTS extends Model implements Serializable {
	private static final String tag = "ADDRESS_COMPONENTS";
	private static final long serialVersionUID = 1L;
	@Column(name = "long_name")
	public String long_name;
	@Column(name = "short_name")
	public String short_name;

	public ArrayList<String> typesList = new ArrayList<String>();
	
	public static ADDRESS_COMPONENTS fromJson(JSONObject jsonObject) throws JSONException {
		if (null == jsonObject) {
			return null;
		}

		ADDRESS_COMPONENTS localItem = new ADDRESS_COMPONENTS();
		localItem.long_name = jsonObject.optString("long_name");
		localItem.short_name = jsonObject.optString("short_name");

		JSONArray types = jsonObject.optJSONArray("types");
		
		if (types != null) {
			for (int i = 0; i < types.length(); i++) {
				if (localItem.typesList != null) {
					localItem.typesList.add(types.getString(i));
				}
			}
		}
		return localItem;
	}
}

###GEOMETRY类:

public class GEOMETRY extends Model implements Serializable {
	private static final String tag = "GEOMETRY";
	private static final long serialVersionUID = 1L;
	
	@Column(name = "location_type")
	public String location_type;
	@Column(name = "lat")
	public String lat;
	@Column(name = "lng")
	public String lng;
	
	public ArrayList<String> location = new ArrayList<String>();

	public static GEOMETRY fromJson(JSONObject jsonObject) throws JSONException {
		if (null == jsonObject) {
			return null;
		}

		GEOMETRY localItem = new GEOMETRY();
		localItem.location_type = jsonObject.optString("location_type");

		JSONObject location = jsonObject.getJSONObject("location");
		localItem.lat = location.optString("lat");
		localItem.lng = location.optString("lng");

		return localItem;
	}
}

通过以上的方法,就完成了API返回数据的解析,接着对数据进行遍历,判断types来获取相应的数据。

例如 types 包含 country,那么当前层级下的 long_name 对应的就是国家。 下面给出一下 types 所拥有的类型值:

street_number:表示精确的街道编号。
airport:表示机场。
premise:表示已命名的位置,通常是具有常用名称的建筑物或建筑群。
neighborhood:表示已命名的邻近地区。
sublocality_level_1:表示仅次于地区级别的1级行政实体。
sublocality_level_2:表示仅次于地区级别的2级行政实体。
sublocality_level_3:表示仅次于地区级别的3级行政实体。
administrative_area_level_1:表示仅次于国家级别的1级行政实体,中国为“省”。
administrative_area_level_2:表示仅次于国家级别的2级行政实体,中国为“市”。
administrative_area_level_3:表示仅次于国家级别的3级行政实体,中国为“县”。
sublocality:
postal_code 表示邮政编码。
political:表示某个行政管理区的多边形。
route:表示一条已命名的路线。
street_address:一个精确的街道地址。
locality:表示合并的市镇级别政治实体。(城市)
country:国家政治实体

最后,因为获取并解析数据是一个耗时的操作,所以这些操作应该写在Service中。 因为是公司项目,所以就不能上Demo了。 下面附上我获取LocationInrmation的完整代码,其实主要的操作都在这里了:

public class LocationInformationService extends Service {
	public static final String tag = "LocationInformationService";
	public static final String LOCATIONSTATUS = "com.qzmobile.android.location";

	private static final String iNFOMATION_URL = "http://maps.google.cn/maps/api/geocode/json?language=zh-CN&sensor=true&latlng=%1$s,%2$s";

	// private long intervalTime = 1000 * 60 * 30;
	private long intervalTime = 5000;
	private long locationRefreshMinTime = 5000;
	private long locationRefreshMinDistance = 0;

	private SharedPreferences shared;
	private SharedPreferences.Editor editor;

	private String latitude;
	private String longitude;

	private long lastTime;
	private long thisTime;

	private ArrayList<LOCATION> loactions = new ArrayList<LOCATION>();

	private String locality;
	private String country;

	private boolean isAnalyzeJson = false;
	
	private boolean hasCountry = false;
	private boolean hasLocality = false;
	
	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		return super.onStartCommand(intent, flags, startId);
	}

	@Override
	public void onCreate() {
		LogUtil.e(tag, "onCreate()");
		super.onCreate();
		shared = getSharedPreferences(SharedPreferencesConst.LOCATION_INFORMATION, 0);
		editor = shared.edit();
		initData();
		getLocalInformation();
	}

	private void initData() {
		LogUtil.e(tag, "initData()");
		latitude = shared.getString(SharedPreferencesConst.LOCATION_INFORMATION_LATITUDE, "0.00");
		longitude = shared.getString(SharedPreferencesConst.LOCATION_INFORMATION_LONGITUDE, "0.00");
		lastTime = shared.getLong(SharedPreferencesConst.LOCATION_INFORMATION_UPDATE_LAST_TIME, 0);
		locality = shared.getString(SharedPreferencesConst.LOCATION_INFORMATION_LOCALITY, " ");
		country = shared.getString(SharedPreferencesConst.LOCATION_INFORMATION_COUNTRY, " ");
	}

	private void getLocalInformation() {
		LogUtil.e(tag, "getLocalInformation()");
		LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
		if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
			LogUtil.e(tag, "GPS_PROVIDER");
			locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, locationRefreshMinTime, locationRefreshMinDistance, locationListener);
		} else {
			LogUtil.e(tag, "NETWORK_PROVIDER");
			locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, locationRefreshMinTime, locationRefreshMinDistance, locationListener);
		}
	}

	@Override
	public IBinder onBind(Intent intent) {
		return null;
	}

	private LocationListener locationListener = new LocationListener() {

		@Override
		public void onStatusChanged(String provider, int status, Bundle extras) {
			LogUtil.e(tag, "onStatusChanged");
		}

		@Override
		public void onProviderEnabled(String provider) {
			LogUtil.e(tag, "onProviderEnabled");
		}

		@Override
		public void onProviderDisabled(String provider) {
			LogUtil.e(tag, "onProviderDisabled");
		}

		@Override
		public void onLocationChanged(Location location) {
			LogUtil.e(tag, "onLocationChanged");
			if (location != null) {
				latitude = location.getLatitude() + "";
				longitude = location.getLongitude() + "";

				LogUtil.e(tag, "经度:" + latitude + "\n" + "纬度:" + longitude);

				editor.putString(SharedPreferencesConst.LOCATION_INFORMATION_LATITUDE, latitude);
				editor.putString(SharedPreferencesConst.LOCATION_INFORMATION_LONGITUDE, longitude);
				editor.commit();

				thisTime = location.getTime();
				LogUtil.e(tag, "thisTime = " + thisTime);
				LogUtil.e(tag, "lastTime = " + lastTime);
				LogUtil.e(tag, "thisTime - lastTime = " + (thisTime - lastTime));
				if (thisTime - lastTime > intervalTime || locality.equals(" ") || country.equals(" ")) {
					lastTime = thisTime;
					editor.putLong(SharedPreferencesConst.LOCATION_INFORMATION_UPDATE_LAST_TIME, thisTime);
					editor.commit();
					if (isAnalyzeJson) {

					} else {
						analyzeJson();
					}
				}
			}
		}
	};

	private void analyzeJson() {
		isAnalyzeJson = true;
		LogUtil.e(tag, "analyzeJson()");
		String urlString = String.format(iNFOMATION_URL, Double.valueOf(latitude), Double.valueOf(longitude));
		parseJsonString(getJsonStringFromUrl(urlString));

		for (int i = 0; i < loactions.size(); i++) {
			ArrayList<String> typesList = loactions.get(i).typesList;
			int typesListSize = typesList.size();
			for (int j = 0; j < typesListSize; j++) {
				if (typesList.get(j).equals("country")) {
					hasCountry = true;
					country = loactions.get(i).formatted_address;
					editor.putString(SharedPreferencesConst.LOCATION_INFORMATION_COUNTRY, loactions.get(i).formatted_address);
					editor.commit();
				}
			}

			ArrayList<ADDRESS_COMPONENTS> address_components_list = loactions.get(i).address_components_list;
			int address_components_list_size = address_components_list.size();
			for (int k = 0; k < address_components_list_size; k++) {
				ADDRESS_COMPONENTS address_components = address_components_list.get(k);
				ArrayList<String> address_components_typesList = address_components.typesList;
				int address_components_typesListSize = address_components_typesList.size();
				for (int j = 0; j < address_components_typesListSize; j++) {
					if (address_components_typesList.get(j).equals("locality")) {
						hasLocality = true;
						locality = address_components.long_name;
						editor.putString(SharedPreferencesConst.LOCATION_INFORMATION_LOCALITY, address_components.long_name);
						editor.commit();
					}

					if (address_components_typesList.get(j).equals("country")) {
						hasCountry = true;
						country = address_components.long_name;
						editor.putString(SharedPreferencesConst.LOCATION_INFORMATION_COUNTRY, address_components.long_name);
						editor.commit();
					}
				}
			}
		}

		if (!hasCountry) {
			country = " ";
			editor.putString(SharedPreferencesConst.LOCATION_INFORMATION_COUNTRY, country);
			editor.commit();
		}

		if (!hasLocality) {
			locality = " ";
			editor.putString(SharedPreferencesConst.LOCATION_INFORMATION_LOCALITY, locality);
			editor.commit();
		}

		LogUtil.e(tag, "analyzeJson(),locality = " + locality);
		LogUtil.e(tag, "analyzeJson(),country = " + country);
		
		isAnalyzeJson = false;
		hasCountry = false;
		hasLocality = false;
	}

	private String getJsonStringFromUrl(String url) {
		LogUtil.e(tag, "getJsonStringFromUrl(),url = " + url);

		StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectDiskReads().detectDiskWrites().detectNetwork().penaltyLog().build());
		StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectLeakedSqlLiteObjects().penaltyLog().penaltyDeath().build());

		URL cityInfoUrl;
		byte[] data = new byte[] {};
		try {
			cityInfoUrl = new URL(url);
			HttpURLConnection connection = (HttpURLConnection) cityInfoUrl.openConnection();
			connection.setReadTimeout(5 * 1000);
			connection.setRequestMethod("GET");
			InputStream inStream = connection.getInputStream();
			data = readInputStream(inStream);
			return (new String(data));
		} catch (Exception e) {
			e.printStackTrace();
		}
		return (new String(data));
	}

	private byte[] readInputStream(InputStream inStream) throws Exception {
		ByteArrayOutputStream outStream = new ByteArrayOutputStream();
		byte[] buffer = new byte[1024];
		int len = 0;
		while ((len = inStream.read(buffer)) != -1) {
			outStream.write(buffer, 0, len);
		}
		inStream.close();
		return outStream.toByteArray();
	}

	private void parseJsonString(String jsonString) {
		try {
			JSONObject json = new JSONObject(jsonString);
			JSONArray results = json.getJSONArray("results");
			int resultsLength = results.length();
			for (int i = 0; i < resultsLength; i++) {
				JSONObject results_item = results.getJSONObject(i);
				loactions.add(LOCATION.fromJson(results_item));
			}
		} catch (JSONException e) {
			e.printStackTrace();
		}
	}
}

Whitelaning’s wiki It’s very easy to be different but very difficult to be better.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值