Android高德地圖的使用,狠詳細!手把手!(地圖+定位+逆地理編碼+輸入提示+Poi搜索)

http://www.jianshu.com/p/1ff5203be160

Android高德地圖的使用,狠詳細!手把手!(地圖+定位+逆地理編碼+輸入提示+Poi搜索)

96 
Then丨 
2016.11.18 15:24* 字數 1001 閱讀 7961評論 48

最近項目用到高德地圖,因此來寫一篇文章理一下高德的使用步驟方法,希望對大家有用!

1.註冊+配置

廢話不多說,要使用高德地圖首先要去高德開放平臺註冊成爲開發者(http://lbs.amap.com/), 註冊成爲高德開發者需要分三步:第一步,註冊高德開發者;第二步,去控制檯創建應用;第三步,獲取Key(見下圖,注意看命名規範,SHA1值得獲取網上有!很簡單)。


獲取key


ok之後,到官網下載高德SDK(http://lbs.amap.com/api/android-sdk/download/), 我這邊全部都下載了,解壓後,得到一個 AMap3DMap_xxxxx(版本號).jar 文件和一個 armeabi 文件夾,之後,
(一)將jar包拷貝到你項目的libs目錄下.
(二)在 main 目錄下創建文件夾 jniLibs (如果有就不需要創建了),將armeabi 文件夾複製到這個目錄下,如果已經有這個目錄,將下載的 so 庫複製到這個目錄即可.
見圖(也可以參考高德官網的第二種配置方式):


Studio 配置工程


別忘了添加File依賴:


FileDependencies

好了,前期準備弄好,終於可以上代碼了.

2.地圖

1.在清單文件中配置key:

1  <meta-data android:name="com.amap.api.v2.apikey" 
2  android:value="您申請的Key"></meta-data>

2.配置權限(把下面這堆配置進去,再也不用擔心bug出在權限問題上了):

<!--允許程序打開網絡套接字-->
<uses-permission android:name="android.permission.INTERNET" />
<!--允許程序設置內置sd卡的寫權限-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!--允許程序獲取網絡狀態-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!--允許程序訪問WiFi網絡信息-->
<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>
<!--用於訪問GPS定位-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"></uses-permission>
<!--用於獲取wifi的獲取權限,wifi信息會用來進行網絡定位-->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"></uses-permission>
<!--用於讀取手機當前的狀態-->
<uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>
<!--用於申請調用A-GPS模塊-->
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS"></uses-permission>

3.在佈局文件中加載地圖控件:

<com.amap.api.maps.MapView    
android:id="@+id/map"    
android:layout_width="match_parent"    
android:layout_height="match_parent">
</com.amap.api.maps.MapView>

4.你只要在onCreate()中添加如下幾行代碼,高德地圖就顯示出來了!

MapView mapView = (MapView) findViewById(R.id.map);//找到地圖控件
mapView.onCreate(savedInstanceState);// 此方法必須重寫
AMap aMap = mapView.getMap();//得到一個map對象

是不是很簡單!再此我還是想說下,高德地圖的軟實力和百度地圖是有差距的,但是高德的開發文檔要比百度很人性化!
接下來我們來使用定位功能在地圖上添加點標記玩玩.

3.定位+添加標記

第一種方式(基礎,可參考官網,鏈接在此:http://lbs.amap.com/api/android-location-sdk/guide/android-location/getlocation/):

//初始化定位
mLocationClient = new AMapLocationClient(getApplicationContext());
//初始化AMapLocationClientOption對象
mLocationOption = new AMapLocationClientOption();
//設置定位模式爲高精度模式。
mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
//設置定位回調監聽
mLocationClient.setLocationListener(this);
//獲取一次定位結果
mLocationOption.setOnceLocation(true);
//設置是否返回地址信息(默認返回地址信息)
mLocationOption.setNeedAddress(true);
//給定位客戶端對象設置定位參數
mLocationClient.setLocationOption(mLocationOption);
//啓動定位
mLocationClient.startLocation();

之後在監聽器的回調方法內解析AMapLocation對象,裏面包含地址,省市縣街道,地區編碼,城市編碼等等等,可以在此添加標記,定位當前位置,你問我如何把標記固定在屏幕中央?也在這裏面:

//----------------------這是位置改變監聽------------------------------------    
@Override    
public void onLocationChanged(AMapLocation aMapLocation) {        
      if (aMapLocation != null) {            
          if (aMapLocation.getErrorCode() == 0) {                
              //可在其中解析amapLocation獲取相應內容。                         
              LatLng latLng = new LatLng(aMapLocation.getLatitude(),       
              aMapLocation.getLongitude());//取出經緯度               
             //添加Marker顯示定位位置                
            if (locationMarker == null) {                    
            //如果是空的添加一個新的,icon方法就是設置定位圖標,可以自定義                    
            locationMarker = aMap.addMarker(new MarkerOptions()                           
            .position(latLng).snippet("最快1分鐘到達").draggable(true).setFlat(true));                    
            locationMarker.showInfoWindow();//主動顯示indowindow                    
            aMap.addText(new TextOptions().position(latLng).text(aMapLocation.getAddress()));                    
            //固定標籤在屏幕中央                    
            locationMarker.setPositionByPixels(mMapView.getWidth() / 2,mMapView.getHeight() / 2);                 
        } else {                   
           //已經添加過了,修改位置即可                    
          locationMarker.setPosition(latLng);                
        }                
       //然後可以移動到定位點,使用animateCamera就有動畫效果                
       aMap.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, 15));//參數提示:1.經緯度 2.縮放級別                        
       }else {                          
        //定位失敗時,可通過ErrCode(錯誤碼)信息來確定失敗的原因,errInfo是錯誤信息,詳見錯誤碼錶。                
        Log.e("AmapError","location Error, ErrCode:" +aMapLocation.getErrorCode() + ", errInfo:"+ aMapLocation.getErrorInfo());            
          }       
     }    
}

第二種方式,實現OnMapLoadedListener,在回調方法中首先添加一個標記在地圖中央,之後封裝一個方法,開啓單次定位即可:

aMap.setOnMapLoadedListener(this);
//----------------------OnMapLoaded 當地圖加載完成時回調此方法------------------------------------------    
    @Override
    public void onMapLoaded() {
        MarkerOptions markerOptions = new MarkerOptions();        
        markerOptions.setFlat(true);
        markerOptions.anchor(0.5f, 0.5f);            
        markerOptions.position(new LatLng(0, 0));        
        markerOptions.snippet("最快1分鐘到達").draggable(true).setFlat(true);        
        markerOptions.icon(BitmapDescriptorFactory.fromBitmap(BitmapFactory.decodeResource(getResources(),                                R.drawable.icon_loaction_start)));
        mPositionMark = aMap.addMarker(markerOptions);
        mPositionMark.showInfoWindow();//主動顯示indowindow
        mPositionMark.setPositionByPixels(mMapView.getWidth() / 2,mMapView.getHeight() / 2);
        mLocationTask.startSingleLocate();    }

封裝的單次定位方法在此,很簡單:

//開啓單次定位
public void startSingleLocate() {
    AMapLocationClientOption option=new AMapLocationClientOption();
    option.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
    option.setOnceLocation(true);
    mLocationClient.setLocationOption(option);
    mLocationClient.startLocation();
}

是時候貼張效果圖圖了:


是的,很醜


關於怎麼讓按鈕懸浮在地圖上?也很簡單啊

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <RelativeLayout 
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <com.amap.api.maps.MapView
            android:id="@+id/map"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
        </com.amap.api.maps.MapView>
        <!--導航欄 -->
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:layout_alignParentStart="true"
            android:layout_alignParentTop="true"
            android:orientation="horizontal">
            <ImageView
                android:id="@+id/menu"
                android:layout_width="50dp"
                android:layout_height="wrap_content"
                android:clickable="true"
                android:src="@mipmap/hanbao"/>
            <ImageView
                android:visibility="gone"
                android:id="@+id/btn_back"
                android:layout_width="50dp"
                android:layout_height="wrap_content"
                android:src="@drawable/btn_back"/>
            <Button
                android:layout_centerInParent="true"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:gravity="center"
                android:text="打車/順風車"/>
        </RelativeLayout>
        <ImageView 
           android:id="@+id/iv_location"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:layout_marginRight="16dp"
            android:layout_marginTop="400dp"
            android:layout_above="@+id/fromto_container"
            android:src="@mipmap/btn_location"/>
    </RelativeLayout>
</FrameLayout>

4.地理編碼+逆地理編碼

下面來說一下地理編碼(地址轉座標)/逆地理編碼(座標轉地址)功能,依然很簡單,再次提一下高德人性化的文檔!
地址轉座標實現步驟:

//構造 GeocodeSearch 對象,並設置監聽。
geocodeSearch = new GeocodeSearch(this);
geocodeSearch.setOnGeocodeSearchListener(this);
//通過GeocodeQuery設置查詢參數,調用getFromLocationNameAsyn(GeocodeQuery geocodeQuery) 方法發起請求。
//address表示地址,第二個參數表示查詢城市,中文或者中文全拼,citycode、adcode都ok 
GeocodeQuery query = newGeocodeQuery(address, "010"); 
geocoderSearch.getFromLocationNameAsyn(query);

座標轉地址實現步驟:

geocoderSearch = new GeocodeSearch(this);
geocoderSearch.setOnGeocodeSearchListener(this);//和上面一樣
// 第一個參數表示一個Latlng(經緯度),第二參數表示範圍多少米,第三個參數表示是火系座標系還是GPS原生座標系
RegeocodeQuery query = newRegeocodeQuery(latLonPoint, 200,GeocodeSearch.AMAP); 
geocoderSearch.getFromLocationAsyn(query);

之後再回調方法中解析即可:

//------------------------座標轉地址/座標轉地址的監聽回調-------------------------
//result裏面有你想要的結果.
    @Override
    public void onRegeocodeSearched(RegeocodeResult result, int rCode) {
       result.getGeocodeAddressList().get(0).getLatLonPoint();
    }
    @Override
    public void onGeocodeSearched(GeocodeResult result, int rCode) {
       result.getRegeocodeAddress().getFormatAddress();
    }

5.輸入提示+Poi搜索

最後是搜索提示+Poi搜索功能:
先上效果圖:


Poi搜索


實現步驟:
這邊已經提供了兩個封裝好的類,一個是輸入提示 一個是Poi搜索

import android.content.Context;import android.util.Log;
import com.amap.api.services.core.AMapException;
import com.amap.api.services.help.Inputtips;
import com.amap.api.services.help.Inputtips.InputtipsListener;
import com.amap.api.services.help.Tip;
import java.util.ArrayList;import java.util.List;
/**
   * ClassName:InputTipTask <br/>
   * Function: 簡單封裝了Inputtips的搜索服務,將其餘提示的adapter進行數據綁定
   * @author   yiyi.qi   * @version     * @since    JDK 1.6   * @see  */
public class InputTipTask implements InputtipsListener {
    private static InputTipTask mInputTipTask;
    private Inputtips mInputTips;
    private RecomandAdapter mAdapter;
    Context mContext;
    public static InputTipTask getInstance(Context context, RecomandAdapter adapter){
        if(mInputTipTask==null){
            mInputTipTask=new InputTipTask(context);
        }        //單例情況,多次進入DestinationActivity傳進來的RecomandAdapter對象會不是同一個
        mInputTipTask.setRecommandAdapter(adapter);
        return mInputTipTask;
    }
    public void setRecommandAdapter(RecomandAdapter adapter){
        mAdapter=adapter;
    }
    private InputTipTask(Context context ){
        mInputTips=new Inputtips(context, this);
        }
    public void searchTips(String keyWord, String city){
        try {
            mInputTips.requestInputtips(keyWord, city);
        } catch (AMapException e) {
            e.printStackTrace();    
    }    
}
    @Override
    public void onGetInputtips(List<Tip> tips, int resultCode) {
        //v3.2.1及以上版本SDK 返回碼1000是正常 千萬注意
        if(resultCode==1000&&tips!=null){
            ArrayList<PositionEntity> positions=new ArrayList<PositionEntity>();
            for(Tip tip:tips){
                //經緯度 address city(adcode)
                positions.add(new PositionEntity(0, 0, tip.getName(),tip.getAdcode()));
            }
            mAdapter.setPositionEntities(positions);
            mAdapter.notifyDataSetChanged();
            PoiSearchTask poiSearchTask=new PoiSearchTask(mContext.getApplicationContext(), mAdapter);
                for(int i = 0;i<positions.size();i++){
                    PositionEntity entity = (PositionEntity)
                    mAdapter.getItem(i);
                    poiSearchTask.search(entity.address,RouteTask.getInstance(mContext.getApplicationContext()).getStartPoint().city);
                }
        }else {
            //可以根據app自身需求對查詢錯誤情況進行相應的提示或者邏輯處理
        }
    }
}
import android.content.Context;
import com.amap.api.services.core.PoiItem;
import com.amap.api.services.poisearch.PoiResult;
import com.amap.api.services.poisearch.PoiSearch;
import com.amap.api.services.poisearch.PoiSearch.OnPoiSearchListener;
import com.amap.api.services.poisearch.PoiSearch.Query;
import java.util.ArrayList;import java.util.List;
/** 
 * ClassName:PoiSearchTask <br/>
 * Function: 簡單封裝了poi搜索的功能,搜索結果配合RecommendAdapter進行使用顯示 <br/>
 * @author yiyi.qi * @version * @since JDK 1.6 * @see */
public class PoiSearchTask implements OnPoiSearchListener {
    private Context mContext;
    private RecomandAdapter mRecommandAdapter;
    public PoiSearchTask(Context context, RecomandAdapter recomandAdapter) {
        mContext = context;
        mRecommandAdapter = recomandAdapter;
    }
    public void search(String keyWord, String city) {
        Query query = new PoiSearch.Query(keyWord, "", city);
        query.setPageSize(10);
        query.setPageNum(0);
        PoiSearch poiSearch = new PoiSearch(mContext, query);
        poiSearch.setOnPoiSearchListener(this);
        poiSearch.searchPOIAsyn();
    }
    @Override
    public void onPoiSearched(PoiResult poiResult, int resultCode) {
        if (resultCode == 1000 && poiResult != null) {
            ArrayList<PoiItem> pois=poiResult.getPois();
            if(pois==null){
                return;
            }
            List<PositionEntity> entities=new ArrayList<PositionEntity>();
            for(PoiItem poiItem:pois){
                PositionEntity entity=new PositionEntity(poiItem.getLatLonPoint().getLatitude(),
                poiItem.getLatLonPoint().getLongitude(),
                poiItem.getTitle(),poiItem.getCityName());
                entities.add(entity);
            }
            mRecommandAdapter.setPositionEntities(entities);
            mRecommandAdapter.notifyDataSetChanged();
        }
        //TODO 可以根據app自身需求對查詢錯誤情況進行相應的提示或者邏輯處理
    }
    @Override
    public void onPoiItemSearched(PoiItem poiItem, int i) {}}

你要做的 只是拷貝這連個類到工程中,然後在搜索的Activity中實現TextWatcher接口後,進行如下調用:

//在onTextChanged方法中調用InputTipTask 的getInstance方法
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
       if (RouteTask.getInstance(getApplicationContext()).getStartPoint() == null) {
       Toast.makeText(getApplicationContext(), "檢查網絡,Key等問題", Toast.LENGTH_SHORT).show();
       return;
}
InputTipTask.getInstance(getApplicationContext(), mRecomandAdapter).searchTips(s.toString(),
        RouteTask.getInstance(getApplicationContext()).getStartPoint().city);
}

輸入提示完成.如果你希望點選後進行更詳細的Poi搜索,也只需在相應位置調用:

//生成poiSearchTask對象
PoiSearchTask poiSearchTask=new PoiSearchTask(getApplicationContext(),mRecomandAdapter);
//開始進行POI搜索
poiSearchTask.search(mDestinaionText.getText().toString(),RouteTask.getInstance(getApplicationContext()).getStartPoint().city);

以上需要一個位置的實體Bean:

/** 
* ClassName:PositionEntity <br/>
 * Function: 封裝的關於位置的實體 <br/>
 * @author yiyi.qi * @version * @since JDK 1.6
 * @see */
public class PositionEntity {
    @Override
    public String toString() {
        return "PositionEntity{" + 
               "latitue=" + latitue + 
               ", longitude=" + longitude +
                ", address='" + address + '\'' + 
               ", city='" + city + '\'' + 
               '}'; 
   }
    public double latitue;
    public double longitude;
    public String address;
    public String city;
    public PositionEntity() {}
    public PositionEntity(double latitude, double longtitude, String address, String city) {
        this.latitue = latitude;
        this.longitude = longtitude;
        this.address = address;
        this.city = city;
    }
}

之後會帶來導航相關文章,如果哪裏不懂或者寫的不對的地方可以聯繫我!有不足之處還請多多包涵!謝謝
最後貼一個地址,如果有用到聚合Marker的可以傳送到此,很詳細:
http://lbsbbs.amap.com/forum.php?mod=viewthread&tid=1459

應評論要求,貼上RouteTask代碼如下:

import android.content.Context;
import android.util.Log;

import com.amap.api.services.core.LatLonPoint;
import com.amap.api.services.route.BusRouteResult;
import com.amap.api.services.route.DrivePath;
import com.amap.api.services.route.DriveRouteResult;
import com.amap.api.services.route.RideRouteResult;
import com.amap.api.services.route.RouteSearch;
import com.amap.api.services.route.RouteSearch.DriveRouteQuery;
import com.amap.api.services.route.RouteSearch.FromAndTo;
import com.amap.api.services.route.RouteSearch.OnRouteSearchListener;
import com.amap.api.services.route.WalkRouteResult;
import com.guibinchuxing.hutens.guestgoout.bean.PositionEntity;

import java.util.ArrayList;
import java.util.List;

/**
 * ClassName:RouteTask <br/>
 * Function: 封裝的駕車路徑規劃 <br/>
 * Date: 2015年4月3日 下午2:38:10 <br/>
 * 
 * @author yiyi.qi
 * @version
 * @since JDK 1.6
 * @see
 */
public class RouteTask implements OnRouteSearchListener {

    private static RouteTask mRouteTask;

    private RouteSearch mRouteSearch;

    private PositionEntity mFromPoint;

    private PositionEntity mToPoint;

    private List<OnRouteCalculateListener> mListeners = new ArrayList<OnRouteCalculateListener>();
    private DrivePath drivepath;

    public interface OnRouteCalculateListener {
        public void onRouteCalculate(float cost, float distance, int duration,DrivePath drivepath);

    }

    public static RouteTask getInstance(Context context) {
        if (mRouteTask == null) {
            mRouteTask = new RouteTask(context);
        }
        return mRouteTask;
    }

    public PositionEntity getStartPoint() {
        return mFromPoint;
    }

    public void setStartPoint(PositionEntity fromPoint) {
        mFromPoint = fromPoint;
    }

    public PositionEntity getEndPoint() {
        return mToPoint;
    }

    public void setEndPoint(PositionEntity toPoint) {
        mToPoint = toPoint;
    }

    private RouteTask(Context context) {
        mRouteSearch = new RouteSearch(context);
        mRouteSearch.setRouteSearchListener(this);
    }

    public void search() {
        if (mFromPoint == null || mToPoint == null) {
            return;
        }
        Log.e(":", "search: "+mFromPoint+","+mToPoint);

        FromAndTo fromAndTo = new FromAndTo(new LatLonPoint(mFromPoint.latitue,
                mFromPoint.longitude), new LatLonPoint(mToPoint.latitue,
                mToPoint.longitude));
        DriveRouteQuery driveRouteQuery = new DriveRouteQuery(fromAndTo,
                RouteSearch.DrivingDefault, null, null, "");

        mRouteSearch.calculateDriveRouteAsyn(driveRouteQuery);
    }

    public void search(PositionEntity fromPoint, PositionEntity toPoint) {

        mFromPoint = fromPoint;
        mToPoint = toPoint;
        search();

    }

    public void addRouteCalculateListener(OnRouteCalculateListener listener) {
        synchronized (this) {
            if (mListeners.contains(listener))
                return;
            mListeners.add(listener);
        }
    }

    public void removeRouteCalculateListener(OnRouteCalculateListener listener) {
        synchronized (this) {
            mListeners.add(listener);
        }
    }


    //駕車路線規劃回調
    @Override
    public void onDriveRouteSearched(DriveRouteResult driveRouteResult,
            int resultCode) {
        if (resultCode == 1000 && driveRouteResult != null) {
            synchronized (this) {
                for (OnRouteCalculateListener listener : mListeners) {

                    List<DrivePath> drivepaths = driveRouteResult.getPaths();
                    float distance = 0;
                    int duration = 0;
                    if (drivepaths.size() > 0) {
                             drivepath = drivepaths.get(0);

                        distance = drivepath.getDistance() / 1000;

                        duration = (int) (drivepath.getDuration() / 60);
                    }

                    float cost = driveRouteResult.getTaxiCost();

                    listener.onRouteCalculate(cost, distance, duration,drivepath);
                }
                   List<DrivePath> paths = driveRouteResult.getPaths();


               }
        }
        //這裏可以根據需求對查詢錯誤情況進行相應的提示或者邏輯處理
    }
    @Override
    public void onWalkRouteSearched(WalkRouteResult arg0, int arg1) {}
    @Override
    public void onRideRouteSearched(RideRouteResult rideRouteResult, int i) {}
    @Override
    public void onBusRouteSearched(BusRouteResult arg0, int arg1) {}
}

發佈了107 篇原創文章 · 獲贊 187 · 訪問量 114萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章