Android開發之高德地圖實現定位

yungfan發表於2016-04-05
在應用開發中,地圖開發是經常需要使用的“元件”,Google Map雖然有官方教程,無奈用不起來,原因你懂的~~那麼國內比較出名的是就是百度地圖和高德地圖,由於個人喜好,所以選擇了高德地圖LBS,廢話不說,上乾貨。

1、註冊開發者,建立應用

這個幾乎是所有開放平臺都通用的做法,無外乎註冊帳號,成為開發者,然後建立一個Android應用,會為你分配一個key繫結你的服務。

img_a0f1489cb130eb79b32840bc25d05e81.png
註冊key.PNG
2、下載SDK,匯入jar包,add to library
img_b0d5919931f249499686d0aedee4ad6c.png
jar包.PNG
  • 第一個是2D地圖的jar包,因為最後定位以後我要在地圖上標出來位置
  • 第二個是用於定位的jar包
  • 注意:如果使用的是3D地圖,那麼地圖SDK和導航SDK需要引入so庫檔案,先在app/src/main/目錄下新建一個jniLibs目錄,將so放到此目錄下
3、配置AndroidMainfest.xml檔案
<!-- 申請必要的許可權-->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />

<application
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme"

        >
        <!--設定key-->
        <meta-data
            android:name="com.amap.api.v2.apikey"
            android:value="這裡填寫第一步你申請的那個key" />
        <!--宣告定位service-->
        <service android:name="com.amap.api.location.APSService"></service>
</application>
4、Activity的佈局檔案
<com.amap.api.maps2d.MapView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/map"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" />

很簡單,就一個2D的地圖

5、Activity,註釋非常詳細
//監聽定位和定位變化
public class MainActivity extends AppCompatActivity implements  LocationSource, AMapLocationListener {

    //顯示地圖需要的變數
    private MapView mapView;//地圖控制元件
    private AMap aMap;//地圖物件


    //定位需要的宣告
    private AMapLocationClient mLocationClient = null;//定位發起端
    private AMapLocationClientOption mLocationOption = null;//定位引數
    private OnLocationChangedListener mListener = null;//定位監聽器

    //標識,用於判斷是否只顯示一次定位資訊和使用者重新定位
    private boolean isFirstLoc = true;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //顯示地圖
        mapView = (MapView) findViewById(R.id.map);
        //必須要寫
        mapView.onCreate(savedInstanceState);
        //獲取地圖物件
        aMap = mapView.getMap();


        //設定顯示定位按鈕 並且可以點選
        UiSettings settings = aMap.getUiSettings();
        //設定定位監聽
        aMap.setLocationSource(this);
        // 是否顯示定位按鈕
        settings.setMyLocationButtonEnabled(true);
        // 是否可觸發定位並顯示定位層
        aMap.setMyLocationEnabled(true);


        //定位的小圖示 預設是藍點 這裡自定義一團火,其實就是一張圖片
        MyLocationStyle myLocationStyle = new MyLocationStyle();
        myLocationStyle.myLocationIcon(BitmapDescriptorFactory.fromResource(R.mipmap.firetwo));
        myLocationStyle.radiusFillColor(android.R.color.transparent);
        myLocationStyle.strokeColor(android.R.color.transparent);
        aMap.setMyLocationStyle(myLocationStyle);

        //開始定位
        initLoc();


    }


    //定位
    private void initLoc() {
        //初始化定位
        mLocationClient = new AMapLocationClient(getApplicationContext());
        //設定定位回撥監聽
        mLocationClient.setLocationListener(this);
        //初始化定位引數
        mLocationOption = new AMapLocationClientOption();
        //設定定位模式為高精度模式,Battery_Saving為低功耗模式,Device_Sensors是僅裝置模式
        mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
        //設定是否返回地址資訊(預設返回地址資訊)
        mLocationOption.setNeedAddress(true);
        //設定是否只定位一次,預設為false
        mLocationOption.setOnceLocation(false);
        //設定是否強制重新整理WIFI,預設為強制重新整理
        mLocationOption.setWifiActiveScan(true);
        //設定是否允許模擬位置,預設為false,不允許模擬位置
        mLocationOption.setMockEnable(false);
        //設定定位間隔,單位毫秒,預設為2000ms
        mLocationOption.setInterval(2000);
        //給定位客戶端物件設定定位引數
        mLocationClient.setLocationOption(mLocationOption);
        //啟動定位
        mLocationClient.startLocation();
    }


    //定位回撥函式
    @Override
    public void onLocationChanged(AMapLocation amapLocation) {

        if (amapLocation != null) {
            if (amapLocation.getErrorCode() == 0) {
                //定位成功回撥資訊,設定相關訊息
                amapLocation.getLocationType();//獲取當前定位結果來源,如網路定位結果,詳見官方定位型別表
                amapLocation.getLatitude();//獲取緯度
                amapLocation.getLongitude();//獲取經度
                amapLocation.getAccuracy();//獲取精度資訊
                SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                Date date = new Date(amapLocation.getTime());
                df.format(date);//定位時間
                amapLocation.getAddress();//地址,如果option中設定isNeedAddress為false,則沒有此結果,網路定位結果中會有地址資訊,GPS定位不返回地址資訊。
                amapLocation.getCountry();//國家資訊
                amapLocation.getProvince();//省資訊
                amapLocation.getCity();//城市資訊
                amapLocation.getDistrict();//城區資訊
                amapLocation.getStreet();//街道資訊
                amapLocation.getStreetNum();//街道門牌號資訊
                amapLocation.getCityCode();//城市編碼
                amapLocation.getAdCode();//地區編碼

                // 如果不設定標誌位,此時再拖動地圖時,它會不斷將地圖移動到當前的位置
                if (isFirstLoc) {
                    //設定縮放級別
                    aMap.moveCamera(CameraUpdateFactory.zoomTo(17));
                    //將地圖移動到定位點
                    aMap.moveCamera(CameraUpdateFactory.changeLatLng(new LatLng(amapLocation.getLatitude(), amapLocation.getLongitude())));
                    //點選定位按鈕 能夠將地圖的中心移動到定位點
                    mListener.onLocationChanged(amapLocation);
                    //新增圖釘
                    aMap.addMarker(getMarkerOptions(amapLocation));
                    //獲取定位資訊
                    StringBuffer buffer = new StringBuffer();
                    buffer.append(amapLocation.getCountry() + "" + amapLocation.getProvince() + "" + amapLocation.getCity() + "" + amapLocation.getProvince() + "" + amapLocation.getDistrict() + "" + amapLocation.getStreet() + "" + amapLocation.getStreetNum());
                    Toast.makeText(getApplicationContext(), buffer.toString(), Toast.LENGTH_LONG).show();
                    isFirstLoc = false;
                }


            } else {
                //顯示錯誤資訊ErrCode是錯誤碼,errInfo是錯誤資訊,詳見錯誤碼錶。
                Log.e("AmapError", "location Error, ErrCode:"
                        + amapLocation.getErrorCode() + ", errInfo:"
                        + amapLocation.getErrorInfo());

                Toast.makeText(getApplicationContext(), "定位失敗", Toast.LENGTH_LONG).show();
            }
        }
    }

    //自定義一個圖釘,並且設定圖示,當我們點選圖釘時,顯示設定的資訊
    private MarkerOptions getMarkerOptions(AMapLocation amapLocation) {
         //設定圖釘選項
        MarkerOptions options = new MarkerOptions();
        //圖示
        options.icon(BitmapDescriptorFactory.fromResource(R.mipmap.fire));
        //位置
        options.position(new LatLng(amapLocation.getLatitude(), amapLocation.getLongitude()));
        StringBuffer buffer = new StringBuffer();
        buffer.append(amapLocation.getCountry() + "" + amapLocation.getProvince() + "" + amapLocation.getCity() +  "" + amapLocation.getDistrict() + "" + amapLocation.getStreet() + "" + amapLocation.getStreetNum());
        //標題
        options.title(buffer.toString());
        //子標題
        options.snippet("這裡好火");
        //設定多少幀重新整理一次圖片資源
        options.period(60);

        return options;

    }
    //啟用定位
    @Override
    public void activate(OnLocationChangedListener listener) {
        mListener = listener;

    }

    //停止定位
    @Override
    public void deactivate() {
        mListener = null;
    }


    /**
     * 方法必須重寫
     */
    @Override
    protected void onResume() {
        super.onResume();
        mapView.onResume();
    }

    /**
     * 方法必須重寫
     */
    @Override
    protected void onPause() {
        super.onPause();
        mapView.onPause();
    }

    /**
     * 方法必須重寫
     */
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        mapView.onSaveInstanceState(outState);
    }

    /**
     * 方法必須重寫
     */
    @Override
    protected void onDestroy() {
        super.onDestroy();
        mapView.onDestroy();
    }
}

6、執行程式,點選自定義的 “火” 圖釘,效果圖如下:
img_99a5b67140f39a1d0b0d22abc091d233.png
Location Result.png
7、長按地圖截圖並儲存圖片

Activity實現AMap.OnMapLongClickListener和AMap.OnMapLongClickListener介面,
然後Activity的宣告變為:

public class MainActivity extends AppCompatActivity implements AMap.OnMapLongClickListener, AMap.OnMapScreenShotListener, LocationSource, AMapLocationListener 

分別實現下列兩個的方法

    /**
     * 長按地圖進行截圖
     *
     * @param latLng
     */
    @Override
    public void onMapLongClick(LatLng latLng) {

        // 設定截圖監聽介面,擷取地圖可視區域
        // 需要傳入一個 AMap.OnMapLongClickListener 介面的實現者
        aMap.getMapScreenShot(this);
    }
  /**
     * 截圖回撥方法 儲存截圖
     */

    @Override
    public void onMapScreenShot(Bitmap bitmap) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        try {
            // 儲存在SD卡根目錄下,圖片為png格式。
            FileOutputStream fos = new FileOutputStream(
                    Environment.getExternalStorageDirectory() + "/test_"
                            + sdf.format(new Date()) + ".png");
            boolean b = bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
            try {
                fos.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (b)

                Toast.makeText(MainActivity.this, "截圖成功", Toast.LENGTH_LONG).show();
            else {
                Toast.makeText(MainActivity.this, "截圖失敗", Toast.LENGTH_LONG).show();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

2016.8.26 補充
有很多簡友按照如上過程走下來,發現實現不了我的效果,因此我總結了可能的原因:

1、AndroidMainfest.xml 裡一定要將自己申請的key放進去;
2、申請key時有個SHA-1的,千萬不能錯,錯了也不能定位,因為一旦錯了,就無法識別是你當前的應用了;
3、如果你使用的是3D的圖,務必要將3D的庫導進專案,我的案例是2D的;
4、一定要在真機測試。

有無法定位的簡友,請按照上述錯誤原因來排查,如果還有問題,可以留言~~~


相關文章