在android开发中地图和定位是很多软件不可或缺的内容,这些特色功能也给人们带来了很多方便。定位一般分为三种发方案:即GPS定位、Google网络定位以及基站定位
最简单的手机定位方式当然是通过GPS模块(现在大部分的智能机应该都有了)。GPS方式准确度是最高的,但是它的缺点也非常明显:1,比较耗电;2,绝大部分用户默认不开启GPS模块;3,从GPS模块启动到获取第一次定位数据,可能需要比较长的时间;4,室内几乎无法使用。这其中,缺点2,3都是比较致命的。需要指出的是,GPS走的是卫星通信的通道,在没有网络连接的情况下也能用。
另外一种常见的定位方式是基站定位。大致思路就是采集到手机上的基站ID号(cellid)和其它的一些信息(MNC,MCC,LAC等等),然后通过网络访问一些定位服务,获取并返回对应的经纬度坐标。基站定位的精确度不如GPS,但好处是能够在室内用,只要网络通畅就行。
还有Wifi定位。和基站定位类似,这种方式是通过获取当前所用的wifi的一些信息,然后访问网络上的定位服务以获得经纬度坐标。因为它和基站定位其实都需要使用网络,所以在Android也统称为Network方式。
最后需要解释一点的是AGPS方式。很多人将它和基站定位混为一谈,但其实AGPS的本质仍然是GPS,只是它会使用基站信息对获取GPS进行辅助,然后还能对获取到的GPS结果进行修正,所以AGPS要比传统的GPS更快,准确度略高。
本文分别介绍GPS定位、以及基于Google的网络Wifi定位,以及最后的使用百度LBS的定位(百度LBS的定位功能比较强大,集成了GPS,网络wifi以及基站定位三种定位方法)。主要用例就是利用这三种方法获取位置经纬度,以及利用经纬度来获取所在的城市及区域
而根据经纬度来获取所在位置的城市及区域全部都是采用百度地图的API:http://api.map.baidu.com/geocoder?output=json&location=39.983228,116.491146key=您的key
,这个key需要你自己申请百度开发者账号来得到的。
首先来看看定位实例效果图如下:
1.GPS定位
(1)打开GPS设置
private void openGPSSettings() { LocationManager alm = (LocationManager) this .getSystemService(Context.LOCATION_SERVICE); if (alm.isProviderEnabled(android.location.LocationManager.GPS_PROVIDER)) { Toast.makeText(this, "GPS模块正常", Toast.LENGTH_SHORT).show(); doWork(); return; } else { Toast.makeText(this, "请开启GPS!", Toast.LENGTH_SHORT).show(); Intent intent = new Intent(Settings.ACTION_SECURITY_SETTINGS); startActivityForResult(intent, 0); // 此为设置完成后返回到获取界面 } }
(2)通过GPS获取经纬度信息
private void doWork() { String msg = ""; LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); Criteria criteria = new Criteria(); // 获得最好的定位效果 criteria.setAccuracy(Criteria.ACCURACY_FINE); criteria.setAltitudeRequired(false); criteria.setBearingRequired(false); criteria.setCostAllowed(false); // 使用省电模式 criteria.setPowerRequirement(Criteria.POWER_LOW); // 获得当前的位置提供者 String provider = locationManager.getBestProvider(criteria, true); // 获得当前的位置 Location location = locationManager.getLastKnownLocation(provider); double latitude = location.getLatitude(); double longitude = location.getLongitude(); locationString = "&location=" + latitude + "," + longitude; keyString = "&key=您的key"; questURL = questURL + locationString + keyString; new ReadJSONFeedTask().execute(questURL); }
(3)由经纬度获取所在城市和区域的ReadJSONFeedTask类的实现:
/** * 由经纬度获取所在的城市及区域信息 * @author caizhiming * */ private class ReadJSONFeedTask extends AsyncTask<String, Void, String> { StringBuilder stringBuilder = new StringBuilder(); @Override protected String doInBackground(String... urls) { // TODO Auto-generated method stub return readJSONFeed(urls[0]); } @Override protected void onPostExecute(String result) { // TODO Auto-generated method stub String strItem; try { JSONObject jsonObject = new JSONObject(result); JSONObject resultObject = jsonObject.getJSONObject("result"); JSONObject addressComponentObject = resultObject .getJSONObject("addressComponent"); String city = addressComponentObject.getString("city"); String district = addressComponentObject.getString("district"); city = "城市:" + city; district = " 区:" + district; stringBuilder.append(city + district); textView.setText(stringBuilder.toString()); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } /** * 请求json数据 * @param url * @author caizhiming */ public String readJSONFeed(String url) { StringBuilder stringBuilder = new StringBuilder(); HttpClient client = new DefaultHttpClient(); HttpGet httpGet = new HttpGet(url); HttpResponse response; try { response = client.execute(httpGet); StatusLine statusLine = response.getStatusLine(); int statusCode = statusLine.getStatusCode(); if (statusCode == 200) { HttpEntity entity = response.getEntity(); InputStream content = entity.getContent(); BufferedReader reader = new BufferedReader( new InputStreamReader(content)); String line; while ((line = reader.readLine()) != null) { stringBuilder.append(line); } } else { Log.e("JSON", "Failed to download file"); } } catch (ClientProtocolException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return stringBuilder.toString(); }
2. 网络WIFI定位
(1) 通过网络WIFI来获取经纬度信息:
/* ====================Google Location By NetWork=========================== */ private void getLocationByNetwork() { LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); LocationListener locationListener = new LocationListener() { // Provider的状态在可用、暂时不可用和无服务三个状态直接切换时触发此函数 @Override public void onStatusChanged(String provider, int status, Bundle extras) { } // Provider被enable时触发此函数,比如GPS被打开 @Override public void onProviderEnabled(String provider) { } // Provider被disable时触发此函数,比如GPS被关闭 @Override public void onProviderDisabled(String provider) { } // 当坐标改变时触发此函数,如果Provider传进相同的坐标,它就不会被触发 @Override public void onLocationChanged(Location location) { if (location != null) { Log.e("Map", "Location changed : Lat: " + location.getLatitude() + " Lng: " + location.getLongitude()); } } }; locationManager.requestLocationUpdates( LocationManager.NETWORK_PROVIDER, 1000, 0, locationListener); Location location = locationManager .getLastKnownLocation(LocationManager.NETWORK_PROVIDER); double latitude = 0; double longitude = 0; if (location != null) { latitude = location.getLatitude(); // 经度 longitude = location.getLongitude(); // 纬度 } locationString = "&location=" + latitude + "," + longitude; keyString = "&key=你的key"; questURL = questURL + locationString + keyString; Toast.makeText(this, locationString, Toast.LENGTH_LONG).show(); new ReadJSONFeedTask().execute(questURL); }
(2)由经纬度获取所在城市和区域的ReadJSONFeedTask类的实现:
/**
* 由经纬度获取所在的城市及区域信息
* @author caizhiming
*
*/
private class ReadJSONFeedTask extends AsyncTask<String, Void, String> {
StringBuilder stringBuilder = new StringBuilder(); @Override protected String doInBackground(String... urls) { // TODO Auto-generated method stub return readJSONFeed(urls[0]); } @Override protected void onPostExecute(String result) { // TODO Auto-generated method stub String strItem; try { JSONObject jsonObject = new JSONObject(result); JSONObject resultObject = jsonObject.getJSONObject("result"); JSONObject addressComponentObject = resultObject .getJSONObject("addressComponent"); String city = addressComponentObject.getString("city"); String district = addressComponentObject.getString("district"); city = "城市:" + city; district = " 区:" + district; stringBuilder.append(city + district); textView.setText(stringBuilder.toString()); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } /** * 请求json数据 * @param url * @author caizhiming */ public String readJSONFeed(String url) { StringBuilder stringBuilder = new StringBuilder(); HttpClient client = new DefaultHttpClient(); HttpGet httpGet = new HttpGet(url); HttpResponse response; try { response = client.execute(httpGet); StatusLine statusLine = response.getStatusLine(); int statusCode = statusLine.getStatusCode(); if (statusCode == 200) { HttpEntity entity = response.getEntity(); InputStream content = entity.getContent(); BufferedReader reader = new BufferedReader( new InputStreamReader(content)); String line; while ((line = reader.readLine()) != null) { stringBuilder.append(line); } } else { Log.e("JSON", "Failed to download file"); } } catch (ClientProtocolException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return stringBuilder.toString(); }
3.使用百度LBS的SDK定位
(1)导入百度的LBS的SDK开发Jar包,开发者可以到百度开发者中心去下载即可。即BaiduLBS_Android.jar包,放在项目的libs目录下即可。需要注意的是,同时需要在libs目录下建立armeabi目录,并在该目录下放sdk中的liblocSDK4d.so文件,这样才能使用sdk。
(2)初始化百度LBS定位信息,包括初始化定位客户端,定位监听器,定位模式等信息:
/** * baidu lbs location * * @author caizhiming */ private void InitLocation() { Log.v("LocationActivity", "InitLocation"); mLocationClient = new LocationClient(this.getApplicationContext()); // 声明LocationClient类 myListener = new MyLocationListener(); mLocationClient.registerLocationListener(myListener); // 注册监听函数 LocationClientOption option = new LocationClientOption(); option.setLocationMode(tempMode);// 设置定位模式 option.setCoorType(tempcoor);// 返回的定位结果是百度经纬度,默认值gcj02 int span = 3000; option.setScanSpan(span);// 设置发起定位请求的间隔时间为5000ms option.setIsNeedAddress(false); mLocationClient.setLocOption(option); }
另外,还需要在AndroidMenifest.xml中配置key信息如下:
<!-- meta-data需要写在application中 --> <meta-data android:name="com.baidu.lbsapi.API_KEY" android:value="您的key" />
最后还需要AndroidMenifest.xml中配置相应需要的权限如下:
<!-- baidu lbs --> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" > </uses-permission> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" > </uses-permission> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" > </uses-permission> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" > </uses-permission> <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" /> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" > </uses-permission> <uses-permission android:name="android.permission.READ_LOGS" > </uses-permission> <uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.WRITE_SETTINGS" />
(3)启动百度LBS的定位服务并获取经纬度等信息:
/** * baidu lbs location * * @author caizhiming */ private void getLocationByBaiduLBS() { Log.v("LocationActivity", "getLocationByBaiduLBS"); mLocationClient.start(); } /** * baidu lbs location * * @author caizhiming */ public class MyLocationListener implements BDLocationListener { @Override public void onReceiveLocation(BDLocation location) { Log.v("LocationActivity", "MyLocationListener-onReceiveLocation"); if (location == null) return; StringBuffer sb = new StringBuffer(256); sb.append("time : "); sb.append(location.getTime()); sb.append("\nerror code : "); sb.append(location.getLocType()); sb.append("\nlatitude : "); sb.append(location.getLatitude()); sb.append("\nlontitude : "); sb.append(location.getLongitude()); sb.append("\nradius : "); sb.append(location.getRadius()); if (location.getLocType() == BDLocation.TypeGpsLocation) { sb.append("\nspeed : "); sb.append(location.getSpeed()); sb.append("\nsatellite : "); sb.append(location.getSatelliteNumber()); } else if (location.getLocType() == BDLocation.TypeNetWorkLocation) { sb.append("\naddr : "); sb.append(location.getAddrStr()); } logMsg(sb.toString()); locationString = "&location=" + location.getLatitude() + "," + location.getLongitude(); keyString = "&key=你的key"; questURL = questURL + locationString + keyString; new ReadJSONFeedTask().execute(questURL); } }
(4)由经纬度获取所在城市和区域的ReadJSONFeedTask类的实现:
/** * 由经纬度获取所在的城市及区域信息 * @author caizhiming * */ private class ReadJSONFeedTask extends AsyncTask<String, Void, String> { StringBuilder stringBuilder = new StringBuilder(); @Override protected String doInBackground(String... urls) { // TODO Auto-generated method stub return readJSONFeed(urls[0]); } @Override protected void onPostExecute(String result) { // TODO Auto-generated method stub String strItem; try { JSONObject jsonObject = new JSONObject(result); JSONObject resultObject = jsonObject.getJSONObject("result"); JSONObject addressComponentObject = resultObject .getJSONObject("addressComponent"); String city = addressComponentObject.getString("city"); String district = addressComponentObject.getString("district"); city = "城市:" + city; district = " 区:" + district; stringBuilder.append(city + district); textView.setText(stringBuilder.toString()); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } /** * 请求json数据 * @param url * @author caizhiming */ public String readJSONFeed(String url) { StringBuilder stringBuilder = new StringBuilder(); HttpClient client = new DefaultHttpClient(); HttpGet httpGet = new HttpGet(url); HttpResponse response; try { response = client.execute(httpGet); StatusLine statusLine = response.getStatusLine(); int statusCode = statusLine.getStatusCode(); if (statusCode == 200) { HttpEntity entity = response.getEntity(); InputStream content = entity.getContent(); BufferedReader reader = new BufferedReader( new InputStreamReader(content)); String line; while ((line = reader.readLine()) != null) { stringBuilder.append(line); } } else { Log.e("JSON", "Failed to download file"); } } catch (ClientProtocolException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return stringBuilder.toString(); }