基于android的定位無非就兩種:network、gps。兩者各有優(yōu)劣。
Network:定位快,準(zhǔn)確度低,受環(huán)境影響小。
GPS:定位慢,準(zhǔn)確度高,受環(huán)境影響大。
本文要解決的問題:
1.????? locationManager.getLastKnownLocation方法返回null。
2.????? 如何實現(xiàn)快速而又精確的定位。
E文好的話,直接看官網(wǎng)就好了 http://developer.android.com/guide/topics/location/strategies.html
在你的程序里如果有這樣的代碼你就要注意了(現(xiàn)在看來這些倒是多余了)
locationManager.getBestProvider(criteria,true);方法看起來很完美,但其實返回值就network、gps二選一。而且如果你要求高精度,它會優(yōu)先檢查GPS,如果手機開啟了GPS就返回GPS,否則返回network。如果都沒開啟則返回null。
結(jié)合Network、GPS兩種定位方式的優(yōu)劣不難看出為什么getLastKnownLocation方法會返回null(這只針對第一次定位)。
當(dāng)你開啟GPS,provider的值為GPS。這時的定位方式為GPS,由于GPS定位慢(我測試的時間大約為50秒),所以它不可能立即返回你一個Location對象,所以就返回null了。還有人用下面的方法解決這個問題:
這絕對是個愚蠢的做法!舉個例子:如果你在室內(nèi),gps無法定位到,你的程序?qū)⑾萑胨姥h(huán)。當(dāng)然使用requestLocationUpdates可以做到定位且不讓程序陷入死循環(huán),但是定位耗時長,甚至得不到定位。
如果使用網(wǎng)絡(luò)定位呢,不得說這也是一個不錯的選擇。locationManager.requestLocationUpdates(
????????????? LocationManager.NETWORK_PROVIDER, 0, 0,networkListener);
網(wǎng)絡(luò)定位耗時一般在2秒左右(網(wǎng)絡(luò)差,時間會更長),只要你接入網(wǎng)絡(luò),基本上都能獲得定位。唯一的缺點就是精度不高。
那能不能將兩者結(jié)合,這也是本文的重點。既然結(jié)合兩者,就要同時為兩者添加監(jiān)聽
這樣,大概2秒我們就可以得到來自網(wǎng)絡(luò)的定位,一分鐘后得到來自GPS定位。這時用GPS定位替換網(wǎng)絡(luò)定位就好了。當(dāng)然這只是個理想的情況,現(xiàn)實要復(fù)雜的多。
比如:
你第一次定位成功返回location,由于網(wǎng)絡(luò)問題第二次返回null。這時會發(fā)現(xiàn),更新的location沒有上次的精確,甚至是null,無法使用,這時我們要判斷當(dāng)前的location和新獲得的location那個更好。可能你獲得GPS定位后,由于天氣、進(jìn)入隧道等原因GPS服務(wù)器丟失,無法更新location(這時一個好的做法是切換到network定位)。還有可能用戶沒有開啟GPS和network,根本就談不上定位(其實每次定位成功都會有個定位緩存的,可以使用getLastKnownLocation獲得)。
終上所述,我們要做的就是:
1.? 嘗試通過getLastKnownLocation獲取上次定位信息
2.? 開啟network和gps監(jiān)聽
3.? 獲得network定位信息location
4.? 比較當(dāng)前l(fā)ocation和新獲取的location哪個更好(來自network)
5.? 獲得gps定位信息location
6.? 停掉network監(jiān)聽
7.? 比較當(dāng)前l(fā)ocation和新獲取的location哪個更好(來自gps)
8.? 如果gps服務(wù)器丟失,重新開啟network監(jiān)聽
以GPS監(jiān)聽為例
其中isBetterLocation是用來判斷哪個location更好的。這個方法來自android官網(wǎng)的,通過location獲取的時間,精度等信息進(jìn)行判斷。
因為之前上傳的demo,大家覺得意義不大,所以就不再提供了。
下圖的‘微秒’單位錯了,應(yīng)該是毫秒
andriod 自動切換網(wǎng)絡(luò)和gps定位
獲取到位置服務(wù)以后,同時請求網(wǎng)絡(luò)和gps定位更新,然后就會同時上報網(wǎng)絡(luò)和gps的Location 信息。在沒有g(shù)ps信號的時候,會自動獲取網(wǎng)絡(luò)定位的位置信息,如果有g(shù)ps信號,則優(yōu)先獲取gps提供的位置信息.isBetterLocation 根據(jù) 時間、準(zhǔn)確性、定位方式等判斷是否更新當(dāng)前位置信息,該方法來源于開發(fā)指南的Obtaining User Location 下。
Network:定位快,準(zhǔn)確度低,受環(huán)境影響小。
GPS:定位慢,準(zhǔn)確度高,受環(huán)境影響大。
本文要解決的問題:
1.????? locationManager.getLastKnownLocation方法返回null。
2.????? 如何實現(xiàn)快速而又精確的定位。
E文好的話,直接看官網(wǎng)就好了 http://developer.android.com/guide/topics/location/strategies.html
在你的程序里如果有這樣的代碼你就要注意了(現(xiàn)在看來這些倒是多余了)
Criteria criteria = new Criteria(); criteria.setAccuracy(Criteria.ACCURACY_FINE);//高精度 criteria.setAltitudeRequired(false);//無海拔要求 criteria.setBearingRequired(false);//無方位要求 criteria.setCostAllowed(true);//允許產(chǎn)生資費 criteria.setPowerRequirement(Criteria.POWER_LOW);//低功耗 // 獲取最佳服務(wù)對象 String provider = locationManager.getBestProvider(criteria,true); locationManager.getLastKnownLocation(provider);
locationManager.getBestProvider(criteria,true);方法看起來很完美,但其實返回值就network、gps二選一。而且如果你要求高精度,它會優(yōu)先檢查GPS,如果手機開啟了GPS就返回GPS,否則返回network。如果都沒開啟則返回null。
結(jié)合Network、GPS兩種定位方式的優(yōu)劣不難看出為什么getLastKnownLocation方法會返回null(這只針對第一次定位)。
當(dāng)你開啟GPS,provider的值為GPS。這時的定位方式為GPS,由于GPS定位慢(我測試的時間大約為50秒),所以它不可能立即返回你一個Location對象,所以就返回null了。還有人用下面的方法解決這個問題:
while (location ==null) { location = locationManager.getLastKnownLocation(provider); }
這絕對是個愚蠢的做法!舉個例子:如果你在室內(nèi),gps無法定位到,你的程序?qū)⑾萑胨姥h(huán)。當(dāng)然使用requestLocationUpdates可以做到定位且不讓程序陷入死循環(huán),但是定位耗時長,甚至得不到定位。
如果使用網(wǎng)絡(luò)定位呢,不得說這也是一個不錯的選擇。locationManager.requestLocationUpdates(
????????????? LocationManager.NETWORK_PROVIDER, 0, 0,networkListener);
網(wǎng)絡(luò)定位耗時一般在2秒左右(網(wǎng)絡(luò)差,時間會更長),只要你接入網(wǎng)絡(luò),基本上都能獲得定位。唯一的缺點就是精度不高。
那能不能將兩者結(jié)合,這也是本文的重點。既然結(jié)合兩者,就要同時為兩者添加監(jiān)聽
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,1000 * 2,50,gpsListener); locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0,networkListener);
這樣,大概2秒我們就可以得到來自網(wǎng)絡(luò)的定位,一分鐘后得到來自GPS定位。這時用GPS定位替換網(wǎng)絡(luò)定位就好了。當(dāng)然這只是個理想的情況,現(xiàn)實要復(fù)雜的多。
比如:
你第一次定位成功返回location,由于網(wǎng)絡(luò)問題第二次返回null。這時會發(fā)現(xiàn),更新的location沒有上次的精確,甚至是null,無法使用,這時我們要判斷當(dāng)前的location和新獲得的location那個更好。可能你獲得GPS定位后,由于天氣、進(jìn)入隧道等原因GPS服務(wù)器丟失,無法更新location(這時一個好的做法是切換到network定位)。還有可能用戶沒有開啟GPS和network,根本就談不上定位(其實每次定位成功都會有個定位緩存的,可以使用getLastKnownLocation獲得)。
終上所述,我們要做的就是:
1.? 嘗試通過getLastKnownLocation獲取上次定位信息
2.? 開啟network和gps監(jiān)聽
3.? 獲得network定位信息location
4.? 比較當(dāng)前l(fā)ocation和新獲取的location哪個更好(來自network)
5.? 獲得gps定位信息location
6.? 停掉network監(jiān)聽
7.? 比較當(dāng)前l(fā)ocation和新獲取的location哪個更好(來自gps)
8.? 如果gps服務(wù)器丟失,重新開啟network監(jiān)聽
以GPS監(jiān)聽為例
// GPS監(jiān)聽的回調(diào)函數(shù) private class GPSLocationListener implements LocationListener { private boolean isRemove = false;//判斷網(wǎng)絡(luò)監(jiān)聽是否移除 @Override public void onLocationChanged(Location location) { // TODO Auto-generatedmethod stub boolean flag =betterLocation.isBetterLocation(location, currentBestLocation); if (flag) { currentBestLocation = location; updateLocation(currentBestLocation); } // 獲得GPS服務(wù)后,移除network監(jiān)聽 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服務(wù)丟失,切換至網(wǎng)絡(luò)定位", Toast.LENGTH_SHORT).show(); locationManager .requestLocationUpdates( LocationManager.NETWORK_PROVIDER, 0, 0, networkListener); } } }
其中isBetterLocation是用來判斷哪個location更好的。這個方法來自android官網(wǎng)的,通過location獲取的時間,精度等信息進(jìn)行判斷。
private static final int TWO_MINUTES = 1000 * 60 * 2; /** * Determines whether one Location reading is better than the current * Location fix * * @param location * The new Location that you want to evaluate * @param currentBestLocation * The current Location fix, to which you want to compare the new * one */ protected boolean isBetterLocation(Location location, Location currentBestLocation) { if (currentBestLocation == null) { // A new location is always better than no location return true; } // Check whether the new location fix is newer or older long timeDelta = location.getTime() - currentBestLocation.getTime(); boolean isSignificantlyNewer = timeDelta > TWO_MINUTES; boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES; boolean isNewer = timeDelta > 0; // If it's been more than two minutes since the current location, use // the new location // because the user has likely moved if (isSignificantlyNewer) { return true; // If the new location is more than two minutes older, it must be // worse } else if (isSignificantlyOlder) { return false; } // Check whether the new location fix is more or less accurate int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation .getAccuracy()); boolean isLessAccurate = accuracyDelta > 0; boolean isMoreAccurate = accuracyDelta < 0; boolean isSignificantlyLessAccurate = accuracyDelta > 200; // Check if the old and new location are from the same provider boolean isFromSameProvider = isSameProvider(location.getProvider(), currentBestLocation.getProvider()); // Determine location quality using a combination of timeliness and // accuracy if (isMoreAccurate) { return true; } else if (isNewer && !isLessAccurate) { return true; } else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) { return true; } return false; } /** Checks whether two providers are the same */ private boolean isSameProvider(String provider1, String provider2) { if (provider1 == null) { return provider2 == null; } return provider1.equals(provider2); }
因為之前上傳的demo,大家覺得意義不大,所以就不再提供了。
下圖的‘微秒’單位錯了,應(yīng)該是毫秒

andriod 自動切換網(wǎng)絡(luò)和gps定位
獲取到位置服務(wù)以后,同時請求網(wǎng)絡(luò)和gps定位更新,然后就會同時上報網(wǎng)絡(luò)和gps的Location 信息。在沒有g(shù)ps信號的時候,會自動獲取網(wǎng)絡(luò)定位的位置信息,如果有g(shù)ps信號,則優(yōu)先獲取gps提供的位置信息.isBetterLocation 根據(jù) 時間、準(zhǔn)確性、定位方式等判斷是否更新當(dāng)前位置信息,該方法來源于開發(fā)指南的Obtaining User Location 下。
import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; import android.content.Context; import android.location.Address; import android.location.Geocoder; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import cn.tangdada.tangbang.R; public class SecondFragment extends BaseFragment { private TextView tv; LocationManager lm = null; Location myLocation = null; SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSZ"); public SecondFragment() { super(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { super.onCreateView(inflater, container, savedInstanceState); View view = inflater.inflate(R.layout.fragment_second, null); tv = (TextView) view.findViewById(R.id.tv); lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); return view; } @Override public void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); } @Override public void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); } @Override public void onPause() { // TODO Auto-generated method stub super.onPause(); lm.removeUpdates(listener); } @Override public void onResume() { // TODO Auto-generated method stub super.onResume(); lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, listener); lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, listener); } LocationListener listener = new LocationListener() { @Override public void onLocationChanged(Location location) { // 實際上報時間 // String time = sdf.format(new Date(location.getTime())); // timeText.setText("實際上報時間:" + time); if (isBetterLocation(location, myLocation)) { // 獲取緯度 double lat = location.getLatitude(); // 獲取經(jīng)度 double lon = location.getLongitude(); // 位置提供者 String provider = location.getProvider(); // 位置的準(zhǔn)確性 float accuracy = location.getAccuracy(); // 高度信息 double altitude = location.getAltitude(); // 方向角 float bearing = location.getBearing(); // 速度 米/秒 float speed = location.getSpeed(); String locationTime = sdf.format(new Date(location.getTime())); String currentTime = null; if (myLocation != null) { currentTime = sdf.format(new Date(myLocation.getTime())); myLocation = location; } else { myLocation = location; } // 獲取當(dāng)前詳細(xì)地址 StringBuffer sb = new StringBuffer(); if (myLocation != null) { Geocoder gc = new Geocoder(context); List<Address> addresses = null; try { addresses = gc.getFromLocation(myLocation.getLatitude(), myLocation.getLongitude(), 1); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } if (addresses != null && addresses.size() > 0) { Address address = addresses.get(0); sb.append(address.getCountryName() + address.getLocality()); sb.append(address.getSubThoroughfare()); } } tv.setText("經(jīng)度:" + lon + "\n緯度:" + lat + "\n服務(wù)商:" + provider + "\n準(zhǔn)確性:" + accuracy + "\n高度:" + altitude + "\n方向角:" + bearing + "\n速度:" + speed + "\n上次上報時間:" + currentTime + "\n最新上報時間:" + locationTime + "\n您所在的城市:" + sb.toString()); } } @Override public void onStatusChanged(String provider, int status, Bundle extras) { Log.i("tag", "onStatusChanged: " + provider); } @Override public void onProviderEnabled(String provider) { Log.i("tag", "onProviderEnabled: " + provider); } @Override public void onProviderDisabled(String provider) { Log.i("tag", "onProviderDisabled: " + provider); } }; private static final int TWO_MINUTES = 1000 * 1 * 2; /** * Determines whether one Location reading is better than the current Location fix * * @param location The new Location that you want to evaluate * @param currentBestLocation The current Location fix, to which you want to compare the new one */ protected boolean isBetterLocation(Location location, Location currentBestLocation) { if (currentBestLocation == null) { // A new location is always better than no location return true; } // Check whether the new location fix is newer or older long timeDelta = location.getTime() - currentBestLocation.getTime(); boolean isSignificantlyNewer = timeDelta > TWO_MINUTES; boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES; boolean isNewer = timeDelta > 0; // If it's been more than two minutes since the current location, use // the new location // because the user has likely moved if (isSignificantlyNewer) { return true; // If the new location is more than two minutes older, it must be // worse } else if (isSignificantlyOlder) { return false; } // Check whether the new location fix is more or less accurate int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation.getAccuracy()); boolean isLessAccurate = accuracyDelta > 0; boolean isMoreAccurate = accuracyDelta < 0; boolean isSignificantlyLessAccurate = accuracyDelta > 200; // Check if the old and new location are from the same provider boolean isFromSameProvider = isSameProvider(location.getProvider(), currentBestLocation.getProvider()); // Determine location quality using a combination of timeliness and // accuracy if (isMoreAccurate) { return true; } else if (isNewer && !isLessAccurate) { return true; } else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) { return true; } return false; } /** Checks whether two providers are the same */ private boolean isSameProvider(String provider1, String provider2) { if (provider1 == null) { return provider2 == null; } return provider1.equals(provider2); } }
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
