在App中使用地图定位十分常见,购物功能的可以直接定位当前位置,发动态功能可以定位当前位置发出,社交功能可以定位周边用户等等。这里我使用高德地图定位当前位置并显示地址和经纬度。
先上效果图:
实现步骤:
1. 创建应用获取key:
接入第三方无一例外,去高德地图官网注册账号并创建应用。填入包名和keystore的Sha1。
获取Sha1,输入命令keytool -v -list -keystore keystore文件路径
-
获取调试版Sha1:
进入.android目录
cd .android
输入命令获取
keytool -v -list -keystore debug.keystore
过程截图:
-
获取正式版Sha1:
输入命令获取接正式keystore路径
keytool -v -list -keystore ../../xxx.keystore
过程截图:
创建完成获取Key:
2. 接入SDK
添加定位库
compile 'com.amap.api:location:latest.integration'
添加2D地图库
compile 'com.amap.api:map2d:latest.integration'
添加地图权限:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
在<application></application>中设置地图key
<meta-data
android:name="com.amap.api.v2.apikey"
android:value="db1fde13fd28fb07223212dd8e9eef72" />
3. 代码实现(带每一步功能注释):
实现思路:创建MapView显示地图;设置定位定位监听,设置定位参数,在activate激活后启动定位;在定位回调中获取经纬度,在将地图移动到定位位置,在该经纬度上添加覆盖图标。详细代码如下:
- 地图控件:
<com.amap.api.maps2d.MapView
android:id="@+id/mapview"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
- 定位类AmapActivity完整代码:
public class MainActivity extends BasePermissionActivity implements LocationManager.ILocationCallBack {
private MapView mapview;
private AMap aMap;
private LocationSource.OnLocationChangedListener mListener;//定位监听器
private LocationManager locationManager;
/**
* 纬度
*/
protected double lat = 39.90;
/**
* 经度
*/
protected double lgt = 116.38;
/**
* 地点名
*/
private String location = "北京天安门";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mapview = findViewById(R.id.mapview);
mapview.onCreate(savedInstanceState);
setLocationMap();
addInfoWindow();
}
/**
* 设置地图定位属性
*/
private void setLocationMap() {
if (aMap == null) {
aMap = mapview.getMap();
}
setLocationCallBack();
aMap.setMapType(AMap.MAP_TYPE_NORMAL);
//设置定位监听
aMap.setLocationSource(new LocationSource() {
@Override
public void activate(OnLocationChangedListener onLocationChangedListener) {
mListener = onLocationChangedListener;
locationManager.startLocation(MainActivity.this);
}
@Override
public void deactivate() {
mListener = null;
}
});
//设置缩放级别
aMap.moveCamera(CameraUpdateFactory.zoomTo(15));
//显示定位层并可触发,默认false
aMap.setMyLocationEnabled(true);
}
/**
* 根据经纬度调用地图定位
*/
private void setLocationCallBack() {
locationManager = new LocationManager();
//根据获取的经纬度,将地图移动到定位位置
aMap.moveCamera(CameraUpdateFactory.changeLatLng(new com.amap.api.maps2d.model.LatLng(lat, lgt)));
//添加定位图标,并弹出标注弹框
aMap.addMarker(locationManager.getMarkerOption(location, lat, lgt));
}
@Override
public void callBack(String str, double lat, double lgt, AMapLocation aMapLocation) {
getCurLant(str, lat, lgt);
}
/**
* 进入导航页
*
* @param curPos
* @param curLat
* @param curLgt
*/
private void getCurLant(String curPos, double curLat, double curLgt) {
Poi start = new Poi(curPos, new LatLng(curLat, curLgt), "");
Poi end = new Poi(location, new LatLng(lat, lgt), "");
AmapNaviPage.getInstance().showRouteActivity(this, new AmapNaviParams(start, null, end, AmapNaviType.DRIVER), null);
}
/**
* 添加悬浮标注框
*/
private void addInfoWindow() {
aMap.setInfoWindowAdapter(new AMap.InfoWindowAdapter() {
@Override
public View getInfoWindow(Marker marker) {
View infoWindow = getLayoutInflater().inflate(R.layout.view_latlgt_marker, null);
TextView tvLat = infoWindow.findViewById(R.id.tv_lat);
TextView tvLgt = infoWindow.findViewById(R.id.tv_lgt);
tvLat.setText("纬度:" + lat);
tvLgt.setText("经度:" + lgt);
return infoWindow;
}
@Override
public View getInfoContents(Marker marker) {
return null;
}
});
}
/**
* 发起导航
*/
private void startNavigation() {
String[] permissions = new String[]{Manifest.permission.ACCESS_COARSE_LOCATION};
requestPermissions(permissions, new PermissionListener() {
@Override
public void onGranted() {
locationManager.startLocation(MainActivity.this);
locationManager.setLocationCallBack(MainActivity.this);
}
@Override
public void onDenied(List<String> deniedPermissions) {
}
});
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapview.onSaveInstanceState(outState);
}
@Override
public void onResume() {
super.onResume();
mapview.onResume();
}
@Override
public void onPause() {
super.onPause();
mapview.onPause();
}
@Override
public void onDestroy() {
super.onDestroy();
if (mapview != null) {
mapview.onDestroy();
}
}
@Override
public void onPointerCaptureChanged(boolean hasCapture) {
}
public void poi(View view) {
startActivity(new Intent(MainActivity.this, PoiActivity.class));
}
public void navigation(View view) {
startNavigation();
}
}
- 定位参数设置和定位回调LocationUtil类完整代码:
import android.content.Context;
import android.os.Build;
import android.provider.Settings;
import android.text.TextUtils;
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.maps2d.model.LatLng;
import com.amap.api.maps2d.model.MarkerOptions;
/**
* create by libo
* create on 2018/11/15
* description 高德定位工具类
*/
public class LocationManager implements AMapLocationListener {
private ILocationCallBack callBack;
public LocationManager() {
}
public void startLocation(Context context) {
AMapLocationClientOption mLocationOption = new AMapLocationClientOption();
AMapLocationClient mLocationClient = new AMapLocationClient(context);
mLocationClient.setLocationListener(this);
mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy); //设置定位模式
mLocationOption.setOnceLocation(true);
mLocationOption.setOnceLocationLatest(true);
mLocationOption.setNeedAddress(true); //是否返回地址信息
mLocationOption.setWifiActiveScan(false);
mLocationOption.setMockEnable(false);
mLocationOption.setLocationCacheEnable(false);
mLocationClient.setLocationOption(mLocationOption);
mLocationClient.startLocation();
}
public static boolean isLocationEnabled(Context context) {
int locationMode;
String locationProviders;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
try {
locationMode = Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.LOCATION_MODE);
} catch (Settings.SettingNotFoundException e) {
e.printStackTrace();
return false;
}
return locationMode != Settings.Secure.LOCATION_MODE_OFF;
} else {
locationProviders = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
return !TextUtils.isEmpty(locationProviders);
}
}
@Override
public void onLocationChanged(AMapLocation aMapLocation) {
if (aMapLocation == null) {
return;
}
if (aMapLocation.getErrorCode() == 0) {
double lat = aMapLocation.getLatitude();//获取纬度
double lgt = aMapLocation.getLongitude();//获取经度
String country = aMapLocation.getCountry();//国家信息
String province = aMapLocation.getProvince();//省信息
String city = aMapLocation.getCity();//城市信息
String district = aMapLocation.getDistrict();//城区信息
String street = aMapLocation.getStreet();//街道信息
if (callBack != null) {
callBack.callBack(country + province + city + district + street,lat,lgt,aMapLocation);
}
}
}
/**
* 自定义图标
* @return
*/
public MarkerOptions getMarkerOption(String str, double lat, double lgt) {
MarkerOptions markerOptions = new MarkerOptions();
// markerOptions.icon(BitmapDescriptorFactory.fromResource(R.mipmap.coordinate));
markerOptions.position(new LatLng(lat,lgt));
markerOptions.title(str);
markerOptions.snippet("纬度:" + lat + " 经度:" + lgt);
markerOptions.period(100);
return markerOptions;
}
public interface ILocationCallBack {
void callBack(String str, double lat, double lgt, AMapLocation aMapLocation);
}
public void setLocationCallBack(ILocationCallBack callBack){
this.callBack = callBack;
}
}
传入当前经纬度得到起点的Poi,传入终点经纬度得到终点Poi,开启导航:
/**
* 进入导航页
*
* @param curPos
* @param curLat
* @param curLgt
*/
private void getCurLant(String curPos, double curLat, double curLgt) {
Poi start = new Poi(curPos, new LatLng(curLat, curLgt), "");
Poi end = new Poi(location, new LatLng(lat, lgt), "");
AmapNaviPage.getInstance().showRouteActivity(this, new AmapNaviParams(start, null, end, AmapNaviType.DRIVER), null);
}
记得需要在Androidmanifest文件中注册导航activity
<activity android:name="com.amap.api.navi.AmapRouteActivity"
android:theme="@android:style/Theme.NoTitleBar"
android:configChanges="orientation|keyboardHidden|screenSize" />
Poi搜索周边地址:
先开启调用定位当前位置,然后使用PoiSearch类进行搜索,回调获得poiResult,获取PoiItem集合,就是周边位置信息集合。
public class PoiActivity extends AppCompatActivity implements AMapLocationListener, PoiSearch.OnPoiSearchListener {
private RecyclerView recyclerView;
private PoiAdapter poiAdapter;
private ArrayList<PoiItem> poiDatas = new ArrayList<>();
private AMapLocationClient mlocationClient;
private LatLonPoint searchLatlonPoint;
private PoiSearch poisearch;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_poi);
recyclerView = findViewById(R.id.recyclerview);
setPoiAdapter();
initLocation();
startLocation();
}
private void setPoiAdapter() {
poiAdapter = new PoiAdapter(getApplicationContext(), poiDatas);
recyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
recyclerView.setAdapter(poiAdapter);
}
/**
* 初始化定位,设置回调监听
*/
private void initLocation() {
mlocationClient = new AMapLocationClient(this); //初始化client
mlocationClient.setLocationListener(this); // 设置定位监听
}
/**
* 开始定位
*/
private void startLocation() {
mlocationClient.setLocationOption(getOption()); //设置定位参数
mlocationClient.startLocation(); // 启动定位
}
/**
* 设置定位参数
*
* @return 定位参数类
*/
private AMapLocationClientOption getOption() {
AMapLocationClientOption mOption = new AMapLocationClientOption();
mOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);//可选,设置定位模式,可选的模式有高精度、仅设备、仅网络。默认为高精度模式
mOption.setHttpTimeOut(30000);//可选,设置网络请求超时时间。默认为30秒。在仅设备模式下无效
mOption.setNeedAddress(true);//可选,设置是否返回逆地理地址信息。默认是true
mOption.setLocationCacheEnable(false);//设置是否返回缓存中位置,默认是true
mOption.setOnceLocation(true);//可选,设置是否单次定位。默认是false
return mOption;
}
@Override
public void onLocationChanged(AMapLocation aMapLocation) {
if (aMapLocation != null && aMapLocation.getErrorCode() == 0) {
searchLatlonPoint = new LatLonPoint(aMapLocation.getLatitude(), aMapLocation.getLongitude());
if (searchLatlonPoint != null) {
doSearchQuery(searchLatlonPoint);
}
}
}
/**
* 搜索周边poi
*
* @param centerpoint
*/
private void doSearchQuery(LatLonPoint centerpoint) {
PoiSearch.Query query = new PoiSearch.Query("", "", "");
query.setPageSize(30);
query.setPageNum(0);
poisearch = new PoiSearch(this, query);
poisearch.setOnPoiSearchListener(this);
poisearch.setBound(new PoiSearch.SearchBound(centerpoint, 500, true));
poisearch.searchPOIAsyn();
}
@Override
public void onPoiSearched(PoiResult poiResult, int resultCode) {
if (resultCode == AMapException.CODE_AMAP_SUCCESS) {
if (poiResult != null && poiResult.getPois().size() > 0) {
List<PoiItem> poiItems = poiResult.getPois();
poiDatas.addAll(poiItems);
poiAdapter.notifyDataSetChanged();
} else {
Toast.makeText(this, "无搜索结果", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(this, "搜索失败", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onPoiItemSearched(PoiItem poiItem, int i) {
}
@Override
protected void onDestroy() {
super.onDestroy();
destroyLocation();
}
/**
* 销毁定位
*/
private void destroyLocation() {
if (null != mlocationClient) {
mlocationClient.onDestroy();
mlocationClient = null;
}
}
}
错误情况检查:
- Key是否配置错误
- 在onCreate中调用mapView.onCreate(savedInstanceState);
- mapView.onPause()、mapView.onDestroy()、mapView.onResume()、mapView.onSaveInstanceState(outState)是否都已调用且不写错
- aMap.setMyLocationEnabled(true)设置显示定位层并可触发
- 手机是否开启定位