1. 程式人生 > >google map 接入指南——定位

google map 接入指南——定位

最近專案中有用到了google map,故寫下接入google map的心得;由於國內的地圖在海外無法使用,所以當你的應用是海外使用,則不得不考慮使用google map。


google map 基本環境搭建

環境搭建可以參考文章 點選這裡 或者  官方文件;然後我想說的是google map 申請key的時候,不要加限制,比如包名限制,這樣在除錯的時候比較方便;第二,在使用地圖的時候,要翻牆才行。(總的來說獲取key,就是到console.cloud.google.com 然後去設定一下)

 

定位功能

說到定位,android 可以用sdk中Location 實現,也可以藉助play service中的map去實現(這裡要手機安裝play services app);前者實現沒有限制,藉助GPS(高精度)和網路(低精度)實現定位,手機系統的GPS設定開關,網路是依靠連線的基站實現的。記得加上許可權:<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> ,這個許可權包含了<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />,所以只需申請第一個就可以了。

第一種方式:Android api:android.Location包下的實現

public Location getGpsInfo(Context context) {
        Location location = null;
        try{
            Criteria criteria = new Criteria();
            criteria.setAccuracy(Criteria.ACCURACY_COARSE);//低精度,如果設定為高精度,依然獲取不了location。
            criteria.setAltitudeRequired(false);//不要求海拔
            criteria.setBearingRequired(false);//不要求方位
            criteria.setCostAllowed(true);//允許有花費
            criteria.setPowerRequirement(Criteria.POWER_LOW);//低功耗

            LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
            //從可用的位置提供器中,匹配以上標準的最佳提供器
            if(locationManager != null){
                String locationProvider = locationManager.getBestProvider(criteria, true);
                location = locationManager.getLastKnownLocation(locationProvider);
            }
           
        }catch (SecurityException e){
            e.printStackTrace();
        }

        return location;
    }

或者是兩個分開來寫:用GPS獲取,NetWork獲取,當一種獲取不到的時候換另一種方式;

/**
     * GPS獲取定位方式
     */
    public static Location getGPSLocation(@NonNull Context context) {
        Location location = null;
        LocationManager manager = getLocationManager(context);
        //高版本的許可權檢查
        if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return null;
        }
        if (manager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {//是否支援GPS定位
            //獲取最後的GPS定位資訊,如果是第一次開啟,一般會拿不到定位資訊,一般可以請求監聽,在有效的時間範圍可以獲取定位資訊
            location = manager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
        }
        return location;
    }

    /**
     * network獲取定位方式
     */
    public static Location getNetWorkLocation(Context context) {
        Location location = null;
        LocationManager manager = getLocationManager(context);
        //高版本的許可權檢查
        if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return null;
        }
        if (manager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {//是否支援Network定位
            //獲取最後的network定位資訊
            location = manager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
        }
        return location;
    }

或則

locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
            lastKnownLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
            if (lastKnownLocation == null){
                locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);
                lastKnownLocation = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
            }

其實和上面的一樣,注意一點,當用戶關閉了GPS定位服務,裝置聯網後(wifi或移動資料)仍然可以定位的,這時候可以進行檢查並提醒使用者進行開啟定位服務,獲取更精確的定位:

 Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
 startActivityForResult(intent, GPS_REQUEST_CODE);


private boolean checkGPSIsOpen() {
    boolean isOpen;
    LocationManager locationManager = (LocationManager) this
            .getSystemService(Context.LOCATION_SERVICE);
    isOpen = locationManager.isProviderEnabled(android.location.LocationManager.GPS_PROVIDER);
    return isOpen;
}

第二種方式:用play service中的api獲取(也是官方推薦的方式),但有個缺點要安裝google 服務,翻牆,但這樣很多國產手機都不行,華為,三星都試過,google的pixel手機可以的,不知道什麼原因。所以很蛋疼....

一、用FusedLocationProviderClient實現,

例項化
FusedLocationProviderClientmFusedLocationProviderClient =  LocationServices.getFusedLocationProviderClient(this);

 //獲取位置  在點選定位按鈕或者是onMapReady之後
 Task locationResult = mFusedLocationProviderClient.getLastLocation();

mFusedLocationProviderClient.requestLocationUpdates( mLocationRequest, mLocationCallback,  null);

    private void createLocationRequest(){
        mLocationRequest = LocationRequest.create();
        mLocationRequest.setInterval(10000); //5 seconds
        mLocationRequest.setFastestInterval(5000); //3 seconds
        mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    }

 LocationCallback mLocationCallback = new LocationCallback() {
                @Override
                public void onLocationResult(LocationResult locationResult) {
                    if (locationResult == null) {
                        return;
                    }
                    for (Location location : locationResult.getLocations()) {
                        if (location != null) {
                            //TODO: UI updates.
                            Log.d(TAG, "onLocationResult: " + location.toString());
                        }
                    }
                }
            };

二、mGoogleApiClient 實現,官方文件連線 點選 ;

    @Override
    public void onConnected(@Nullable Bundle bundle) {
      
        Location mLastLocation = null;
        try {
            mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
        } catch (SecurityException e) {
            e.printStackTrace();
        }


// 在onMapReady中呼叫連線和建立物件
 mGoogleApiClient.connect();


//在onMapReady中建立mGoogleApiClient  例項物件
 mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();

上面的2種方法均是google 推薦的,但是在國產手機基本不行,上面已說過,原因不明。最後還是推薦第一種provider的方式;

地理反編碼

在進行到定位後,我們需要把地理編碼經緯度換成生活中人們使用的地址,這時候就需要用到地理反編碼了,相關參考文件官方文件。注意這是耗時任務,要在子執行緒進行,否則介面會出現卡頓現象。具體程式碼展現:

/**
     * 逆地理編碼 耗時任務 需要子執行緒進行
     * @param latitude
     * @param longitude
     * @return
     */
    public String getAddress(double latitude, double longitude) {
        Geocoder geocoder = new Geocoder(mActivity, Locale.getDefault());
        try {
            List<Address> address = geocoder.getFromLocation(latitude, longitude, 1);
            LogUtil.debugLog("onCameraChange", "得到位置當前" + address + "'\n"
                    + "經度:" + String.valueOf(address.get(0).getLongitude()) + "\n"
                    + "緯度:" + String.valueOf(address.get(0).getLatitude()) + "\n"
                    + "緯度:" + "國家:" + address.get(0).getCountryName() + "\n"
                    + "code"  + address.get(0).getCountryCode() +"\n"
                    + "城市:" + address.get(0).getLocality() + "\n"
                    + "名稱:" + address.get(0).getAddressLine(1) + "\n"
                    + "街道:" + address.get(0).getAddressLine(0)
            );
            //+ "  " + address.get(0).getLocality() + " " + address.get(0).getCountryName()
            return address.get(0).getAddressLine(0) ;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

這時候,拿到你想要的資訊,如果定位可以根據address.get(0).getCountryCode 來判斷國家,這樣就實現定位功能了。

 

參考資料:

另外,附上相應的學習文件:

https://developer.android.com/training/location/

https://developers.google.com/maps/documentation/android-sdk/location

https://developers.google.com/maps/documentation/android-sdk/current-place-tutorial

https://developers.google.com/android/reference/com/google/android/gms/maps/GoogleMap 這是相應的google play service裡面的服務api

SDK Location的介紹: 

https://developer.android.com/guide/topics/location/strategies

https://developer.android.com/reference/android/location/Location