【Android -- SDK】高德地图的使用

1. 简介

高德地图 Android SDK 是一套地图开发调用接口,开发者可以轻松地在自己的Android应用中加入地图相关的功能,包括:地图显示(含室内、室外地图)、与地图交互、在地图上绘制、兴趣点搜索、地理编码、离线地图等功能。

2. 获取高德 Key

要使用高德地图首先要去高德开放平台注册成为开发者(http://lbs.amap.com/), 注册成为高德开发者需要分三步:

  • 第一步,注册高德开发者;
  • 第二步,去控制台创建应用;
  • 第三步,获取Key
    在这里插入图片描述

3. 准备

1. 下载并解压
高德地图SDK - 开发包定制下载

2. 向工程中添加地图开发包
2.1 添加 so 文件,在 src/main/ 目录下新建 jniLibs 目录,并将文件放入其中。
1.png

2.2 将 jar 包放入 libs 目录下。然后 右键-选择 Add As Library,导入到工程中。
2.png

4. 地图

1. 配置 AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.gyq.mapdemo">

    <!--允许程序打开网络套接字-->
    <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" />
    <!--允许程序访问CellID或WiFi热点来获取粗略的位置-->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <meta-data android:name="com.amap.api.v2.apikey"
            android:value="高德key">
        </meta-data>
    </application>

</manifest>

3. 布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

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

</LinearLayout>

4. 只要在 onCreate() 中添加如下几行代码,高德地图就显示出来了

public class MainActivity extends AppCompatActivity {
    private MapView mMapView;
    private AMap mAMap;
    private MyLocationStyle mLocationStyle;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mMapView = findViewById(R.id.map);
        mMapView.onCreate(savedInstanceState);
        if (mAMap == null) {
            mAMap = mMapView.getMap();
        }
        mAMap.getUiSettings().setZoomControlsEnabled(false);
        mAMap.moveCamera(CameraUpdateFactory.zoomTo(15));
        mAMap.setMapTextZIndex(2);


        mLocationStyle = new MyLocationStyle();
        mLocationStyle.interval(2000);
        mLocationStyle.showMyLocation(true);
        mAMap.setMyLocationStyle(mLocationStyle);
        mAMap.setMyLocationEnabled(true);

        mAMap.setOnMyLocationChangeListener(new AMap.OnMyLocationChangeListener() {
            @Override
            public void onMyLocationChange(Location location) {
                double lat = location.getLatitude();
                double lng = location.getLongitude();

                Log.e("duo", "onMyLocationChange: lat=" + lat + "|lng=" + lng);
            }
        });
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        mMapView.onSaveInstanceState(outState);
    }

    @Override
    protected void onResume() {
        super.onResume();
        mMapView.onResume();
    }

    @Override
    protected void onPause() {
        super.onPause();
        mMapView.onPause();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mMapView.onDestroy();
    }
}

5. 定位

//初始化定位
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>

6. Poi搜索

先上效果图:
在这里插入图片描述

  • 实现
    这边已经提供了两个封装好的类,一个是输入提示 一个是Poi搜索
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自身需求对查询错误情况进行相应的提示或者逻辑处理
        }
    }
}
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:

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;
    }
}

RouteTask 代码如下:

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) {}
}
  • 3
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Kevin-Dev

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值