[應用代碼] 實現Android的不一樣精度的定位(基於網絡和GPS)

在本教程中,我會分別講述如何開啓位置服務的監聽,如何中止監聽,如何得到不一樣精度的定位,以及如何判判定位是否更精確。
Android中的定位服務的相關類基本上都在android.location包中,下面會按編寫的順序依次講解。

位置服務管理器(LocationManager)
首先,咱們須要1個LocationManager,考慮到它會被多個方法使用,咱們將它定義成Activity的Field。而後在onCreate方法中爲它賦值。



1
2
3
4
5

    //變量定義
    private LocationManager locationManager;
    //獲得LocationManager
    locationManager = (LocationManager) this
            .getSystemService(Context.LOCATION_SERVICE)




開啓位置服務的監聽
有了LocationManager以後,咱們就能夠開始監聽位置的變化了。咱們使用LocationManager中的方法:
requestLocationUpdates(String provider, long minTime, float minDistance, LocationListener listener)
來設置監聽器。
首先,咱們要注意到第1個參數,這個參數的值爲2選1,分別是:LocationManager.NETWORK_PROVIDER和LocationManager.GPS_PROVIDER,前者用於移動網絡中獲取位置,精度較低但速度很快,後者使用GPS進行定位,精度很高但通常須要10-60秒時間才能開始第1次定位,若是是在室內則基本上沒法定位。
這2種Provider本質上是互補的,在本教程中,咱們會同時開啓2個監聽,但基於移動網絡的監聽只會執行一次就會被中止,而基於GPS的監聽則會一直持續下去,直至用戶本身中止監聽。
代碼片斷以下:
首先,咱們會聲明1個監聽器的內部類,這個類會同時用於2種模式的監聽。還要聲明1個變量,用於記錄當前的位置。





1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

private class MyLocationListner implements LocationListener{
    @Override
    public void onLocationChanged(Location location) {
        // Called when a new location is found by the location provider.
        Log.v("GPSTEST", "Got New Location of provider:"+location.getProvider());
        if(currentLocation!=null){
            if(isBetterLocation(location, currentLocation)){
                Log.v("GPSTEST", "It's a better location");
                currentLocation=location;
                showLocation(location);
            }
            else{
                Log.v("GPSTEST", "Not very good!");
            }
        }
        else{
            Log.v("GPSTEST", "It's first location");
            currentLocation=location;
            showLocation(location);
        }
        //移除基於LocationManager.NETWORK_PROVIDER的監聽器
        if(LocationManager.NETWORK_PROVIDER.equals(location.getProvider())){
            locationManager.removeUpdates(this);
        }
    }

    //後3個方法此處不作處理
    public void onStatusChanged(String provider, int status, Bundle extras) {
    }

    public void onProviderEnabled(String provider) {
    }

    public void onProviderDisabled(String provider) {
    }
};
Location currentLocation;
private void showLocation(Location location){
    //緯度
    Log.v("GPSTEST","Latitude:"+location.getLatitude());
    //經度
    Log.v("GPSTEST","Longitude:+location.getLongitude());
    //精確度
    Log.v("GPSTEST","Accuracy:"+location.getAccuracy());
    //Location還有其它屬性,請自行探索
}



開始監聽的代碼片斷:



       
1
2
3
4
5
6
7
8

    private LocationListener gpsListener=null;
    private LocationListener networkListner=null;
    private void registerLocationListener(){
        networkListner=new MyLocationListner();
        locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 3000, 0, networkListner);
        gpsListener=new MyLocationListner();
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 5000, 0, gpsListener);
    }




以上的代碼仍是很易懂的吧,建立1個監聽器對象,而後指定1個provider,而後requestLocationUpdates。在監聽器中檢查若是是NETWORK_PROVIDER,則取消監聽,只留GPS的監聽(在你的實際應用中能夠根據狀況來進行,由於GPS有可能會由於建築的阻擋而暫時不工做)。
位置精度的判斷在showLocation方法中,咱們打印了location的Accuracy屬性,這就是精確度,通常來講NETWORK獲得的位置精度通常在500-1000米,GPS獲得的精度通常在5-50米,基於這個屬性咱們能夠對精度進行判斷,以決定是否採用這個精度。
你可能已經注意到上面的代碼中有1個isBetterLocation方法,這是用來判斷獲取的位置是否更好,事實上這個方法來自於Dev Guide。咱們看下這個方法的內容:





1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

private static final int CHECK_INTERVAL = 1000 * 30;
    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 > CHECK_INTERVAL;
        boolean isSignificantlyOlder = timeDelta < -CHECK_INTERVAL;
        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);
    }




從代碼中能夠很清楚的看出判斷位置是否「更好」的準則,不只使用了精度(getAccuracy()),還使用了時間進行判斷。事實上除了在導航應用,其它的時候都可以直接使用上面的這個方法來對位置更新信息進行過濾,以減小不斷更新界面而帶來的性能損失。
結束監聽只須要調用LocationManager對象的removeUpdates(LocationListener listener)方法就能夠中止監聽。事實上,在以前的代碼中你已經看到咱們移除了基於移動網絡的監聽器,下面的代碼片斷用於移除GPS監聽器。




   
1
2
3
4

    if(gpsListener!=null){
        locationManager.removeUpdates(gpsListener);
        gpsListener=null;
    }




LocationManager的其它使用這裏還要介紹LocationManager中的幾個方法:
getLastKnownLocation(String provider),用於獲得上次定位時的最後位置,一般在應用剛啓動時馬上獲得1個位置,這樣應用看上去會比較快。
getBestProvider(Criteria criteria, boolean enabledOnly),根據條件(精度的高低,是否可以獲得海拔等)以及當前是否開啓,獲得1個最好的位置Provider。看上去很美,但如今的Android系統中只有2個Provider,而大多數用戶的GPS都是開啓的,在僅僅是2選1的狀況我想像不出這個方法的用途。而即使用戶關閉了GPS,咱們也有能力幫他開啓,用完了以後再關掉它。開啓的方法見《進階:如何編程實現開啓或關閉GPS?》。
總結2個Provider提供了不一樣精度的定位服務,咱們能夠根據狀況來使用。 通常來講,先使用NETWORK來獲得1個精度較差的位置,再使用GPS來獲得更準確的位置。 在Android官方提供的Dev Guide中,提供了一個關於GPS使用的時間線,咱們來看一下
相關文章
相關標籤/搜索