高德技术 | 实践安卓集中营

利用高德地图API打造基于LBS的Android应用

2016-11-25  本文已影响2089人  RumbleTsc

最近做了一个小的项目,主要功能是获取用户的定位等相关数据用于分析,在开发过程中使用了高德地图SDK,这里结合自己遇到的问题总结一些常见的API的用法,方便以后参考使用。

一、申请Key
二、配置工程
三、定位SDK的使用
四、地图SDK的使用
五、总结

使用高德地图SDK的步骤主要如下:

高德开放平台上注册成为开发者很简单,容易出现问题的是key的获取,下面具体来说。

一、申请Key

在使用高德地图相关SDK前,我们必须先申请Key。这步如果获取不正确,那么后面肯定会出现问题。

申请Key

上面这张图是申请Key时的界面,Package是我们应用的包名,其中容易出现问题的是SHA1码的获取。

官网上面给出的获取SHA1码的方法有好几种,我使用的是第三种。需要注意的是,调试版本(debug)和发布版本(release)下的 SHA1 值是不同的,发布 apk 时需要根据发布 apk 对应的 keystore 重新配置 Key。如果我们的App没有进行签名,那么就获取调试版本下的SHA1码。

使用 keytool(jdk自带工具)获取 SHA1码的过程如下:

1、运行进入控制台

Paste_Image.png

2、在弹出的控制台窗口中输入 cd .android 定位到 .android 文件夹。

Paste_Image.png

3、继续在控制台输入命令。

调试版本使用命令为:keytool -list -v -keystore debug.keystore
发布版本使用命令为:keytool -list -v -keystore apk的keystore

4、提示输入密钥库密码,开发模式默认密码是android,发布模式的密码是为apk的keystore设置的密码。输入密钥后回车(如果没设置密码,可直接回车),此时可在控制台显示的信息中获取 Sha1 值。

到这里,我们已经获取到SHA1码了,填好后点击提交即可获取到Key。

二、配置工程

总的来说,配置工程需要以下几步:

高德地图的SDK有好几种,我们根据自己的需要来选择下载然后配置到工程里,如果只是单纯地需要定位的功能,而不需要展示地图界面,那么可以只下载使用定位SDK,否则就需要添加3D地图的SDK。

在下面的内容中,主要是介绍高德地图定位SDK和地图SDK的使用,这里直接贴出官网上关于配置工程方面的相关文档。

Android Studio中使用定位SDK前的配置

Android Studio中使用3D地图SDK前的配置

可以看到,地图SDK配置相对来说多了so库的添加。

AndroidManifest.xml文件配置完成后如下所示,注意uses-permissionmeta-dataservice三个地方:

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

    <!--用于进行网络定位-->
    <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" />
    <!--用于申请调用A-GPS模块-->
    <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />

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

        <meta-data
            android:name="com.amap.api.v2.apikey"
            android:value="填入申请的Key值" />

        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".LocActivity" />
        <activity android:name=".MapActivity"></activity>

        <service android:name="com.amap.api.location.APSService" />
    </application>

</manifest>

三、定位SDK的使用

在上面Key申请完并成功配置好工程后,我们就正式进入了具体的编码过程。下面首先看一个例子,我们在界面上输出当前的定位结果,运行结果如下图所示:

定位成功

布局界面很简单,主要就是一个显示定位结果的TextView。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:padding="16dp">

    <TextView
        android:id="@+id/tv_location"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="定位结果" />
</LinearLayout>

Activity里的代码如下:

public class LocActivity extends AppCompatActivity implements AMapLocationListener {

    private TextView tvLocation;

    //定位服务类
    private AMapLocationClient locationClient = null;
    //定位参数类
    private AMapLocationClientOption locationClientOption = null;


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

        tvLocation = (TextView) findViewById(R.id.tv_location);

        //初始化定位
        locationClient = new AMapLocationClient(getApplicationContext());
        locationClient.setLocationListener(this);

        //定位参数设置
        locationClientOption = new AMapLocationClientOption();
        locationClientOption.setLocationMode(AMapLocationMode.Hight_Accuracy);

        locationClient.setLocationOption(locationClientOption);
        locationClient.startLocation();


    }


    @Override
    public void onLocationChanged(AMapLocation aMapLocation) {

        if (aMapLocation != null) {

            if (aMapLocation.getErrorCode() == 0) {

                tvLocation.setText("纬度 " + aMapLocation.getLatitude() + "\n" +
                        "经度 " + aMapLocation.getLongitude() + "\n" +
                        aMapLocation.getAddress());

            } else {

                tvLocation.setText("定位失败, ErrCode:"
                        + aMapLocation.getErrorCode() + ", errInfo:"
                        + aMapLocation.getErrorInfo());
            }
        }

    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (locationClient != null) {
            locationClient.onDestroy();
            locationClient = null;
            locationClientOption = null;
        }
    }
}

定位SDK使用小结

在上面的LocActivity中,主要有两个类需要关注,AMapLocationClient和AMapLocationClientOption,其中AMapLocationClient是定位服务类,可以启动定位、停止定位以及销毁定位,而AMapLocationClientOption主要用于对定位的相关参数进行设置。

AMapLocationClient调用方法startLocation()后,开始异步获取定位数据,定位结果在回调方法onLocationChanged中,通过解析AMapLocation,得到需要的数据。

四、地图SDK的使用

在我们的开发中,如果有需要展示一张地图,那么我们就需要使用3D地图的SDK。下面是另外一个例子,主要逻辑是展示一张完整的地图,并显示当前的定位,长按地图时可以弹出对话框显示长按的位置点的详细信息。这里需要说明一下,长按地图时会得到长按的位置的经纬度,这里需要高德地图的搜索SDK,进行逆地理编码。

运行结果如图所示:

运行结果

首先是布局文件,比较简单:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_map"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

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

</LinearLayout>

下面是Activity里的代码:

public class MapActivity extends AppCompatActivity implements LocationSource, AMapLocationListener, AMap.OnMapLongClickListener, GeocodeSearch.OnGeocodeSearchListener {

    private MapView mapView;
    private AMap map;

    private OnLocationChangedListener locationChangedListener;
    private AMapLocationClient locationClient;
    private AMapLocationClientOption locationClientOption;

    private int cLocation = 0;

    //选中位置的数据
    private double zLongtitude;
    private double zLatitude;
    private String zAddress = "";

    private int cMapLongClick = 0;
    private Marker marker;
    private GeocodeSearch geocodeSearch;

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

        mapView = (MapView) findViewById(R.id.mv_test);
        mapView.onCreate(savedInstanceState);

        initMap();
    }

    private void initMap() {

        if (map == null) {

            map = mapView.getMap();

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

            map.setOnMapLongClickListener(this);

        }


        geocodeSearch = new GeocodeSearch(this);
        geocodeSearch.setOnGeocodeSearchListener(this);
    }


    @Override
    public void activate(OnLocationChangedListener onLocationChangedListener) {

        locationChangedListener = onLocationChangedListener;

        if (locationClient == null) {

            locationClient = new AMapLocationClient(this);
            locationClientOption = new AMapLocationClientOption();

            locationClient.setLocationListener(this);

            locationClientOption.setLocationMode(AMapLocationMode.Hight_Accuracy);

            locationClient.setLocationOption(locationClientOption);
            locationClient.startLocation();
        }
    }

    @Override
    public void deactivate() {

        locationChangedListener = null;
        if (locationClient != null) {
            locationClient.stopLocation();
            locationClient.onDestroy();
        }
        locationClient = null;
    }

    @Override
    public void onLocationChanged(AMapLocation aMapLocation) {

        if (locationChangedListener != null && aMapLocation != null) {

            if (locationClient != null && aMapLocation.getErrorCode() == 0) {

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

                //如果是第一次定位成功 就缩放到级别18
                if (cLocation == 0) {
                    map.moveCamera(CameraUpdateFactory.zoomTo(12));
                    cLocation++;
                }
            }
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mapView.onDestroy();
        if (null != locationClient) {
            locationClient.onDestroy();
        }
    }

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

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

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

    @Override
    public void onMapLongClick(LatLng latLng) {

        zLatitude = latLng.latitude;
        zLongtitude = latLng.longitude;

        BitmapDescriptor bitmapDescriptor = BitmapDescriptorFactory.fromResource(R.mipmap.marker_location_center);

        MarkerOptions markerOptions = new MarkerOptions();
        markerOptions.icon(bitmapDescriptor);
        markerOptions.position(latLng);

        if (cMapLongClick == 0) {
            marker = map.addMarker(markerOptions);
            cMapLongClick++;
        } else {
        }
        marker.setPosition(latLng);

        // 长按时中心点切换
        map.animateCamera(CameraUpdateFactory.changeLatLng(latLng), 500, null);

        LatLonPoint latLonPoint = new LatLonPoint(zLatitude, zLongtitude);
        RegeocodeQuery query = new RegeocodeQuery(latLonPoint, 200,
                GeocodeSearch.AMAP);
        // 第一个参数表示一个Latlng,第二参数表示范围多少米,第三个参数表示是火系坐标系还是GPS原生坐标系
        geocodeSearch.getFromLocationAsyn(query);// 设置异步逆地理编码请求
    }


    @Override
    public void onRegeocodeSearched(RegeocodeResult regeocodeResult, int code) {

        if (code == AMapException.CODE_AMAP_SUCCESS) {

            if (regeocodeResult != null && regeocodeResult.getRegeocodeAddress() != null
                    && regeocodeResult.getRegeocodeAddress().getFormatAddress() != null) {
                zAddress = regeocodeResult.getRegeocodeAddress().getFormatAddress()
                        + "附近";
            } else {
                zAddress = "未知位置";
            }

        } else {
            zAddress = "未知位置";
        }

        showLocationInfo();
    }

    @Override
    public void onGeocodeSearched(GeocodeResult geocodeResult, int i) {

    }

    private void showLocationInfo() {

        AlertDialog.Builder builder = new AlertDialog.Builder(this);

        builder.setIcon(R.mipmap.ic_launcher);
        builder.setTitle("长按的位置信息");

        String mess = "经度:" + zLongtitude + "\n纬度:" + zLatitude + "\n地址:" + zAddress;

        builder.setMessage(mess);
        builder.setPositiveButton("是", null);
        builder.setNegativeButton("否", null);
        builder.create().show();
    }
}

五、总结

上面地图SDK的Activity部分代码比较长,下面总结其中的过程:

首先,我们是通过MapView来完成地图的展示的,在代码里类AMap是地图对象,通过MapView的getMap()方法可以实例化地图类。

在得到地图类的实例后我们可以进行一些初始化操作,比如setLocationSource方法设置定位监听,设置定位模式等等。

在地图有关的操作中,一定需要注意根据Activity的不同生命周期进行不同的状态处理。

根据位置的经纬度进行逆地理编码时需要用到搜索SDK的方法,异步获取具体地址时在回调方法onRegeocodeSearched()中获得结果,解析出来即可。

这里简单介绍了高德地图定位SDK和地图SDK的使用,利用好这些API,可以很方便地在应用中集成LBS服务,完善应用的功能,如果有更多别的需要,大家可以到官网上根据文档选择使用。

上一篇 下一篇

猜你喜欢

热点阅读