Google Map API v2 步步為營 (二)----- Location


接上篇。

改造一下MapsActivity:

public class MapsActivity extends Activity implements LocationListener, InfoWindowAdapter, OnMarkerClickListener, OnMarkerDragListener{
}

實現4個interface:

android.location.LocationListener

GoogleMap.InfoWindowAdapter

GoogleMap.OnMarkerClickListener

GoogleMap.OnMarkerDragListener

本篇要實現在地圖上定位,主要用到LocationListener接口。

另外3個接口關系到 打標記(Marker),移動標記點,以及點擊標記彈出info窗口。這些功能將在下一篇文中整理。   

 

地圖初始化

首先在onCreate中需要對地圖對象做一些設置:

@Override
public void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.map);

    ........
            
    if(servicesConnected()){
        initMapView();
    }
}

 

servicesConnected 檢查service是否可用

private boolean servicesConnected() {
    // Check that Google Play services is available
    int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
    // If Google Play services is available
    if(ConnectionResult.SUCCESS == resultCode) {
        log("Google Play services is available.");
        isServiceOk = true;
    } else {
        // Get the error code
        ConnectionResult connectionResult = new ConnectionResult(resultCode, null);
        int errorCode = connectionResult.getErrorCode();
        // Get the error dialog from Google Play services
        Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog(
                    errorCode,
                    this,
                    RESULT_CODE_SERVICE_FAILURE);

        // If Google Play services can provide an error dialog
        if(errorDialog != null) {
            errorDialog.show();
        }
        isServiceOk = false;
    }
    return isServiceOk;
}

上一篇說過,手機調試環境需要安裝Google Play服務和play store。如果沒有安裝,這里就會返回錯誤碼。

 

initMapView 初始化

1 private void initMapView(){
2     mMapView = ((MapFragment)getFragmentManager().findFragmentById(R.id.map_view)).getMap();
3     mMapView.setMapType(GoogleMap.MAP_TYPE_NORMAL);
4 
5     UiSettings setting = mMapView.getUiSettings();
6     setting.setTiltGesturesEnabled(true);
7     //setting.setCompassEnabled(false);
8 }
9     

2行,獲得地圖對象 GoogleMap mMapView;后面很多操作都要通過它。

3行,設在地圖模式為normal

4行,UiSettings 設置人機交互相關的各種按鈕手勢等待,例如:

void setTiltGesturesEnabled(boolean)  是否允許手勢改變視角;

void setCompassEnabled(boolean)  是否顯示指南針;

詳細的UiSettings用法可參考官文 https://developers.google.com/maps/documentation/android/reference/com/google/android/gms/maps/UiSettings

 

移動到經緯度地點

先闡明一個概念,Goolge Map假定地圖本身是固定不動的,移動的是camera(public final class CameraUpdate)。

想象一下,在地球上空漂浮着一只佳能無敵兔,把鏡頭對准魔都,焦距拉近看到了一號線,再拉遠,視角傾斜一下,看到了魔都全貌,還是帶廣角的。不錯吧!

 

回到代碼,這里需要用的GPS。通過LocationManager來獲得位置服務

mLocManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
mGPSOk = mLocManager.isProviderEnabled(LocationManager.GPS_PROVIDER);

獲得LocationManager,並檢查GPS是否可用。

在onResume函數中注冊監聽

 1 @Override
 2 protected void onResume(){
 3     super.onResume();
 4     if(isServiceOk == false)
 5         return;
 6 
 7     String provider = getBestProvider();
 8     if(provider != null){
 9        mLocManager.requestLocationUpdates(provider, 5*1000, 1, this);
10     }
11 
12     updateCurrentLoction();
13     setLatLng();
14 }

7行,獲得可用的Location Provider,開啟GPS的情況下這里得到的是GPS provider

9行,注冊位置變化監聽。第二入參5*1000表示每隔5秒更新一次,第三入參表示移動超過1米更新一次。最后一個入參即LocationListener,由於activity implement了LocationListener,所以這里只需要給activity的this指針。

12行和13行的兩個函數,用於主動獲取最新位置,移動地圖到該位置,稍后貼出。

先看一下位置變化的監聽函數,activity在implement了LocationListener后 需要實現一下幾個函數:

 1 /* LocationListener begin */
 2 @Override
 3 public void onLocationChanged(Location newLoction) {
 4     if(mLocation != null){
 5         mLocation.setLatitude(newLoction.getLatitude());
 6         mLocation.setLongitude(newLoction.getLongitude());
 7         animateLatLng();
 8     }
 9 }
10 
11 @Override
12 public void onProviderDisabled(String arg0) {
13     // TODO Auto-generated method stub    
14 }
15 @Override
16 public void onProviderEnabled(String arg0) {
17     // TODO Auto-generated method stub    
18 }
19 @Override
20 public void onStatusChanged(String arg0, int arg1, Bundle arg2) {
21 }
22 /* LocationListener end */

3~9行,我這里只處理了onLocationChanged,這個函數在location發生變化時會調用到。

我們用了一個私有數據:private Location mLocation = null;

onLocationChanged函數中,把新的location保存到mLocation中,然后調用animateLatLng把地圖移動到該位置。

=================================================================

mLocation用於記錄每次更新的經緯度,建議在onPause的時候把這個數據保存到本地,我是保存在preference中的。在onResume時讀出來。

這樣可以避免gps不可用的時候,地圖飛回非洲。

當然也可一增加一個對network provider的監聽,通過網絡獲取不太准確的位置,這部份我沒做完整。

因為火星坐標系的問題,我最后換了baidu map,google map的這個apk很多后續的優化就沒做了,汗吧!

=================================================================

有時我們需要主動查詢最新的Location

 1  2 private void updateCurrentLoction(){
 3     String bestProvider = getBestProvider();
 4     Location  newLoction = null;
 5 
 6     if(bestProvider != null)
 7         newLoction = mLocManager.getLastKnownLocation(bestProvider);
 8 
 9     if(mLocation == null){
10         mLocation = new Location("");
11     }
12 
13     if(newLoction != null){
14         mLocation.setLatitude(newLoction.getLatitude());
15         mLocation.setLongitude(newLoction.getLongitude());
16     }
17 }

3行,獲取最優的provider

7行,獲取最近一次的location

8~16行,同樣的,新位置記錄到mLocation中。

getBestProvider函數體如下:

private String getBestProvider(){      
    Criteria criteria = new Criteria();
    criteria.setPowerRequirement(Criteria.POWER_LOW);
    criteria.setAccuracy(Criteria.ACCURACY_FINE);
    String bestOne = mLocManager.getBestProvider(criteria, true);
    return bestOne;
}

 

上文用到的兩個函數setLatLng()和animateLatLng()

 

 1 private void setLatLng(boolean marked){
 2     if(mLocation == null){
 3         Toast.makeText(this, R.string.gpserr, Toast.LENGTH_LONG).show();
 4         return;
 5     }
 6 
 7     double dLat = mLocation.getLatitude();
 8     double dLong = mLocation.getLongitude();
 9     log("setLatLng: (" + dLat + "," + dLong + ")");
10 
11     //LatLng latlng = new LatLng(31.13893, 121.39668);
12     LatLng latlng = new LatLng(dLat, dLong);
13     if((latlng.latitude == 0) && (latlng.longitude == 0)){
14         //mMapView.moveCamera(CameraUpdateFactory.newLatLng(latlng));
15     }else{
16         mMapView.moveCamera(CameraUpdateFactory.newLatLngZoom(latlng, 15));
17     }
18 }
19 
20 private void animateLatLng(boolean guide){
21     if(mLocation == null){
22         Toast.makeText(this, R.string.gpserr, Toast.LENGTH_LONG).show();
23         return;
24     }
25         
26     double dLat = mLocation.getLatitude();
27     double dLong = mLocation.getLongitude();
28     log("animateLatLng: (" + dLat + "," + dLong + ")");
29     LatLng latlng = new LatLng(dLat, dLong);
30         
31     mMapView.animateCamera(CameraUpdateFactory.newLatLng(latlng));        
32 }

 

先看第一個setLatLng()

7~8行,從mLocation中調用getLatitude()取得維度,getLongitude()取得經度。

12行,構造一個LatLng對象

16行, mMapView.moveCamera(CameraUpdateFactory.newLatLngZoom(latlng, 15));

CameraUpdateFactory.newLatLngZoom(latlng, 15) 返回一個CameraUpdate對象,入參是經緯度和zoom level;

GoogleMap的moveCamera方法把地圖移動到該位置。

animateLatLng()函數

31行  基本相同,唯一的區別是最后調用的是animateCamera,我們會看到地圖從原location移動到新location的過程。而moveCamera方法是瞬移過去的,不會看到移動過程。

CameraUpdate有很多中構造方法,可以單獨或同時指定位置和放大倍數。指定邊界等待,詳見

https://developers.google.com/maps/documentation/android/reference/com/google/android/gms/maps/CameraUpdateFactory

 

 

最后,要在onPause函數中注銷位置服務監聽

mLocManager.removeUpdates(this);

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM