在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(); }