Android 高德地图的定位,周边搜索

Posted 狗剩砸

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 高德地图的定位,周边搜索相关的知识,希望对你有一定的参考价值。

刚弄完这两个功能,当然是结合官网例子实现的。效果还行,稍作优化便可整合到app使用。在这里做一下总结,及说明下我的思路。

刚开始上手感觉比较乱学起来也比较累,方法,类太多,直接复制各种错,还不知道为什么这么做。现在我们一起交流下实现的思路:

1:定位:这是所有地图功能实现的基础,所以不管要实现诸如周边搜索啊,导航啊什么的都需要基于定位。
如何定位:官网上例子也很详细,主要是实现几个监听,并实现方法:

    aMap.setLocationSource(this);// 设置定位监听
            //绑定监听
            mapLocationClient.setLocationListener(this);
            //开启定位
            mapLocationClient.startLocation();

监听的实现方法:

public void onLocationChanged(AMapLocation aMapLocation)

定位实现:

//激活定位的重写
public void activate(OnLocationChangedListener onLocationChangedListener)
//取消定位的重写
public void deactivate()

定位成功与否会有返回码,返回码对照如下(来自官网):

0 定位成功。
1 一些重要参数为空,如context;请对定位传递的参数进行非空判断。
2 定位失败,由于仅扫描到单个wifi,且没有基站信息。
3 获取到的请求参数为空,可能获取过程中出现异常。
4 请求服务器过程中的异常,多为网络情况差,链路不通导致,请检查设备网络是否通畅。
5 返回的XML格式错误,解析失败。
6 定位服务返回定位失败,如果出现该异常,请将errorDetail信息通过[email protected]反馈给我们。
7 KEY建权失败,请仔细检查key绑定的sha1值与apk签名sha1值是否对应。
8 android exception通用错误,请将errordetail信息通过[email protected]反馈给我们。
9 定位初始化时出现异常,请重新启动定位。
10 定位客户端启动失败,请检查AndroidManifest.xml文件是否配置了APSService定位服务
11 定位时的基站信息错误,请检查是否安装SIM卡,设备很有可能连入了伪基站网络。
12 缺少定位权限,请在设备的设置中开启app的定位权限。

2:搜索,周边搜索 :有了定位,便有了搜索里面的要求的条件(经纬度等),然后就可以慢慢实现功能了。
搜索功能靠一下方法和监听:

PoiSearch.Query query=PoiSearch.Query(keyWord,type,city);
PoiSearch poiSearch = new PoiSearch(this,query);
poiSearch.setOnPoiSearchListener(this);//设置回调数据的监听器
poiSearch.searchPOIAsyn();//开始搜索

监听的回调方法:

public void onPoiSearched(PoiResult poiResult, int i) 
public void onPoiItemSearched(PoiItem poiItem, int i)

搜索返回码对照(来自官网)本文最后:

实例:
功能介绍:定位,周边搜索(可选择搜索范围:1000-5000米(spinner下拉实现))

代码:
清单文件:

<!-- 用于进行网络定位 -->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <!-- 用于访问GPS定位 -->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <!-- 获取运营商信息,用于支持提供运营商信息相关的接口 -->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <!-- 用于访问wifi网络信息,wifi信息会用于进行网络定位 -->
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <!-- 这个权限用于获取wifi的获取权限,wifi信息会用来进行网络定位 -->
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
    <!-- 用于访问网络,网络定位需要上网 -->
    <uses-permission android:name="android.permission.INTERNET" />
    <!-- 用于读取手机当前的状态 -->
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <!-- 写入扩展存储,向扩展卡写入数据,用于写入缓存定位数据 -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!--与activity标签同级-->
<meta-data
            android:name="com.amap.api.v2.apikey"
            android:value="你的key值" />
        <service android:name="com.amap.api.location.APSService" />

布局:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <EditText
        android:id="@+id/search_edit"
        android:hint="输入关键字"
        android:singleLine="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@+id/map" />
    <Spinner
        android:id="@+id/juli"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@+id/map"
        android:layout_toEndOf="@+id/search_button">

    </Spinner>
    <Button
        android:id="@+id/search_button"
        android:text="搜索"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_toEndOf="@+id/search_edit" />
    <Button
        android:id="@+id/next"
        android:text="下一页(笔者该功能未实现)"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_alignParentEnd="true" />
    <com.amap.api.maps.MapView
        android:id="@+id/map"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignEnd="@+id/next"
        android:layout_below="@+id/search_button">
    </com.amap.api.maps.MapView>

</RelativeLayout>

activity:

package com.inext.test.gaodemap;

import android.app.ProgressDialog;
import android.content.res.Configuration;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.Window;
import android.view.inputmethod.EditorInfo;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;

import com.amap.api.location.AMapLocation;
import com.amap.api.location.AMapLocationClient;
import com.amap.api.location.AMapLocationClientOption;
import com.amap.api.location.AMapLocationListener;
import com.amap.api.maps.AMap;
import com.amap.api.maps.AMapException;
import com.amap.api.maps.AMapUtils;
import com.amap.api.maps.LocationSource;
import com.amap.api.maps.MapView;
import com.amap.api.maps.model.Marker;
import com.amap.api.maps.model.NaviPara;
import com.amap.api.maps.overlay.PoiOverlay;
import com.amap.api.services.core.LatLonPoint;
import com.amap.api.services.core.PoiItem;
import com.amap.api.services.core.SuggestionCity;
import com.amap.api.services.poisearch.PoiResult;
import com.amap.api.services.poisearch.PoiSearch;

import java.util.List;

public class MainActivity extends AppCompatActivity implements LocationSource,AMapLocationListener , View.OnClickListener,PoiSearch.OnPoiSearchListener, AMap.OnMarkerClickListener, AMap.InfoWindowAdapter {

    private Button button1;
    private AMap aMap;
    private OnLocationChangedListener  mListener;
    private MapView mMapView;
    //声明AMapLocationClient类对象
    public AMapLocationClient mapLocationClient;
    //声明AMapLocationClientOption对象
    public AMapLocationClientOption mapLocationClientOption;
    ////////
    private ProgressDialog progDialog = null;// 搜索时进度条
    private String keyWord;
    private PoiSearch.Query query;// Poi查询条件类
    private PoiSearch poiSearch;//搜索
    private PoiSearch.SearchBound searchBound;
    private int currentPage;// 当前页面,从0开始计数
    private PoiResult poiResults; // poi返回的结果
    private String city = "";//搜索城市
    private EditText editText1;
    private LatLonPoint latLonPoint;
    private Spinner spinner;
    private int juli = 1000;
    ////////
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getSupportActionBar().hide();
        setContentView(R.layout.activity_main);
        mMapView = (MapView)findViewById(R.id.map);
        //在activity执行onCreate时执行mMapView.onCreate(savedInstanceState),实现地图生命周期管理
        mMapView.onCreate(savedInstanceState);
        init();
    }

    private void init(){

        if (aMap==null){
            aMap = mMapView.getMap();
        }
        setUp();
    }

    private void setUp() {

        aMap.setLocationSource(this);// 设置定位监听
        aMap.getUiSettings().setMyLocationButtonEnabled(true);// 设置默认定位按钮是否显示
        // 设置为true表示显示定位层并可触发定位,false表示隐藏定位层并不可触发定位,默认是false
        aMap.setMyLocationEnabled(true);
        // 设置定位的类型为定位模式 ,可以由定位、跟随或地图根据面向方向旋转几种
        aMap.setMyLocationType(AMap.LOCATION_TYPE_LOCATE);

        button1 = (Button) findViewById(R.id.search_button);
        button1.setOnClickListener(this);
        spinner = (Spinner)findViewById(R.id.juli);
        String[] ints = {"1000","2000","3000","4000","5000"};
        ArrayAdapter adapter = new ArrayAdapter(this,android.R.layout.simple_dropdown_item_1line,ints);
        spinner.setAdapter(adapter);
        spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                juli = Integer.valueOf(String.valueOf(spinner.getSelectedItem()));
                Log.i("---",juli-10+"");
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {

            }
        });
        editText1 = (EditText) findViewById(R.id.search_edit);

        //editText1.addTextChangedListener(this);
        aMap.setOnMarkerClickListener(this);
        aMap.setInfoWindowAdapter(this);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //在activity执行onDestroy时执行mMapView.onDestroy(),实现地图生命周期管理
        mMapView.onDestroy();
        mapLocationClient.onDestroy();
    }
    @Override
    protected void onResume() {
        super.onResume();
        //在activity执行onResume时执行mMapView.onResume (),实现地图生命周期管理
        mMapView.onResume();
    }
    @Override
    protected void onPause() {
        super.onPause();
        //在activity执行onPause时执行mMapView.onPause (),实现地图生命周期管理
        mMapView.onPause();
    }
    @Override
    protected void onStop() {
        super.onStop();
        mapLocationClient.stopLocation();
    }
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        //在activity执行onSaveInstanceState时执行mMapView.onSaveInstanceState (outState),实现地图生命周期管理
        mMapView.onSaveInstanceState(outState);
    }
    @Override
    public void onLocationChanged(AMapLocation aMapLocation) {
        if (aMapLocation!=null){
            if (aMapLocation.getErrorCode()==0){

                mListener.onLocationChanged(aMapLocation);// 显示系统小蓝点

                StringBuilder stringBuilder = new StringBuilder();
                //定位成功回调信息,设置相关消息
                int type = aMapLocation.getLocationType();
                String address = aMapLocation.getAddress();
                stringBuilder.append(type+address);
                city = aMapLocation.getCity();
                //获得小点
                if (latLonPoint==null){
                    latLonPoint = new LatLonPoint(aMapLocation.getLatitude(),aMapLocation.getLongitude());
                }else {
                    latLonPoint.setLatitude(aMapLocation.getLatitude());
                    latLonPoint.setLongitude(aMapLocation.getLongitude());
                }
                //Toast.makeText(this,stringBuilder.toString(),Toast.LENGTH_SHORT).show();
            }else {
                //显示错误信息ErrCode是错误码,errInfo是错误信息,详见下方错误码表。
                Log.i("erro info:",aMapLocation.getErrorCode()+"---"+aMapLocation.getErrorInfo());
            }
        }
    }
    //激活定位
    @Override
    public void activate(OnLocationChangedListener onLocationChangedListener) {
        mListener = onLocationChangedListener;
        if (mapLocationClient==null){
            //初始化AMapLocationClient,并绑定监听
            mapLocationClient = new AMapLocationClient(getApplicationContext());

            //初始化定位参数
            mapLocationClientOption = new AMapLocationClientOption();
            //设置定位精度
            mapLocationClientOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
            //是否返回地址信息
            mapLocationClientOption.setNeedAddress(true);
            //是否只定位一次
            mapLocationClientOption.setOnceLocation(false);
            //设置是否强制刷新WIFI,默认为强制刷新
            mapLocationClientOption.setWifiActiveScan(true);
            //是否允许模拟位置
            mapLocationClientOption.setMockEnable(false);
            //定位时间间隔
            mapLocationClientOption.setInterval(2000);
            //给定位客户端对象设置定位参数
            mapLocationClient.setLocationOption(mapLocationClientOption);
            //绑定监听
            mapLocationClient.setLocationListener(this);
            //开启定位
            mapLocationClient.startLocation();
        }

    }
    //停止定位
    @Override
    public void deactivate() {
        mListener = null;
        if (mapLocationClient!=null){
            mapLocationClient.stopLocation();
            mapLocationClient.onDestroy();
        }
        mapLocationClient = null;
    }
    long firstTime = 0;
    //双击退出
    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        if (keyCode==KeyEvent.KEYCODE_BACK){
            long secondTime = System.currentTimeMillis();
            if (secondTime-firstTime>2000){
                Toast.makeText(this,"再按一次退出",Toast.LENGTH_SHORT).show();
                firstTime = System.currentTimeMillis();
                return true;
            }else {
                finish();
            }
        }
        return super.onKeyUp(keyCode, event);
    }
    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        if (newConfig.orientation==Configuration.ORIENTATION_LANDSCAPE){
            Log.d("=========", "横屏");
        }else {
            Log.d("=========", "竖屏");
        }
    }
    /**
     * 点击搜索按钮
     */
    private void search(){
        keyWord = editText1.getText().toString();
        Log.i("---", keyWord);
        if ("".equals(keyWord)){
            Toast.makeText(MainActivity.this, "请输入搜索关键字",Toast.LENGTH_SHORT).show();
            return;
        }else {
            doSearchQuery();
        }
    }
    /**
     * 搜索操作
     */
    private void doSearchQuery() {
        showProgressDialog();
        currentPage = 0;
        //第一个参数表示搜索字符串,第二个参数表示poi搜索类型,第三个参数表示poi搜索区域(空字符串代表全国)
        query = new PoiSearch.Query(keyWord,"",city);
        query.setPageSize(10);// 设置每页最多返回多少条poiitem
        query.setPageNum(currentPage);// 设置查第一页
        poiSearch = new PoiSearch(this,query);
        poiSearch.setOnPoiSearchListener(this);//设置回调数据的监听器
        //点附近2000米内的搜索结果
        if (latLonPoint!=null){
            searchBound = new PoiSearch.SearchBound(latLonPoint,juli);
            poiSearch.setBound(searchBound);
        }
        poiSearch.searchPOIAsyn();//开始搜索
    }
    /**
     * 显示进度框
     */
    private void showProgressDialog() {
        if (progDialog == null)
            progDialog = new ProgressDialog(this);
        progDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
        progDialog.setIndeterminate(false);
        progDialog.setCancelable(false);
        progDialog.setMessage("正在搜索:\n" + keyWord);
        progDialog.show();
    }

    /**
     * 隐藏进度框
     */
    private void dissmissProgressDialog() {
        if (progDialog != null) {
            progDialog.dismiss();
        }
    }


    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.search_button:
                Log.i("---","搜索操作");
                search();
                break;
        }
    }
    /**
     * poi没有搜索到数据,返回一些推荐城市的信息
     */
    private void showSuggestCity(List<SuggestionCity> cities) {
        String infomation = "推荐城市\n";
        for (int i = 0; i < cities.size(); i++) {
            infomation += "城市名称:" + cities.get(i).getCityName() + "城市区号:"
                    + cities.get(i).getCityCode() + "城市编码:"
                    + cities.get(i).getAdCode() + "\n";
        }
        Toast.makeText(MainActivity.this, infomation,Toast.LENGTH_SHORT).show();

    }


    /**
     * POI信息查询回调方法
     */
    @Override
    public void onPoiSearched(PoiResult poiResult, int i) {
        dissmissProgressDialog();// 隐藏对话框
        if (i == 1000) {
            Log.i("---","查询结果:"+i);
            if (poiResult != null && poiResult.getQuery() != null) {// 搜索poi的结果
                if (poiResult.getQuery().equals(query)) {// 是否是同一条
                    poiResults = poiResult;
                    // 取得搜索到的poiitems有多少页
                    List<PoiItem> poiItems = poiResult.getPois();// 取得第一页的poiitem数据,页数从数字0开始
                    List<SuggestionCity> suggestionCities = poiResult
                            .getSearchSuggestionCitys();// 当搜索不到poiitem数据时,会返回含有搜索关键字的城市信息

                    if (poiItems != null && poiItems.size() > 0) {
                        aMap.clear();// 清理之前的图标
                        PoiOverlay poiOverlay = new PoiOverlay(aMap, poiItems);
                        poiOverlay.removeFromMap();
                        poiOverlay.addToMap();
                        poiOverlay.zoomToSpan();
                    } else if (suggestionCities != null
                            && suggestionCities.size() > 0) {
                        showSuggestCity(suggestionCities);
                    } else {
                        Toast.makeText(MainActivity.this, "未找到结果",Toast.LENGTH_SHORT).show();
                    }
                }
            } else {
                Toast.makeText(MainActivity.this, "该距离内没有找到结果",Toast.LENGTH_SHORT).show();
            }
        } else {
            Log.i("---","查询结果:"+i);
            Toast.makeText(MainActivity.this, "异常代码---"+i,Toast.LENGTH_SHORT).show();
        }

    }

    @Override
    public void onPoiItemSearched(PoiItem poiItem, int i) {

    }

    @Override
    public boolean onMarkerClick(Marker marker) {
        marker.showInfoWindow();
        return false;
    }
    /**
     * 调起高德地图导航功能,如果没安装高德地图,会进入异常,可以在异常中处理,调起高德地图app的下载页面
     */
    public void startAMapNavi(Marker marker) {
        // 构造导航参数
        NaviPara naviPara = new NaviPara();
        // 设置终点位置
        naviPara.setTargetPoint(marker.getPosition());
        // 设置导航策略,这里是避免拥堵
        naviPara.setNaviStyle(NaviPara.DRIVING_AVOID_CONGESTION);

        // 调起高德地图导航
        try {
            AMapUtils.openAMapNavi(naviPara, getApplicationContext());
        } catch (AMapException e) {

            // 如果没安装会进入异常,调起下载页面
            AMapUtils.getLatestAMapApp(getApplicationContext());

        }

    }
    @Override
    public View getInfoWindow(final Marker marker) {
        View view = getLayoutInflater().inflate(R.layout.poikeywordsearch_uri,
                null);
        TextView title = (TextView) view.findViewById(R.id.title);
        title.setText(marker.getTitle());

        TextView snippet = (TextView) view.findViewById(R.id.snippet);
        snippet.setText(marker.getSnippet());
        ImageButton button = (ImageButton) view
                .findViewById(R.id.start_amap_app);
        // 调起高德地图app
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startAMapNavi(marker);
            }
        });
        return view;
    }

    @Override
    public View getInfoContents(Marker marker) {
        return null;
    }
}

注意: 为了更好的对问题进行排查, 自 Android 搜索 SDK V3.2.1 版本,搜索回调接口返回响应
码已经变更,详细见下面表格。
响应码 说明及排查方法 错误码来源
1000 请求正常 公用错误码,来源于
高德服务
1001 开发者签名未通过。
开发者在 key 控制台中,开启了“ 数字签名” 功能,但没有按照指
定算法生成“ 数字签名” 。 现阶段发生在 web 服务 API 和智能硬
件定位的 key。
1002 用户 key 不正确或过期。
a、 目前网站现有产品,仅支持 2014 年 9 月 23 日之后申请的 key。
b、对照开发指南配置功能,检查 key 添加是否正确。
1003 没有权限使用相应的接口。
请检查使用的 key、与使用的接口是否匹配。
1008 绑定的 SHA1 与包名不一致。
请检查 SHA1、包名是否正确,论坛链接
http://lbsbbs.amap.com/forum.php?mod=viewthread&tid=
10894&extra=&page=1
1009 请求 key 与绑定平台不符。
请确认申请的 key,适用于 Android 平台 SDK。
1012 权限不足,服务请求被拒绝。
如果申请的 Android 平台 SDK,请确认 key 调用是否正常。如有
问题,可通过邮件 [email protected]、论坛反馈给高德开放平台。
1013 开发者删除了 key,key 被删除后无法正常使用。
1100 引擎服务响应错误。
1101 引擎返回数据异常。
1102 高德服务端请求链接超时
1103 读取服务结果返回超时。
1200 请求参数非法
请求参数的值没有按照规范要求填写。例如,某参数值域范围为
[1,3],开发者传了’4’
1201 请求条件中,缺少必填参数。
1202 服务请求协议非法
1203 服务端未知错误
1800 服务端新增错误,如有问题,可通过邮件 [email protected]、 论
坛反馈给高德开放平台。
公用错误码,来源于
SDK 本地错误
1801 协议解析错误
1802 socket 连接超时 - SocketTimeoutException
1803 url 异常 - MalformedURLException
1804 未知主机 - UnKnowHostException
1806 http 或 socket 连接失败 - ConnectionException
1900 未知错误
1901 参数无效
1902 IO 操作异常 - IOException
1903 空指针异常 - NullPointException
2000 Tableid 格式不正确。 云检索返回错误码,
来源于高德服务
2001 ID 不存在,请检查。
2002 云检索服务器维护中
2003 key 对应的 tableID 不存在,请检查。
2100 找不到对应的 userid 信息,请检查您提供的 userid 是否存在。 附近功能返回错误
2101 App key 未开通“ 附近” 功能,请登录 码,来源于高德服务
http://lbs.amap.com/console/bind 进行开通。
2200 已开启自动上传 附近功能返回错误
码,来源于 SDK 本
地错误
2201 USERID 非法(UserID 为空、包含非法字符、长度超过 32 位或与
前次上传的 UserID 不同)
2202 NearbyInfo 对象为空
2203 两次单次上传的间隔低于 7 秒
2204 Point 为空,或与前次上传的相同
3000 规划点(包括起点、终点、途经点)不在中国陆地范围内 路径规划功能返回
错误码,来源于高德
服务端
3001 规划点(包括起点、终点、途经点)附近搜不到路
3002 路线计算失败,通常是由于道路连通关系导致
3003 步行算路起点、终点距离过长导致算路失败。
4000 短串分享认证失败,请通过邮件 [email protected]、 论坛等方式
反馈给高德开放平台。
短串分享功能返回,
来源于高德服务端
4001 短串请求失败。

以上是关于Android 高德地图的定位,周边搜索的主要内容,如果未能解决你的问题,请参考以下文章

高德怎么定位一个地方搜附近的影院

百度地图实现普通地图定位周边搜索功能

高德android定位sdk 2.4.0 支持android2.2吗

启动高德地图后如何自动定位我的位置

android高德地图怎么根据坐标定位

android开发如何用高德地图进行模拟定位.