基於android的定位無非就兩種:network、gps。兩者各有優劣。
Network:定位快,準確度低,受環境影響小。
GPS:定位慢,準確度高,受環境影響大。
本文要解決的問題:
1. locationManager.getLastKnownLocation方法返回null。
2. 如何?快速而又精確的定位。
E文好的話,直接看官網就好了http://developer.android.com/guide/topics/location/strategies.html
在你的程式裡如果有這樣的代碼你就要注意了(現在看來這些倒是多餘了)
Criteria criteria = new Criteria(); criteria.setAccuracy(Criteria.ACCURACY_FINE);//高精度 criteria.setAltitudeRequired(false);//無海拔要求 criteria.setBearingRequired(false);//無方位要求 criteria.setCostAllowed(true);//允許產生資費 criteria.setPowerRequirement(Criteria.POWER_LOW);//低功耗 // 擷取最佳服務物件 String provider = locationManager.getBestProvider(criteria,true);locationManager.getLastKnownLocation(provider);
locationManager.getBestProvider(criteria,true);方法看起來很完美,但其實傳回值就network、gps二選一。而且如果你要求高精度,它會優先檢查GPS,如果手機開啟了GPS就返回GPS,否則返回network。如果都沒開啟則返回null。
結合Network、GPS兩種定位方式的優劣不難看出為什麼getLastKnownLocation方法會返回null(這隻針對第一次定位)。
當你開啟GPS,provider的值為GPS。這時的定位方式為GPS,由於GPS定位慢(我測試的時間大約為50秒),所以它不可能立即返回你一個Location對象,所以就返回null了。還有人用下面的方法解決這個問題:
while (location ==null) { location = locationManager.getLastKnownLocation(provider); }
這絕對是個愚蠢的做法!舉個例子:如果你在室內,gps無法定位到,你的程式將陷入死迴圈。當然使用requestLocationUpdates可以做到定位且不讓程式陷入死迴圈,但是定位耗時間長度,甚至得不到定位。
如果使用網路定位呢,不得說這也是一個不錯的選擇。locationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER, 0, 0,networkListener);
網路定位耗時一般在2秒左右(網路差,時間會更長),只要你接入網路,基本上都能獲得定位。唯一的缺點就是精度不高。
那能不能將兩者結合,這也是本文的重點。既然結合兩者,就要同時為兩者添加監聽
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,1000 * 2,50,gpsListener);locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0,networkListener);
這樣,大概2秒我們就可以得到來自網路的定位,一分鐘後得到來自GPS定位。這時用GPS定位替換網路定位就好了。當然這隻是個理想的情況,現實要複雜的多。
比如:
你第一次定位成功返回location,由於網路問題第二次返回null。這時會發現,更新的location沒有上次的精確,甚至是null,無法使用,這時我們要判斷當前的location和新獲得的location那個更好。可能你獲得GPS定位後,由於天氣、進入隧道等原因GPS伺服器丟失,無法更新location(這時一個好的做法是切換到network定位)。還有可能使用者沒有開啟GPS和network,根本就談不上定位(其實每次定位成功都會有個定位緩衝的,可以使用getLastKnownLocation獲得)。
終上所述,我們要做的就是:
1. 嘗試通過getLastKnownLocation擷取上次定位資訊
2. 開啟network和gps監聽
3. 獲得network定位資訊location
4. 比較當前location和新擷取的location哪個更好(來自network)
5. 獲得gps定位資訊location
6. 停掉network監聽
7. 比較當前location和新擷取的location哪個更好(來自gps)
8. 如果gps伺服器丟失,重新開啟network監聽
以GPS監聽為例
// GPS監聽的回呼函數 private class GPSLocationListener implements LocationListener { private boolean isRemove = false;//判斷網路監聽是否移除 @Override public void onLocationChanged(Location location) { // TODO Auto-generatedmethod stub boolean flag =betterLocation.isBetterLocation(location, currentBestLocation); if (flag) { currentBestLocation = location; updateLocation(currentBestLocation); } // 獲得GPS服務後,移除network監聽 if (location !=null && !isRemove) { locationManager.removeUpdates(networkListener); isRemove = true; } } @Override public void onProviderDisabled(String provider) { // TODO Auto-generatedmethod stub } @Override public void onProviderEnabled(String provider) { // TODO Auto-generatedmethod stub } @Override public void onStatusChanged(String provider, int status, Bundleextras) { // TODO Auto-generatedmethod stub if (LocationProvider.OUT_OF_SERVICE == status) { Toast.makeText(MainActivity.this,"GPS服務丟失,切換至網路定位", Toast.LENGTH_SHORT).show(); locationManager .requestLocationUpdates( LocationManager.NETWORK_PROVIDER, 0, 0, networkListener); } } }
其中isBetterLocation是用來判斷哪個location更好的。這個方法來自android官網的,通過location擷取的時間,精度等資訊進行判斷。
因為之前上傳的demo,大家覺得意義不大,所以就不再提供了。
的‘微秒’單位錯了,應該是毫秒