我们接着上一篇文章开始继续实现android中集成高德地图的SDK实现地图 定位,搜索,导航的功能
如何让地图在手机上实现呢?
1.配置AndroidManifest 中的权限申请
可以参考官方文档
<!--允许访问网络,必选权限-->
<uses-permission android:name="android.permission.INTERNET" />
<!--允许获取精确位置,实时导航为必选-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!--允许获取粗略位置,实时导航为必选-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!--允许获取设备和运营商信息,用于问题排查和网络定位(无gps情况下的定位),若需网络定位功能则必选-->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!--允许获取网络状态,用于网络定位(无gps情况下的定位),若需网络定位功能则必选-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!--允许获取wifi网络信息,用于网络定位(无gps情况下的定位),若需网络定位功能则必选-->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!--允许获取wifi状态改变,用于网络定位(无gps情况下的定位),若需网络定位功能则必选-->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<!--后台获取位置信息,若需后台定位或持续导航则必选-->
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<!--用于申请调用A-GPS模块,卫星定位加速-->
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
<!--允许写入扩展存储,用于写入缓存定位数据-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!--用于用户链接蓝牙时,在导航组件页面的蓝牙连接提醒,建立链接后开发者可选用蓝牙通道进行tts播报-->
<uses-permission android:name="android.permission.BLUETOOTH" />
<!--用与导航状态中保持屏幕常亮-->
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<!--允许写设备缓存,用于问题排查-->
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<!--允许读设备等信息,用于问题排查-->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
android6.0以后需要动态申请权限 这里我就不做详细解释了
设置高德地图的key
在androidMainfest文件的appliation 标签中添加之前在高的开发者平台上的key,代码如下
<meta-data
android:name="com.amap.api.v2.apikey"
android:value="这个地方就是你之前申请的key" />
我的key是ba63b…
初始化地图控件
首先要先新创建一个承载地图的Activiy,然后初始化MapView
<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"
tools:context=".activity.GaodeMapActivity"
android:orientation="vertical">
<com.amap.api.maps.MapView
android:id="@+id/gaode_map"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:layout_editor_absoluteX="16dp"
tools:layout_editor_absoluteY="39dp">
</com.amap.api.maps.MapView>
</LinearLayout>
然后再Activity中初始化地图空,这边需要了解到Activity生命周期和这个地图绑定到一起
public class GaodeMapActivity extends AppCompatActivity {
private static final String TAG = "GaodeMapActivity";
private MapView mapView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_gaode_map);
// 这一步操作就设置高德地图中的隐私合规,不然可能会出现地图无法正确加载的问题
MapsInitializer.updatePrivacyShow(this,true,true);
MapsInitializer.updatePrivacyAgree(this,true);
//初始化地图控件
mapView = (MapView) findViewById(R.id.gaode_map);
//这个地方需要捕获下异常,不然会出现编译不过的情况
try {
mLocationClient = new AMapLocationClient(GaodeMapActivity.this);
}catch (Exception e) {
Log.e(TAG, e.getMessage());
}
mapView.onCreate(savedInstanceState);
if (aMap == null) {
//展示地图
aMap = mapView.getMap();
Log.i(TAG,"展示地图");
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
public void onSaveInstanceState(@NonNull Bundle outState, @NonNull PersistableBundle outPersistentState) {
super.onSaveInstanceState(outState, outPersistentState);
//在activity保存时,同时也保存地图
mapView.onSaveInstanceState(outState);
}
效果如上图所示,这就完成了第一步地图的展示
2.定位蓝点
参考官方文档
完整的GaodeActivity的代码如下 因为是一个demo,所以代码写的比较潦草,多多担待
private static final String TAG = "GaodeMapActivity";
private MapView mapView;
private AMap aMap = null;
private double lat;
private double lon;
public AMapLocationClient mLocationClient = null;
public AMapLocationClientOption mLocationOption = null;
private Button btn_search;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_gaode_map);
btn_search = findViewById(R.id.btn_search);
//这地方就是下面要讲的搜索导航功能
btn_search.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(GaodeMapActivity.this, SearchActivity.class);
startActivity(intent);
}
});
MapsInitializer.updatePrivacyShow(this,true,true);
MapsInitializer.updatePrivacyAgree(this,true);
//初始化地图控件
mapView = (MapView) findViewById(R.id.gaode_map);
try {
mLocationClient = new AMapLocationClient(GaodeMapActivity.this);
}catch (Exception e) {
Log.e(TAG, e.getMessage());
}
//设置定位回调监听
mLocationClient.setLocationListener(mLocationListener);
mapView.onCreate(savedInstanceState);
if (aMap == null) {
//展示地图
aMap = mapView.getMap();
Log.i(TAG,"展示地图");
}
MyLocationStyle myLocationStyle;
myLocationStyle = new MyLocationStyle();
myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE); //持续定位
//设置连续定位模式下定位间隔
myLocationStyle.interval(2000);
myLocationStyle.strokeWidth(20f);
aMap.setMyLocationStyle(myLocationStyle);//设置定位蓝点的Style
//aMap.getUiSettings().setMyLocationButtonEnabled(true);设置默认定位按钮是否显示,非必需设置。
aMap.setMyLocationEnabled(true);// 设置为true表示启动显示定位蓝点,false表示隐藏定位蓝点并不进行定位,默认是false。
myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE);
myLocationStyle.showMyLocation(true);
}
public AMapLocationListener mLocationListener = new AMapLocationListener() {
@Override
public void onLocationChanged(AMapLocation amapLocation) {
if (amapLocation != null) {
if (amapLocation.getErrorCode() == 0) {
//定位成功回调信息,设置相关消息
amapLocation.getLocationType();//获取当前定位结果来源,如网络定位结果,详见定位类型表
amapLocation.getLatitude();//获取纬度
amapLocation.getLongitude();//获取经度
amapLocation.getAccuracy();//获取精度信息
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = new Date(amapLocation.getTime());
df.format(date);//定位时间
amapLocation.getAddress();//地址,如果option中设置isNeedAddress为false,则没有此结果,网络定位结果中会有地址信息,GPS定位不返回地址信息。
amapLocation.getCountry();//国家信息
amapLocation.getProvince();//省信息
amapLocation.getCity();//城市信息
amapLocation.getDistrict();//城区信息
amapLocation.getStreet();//街道信息
amapLocation.getStreetNum();//街道门牌号信息
amapLocation.getCityCode();//城市编码
amapLocation.getAdCode();//地区编码
amapLocation.getAoiName();//获取当前定位点的AOI信息
lat = amapLocation.getLatitude();
lon = amapLocation.getLongitude();
Log.v("pcw","lat : "+lat+" lon : "+lon);
// 设置当前地图显示为当前位置
aMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(lat, lon), 15));
MarkerOptions markerOptions = new MarkerOptions();
markerOptions.position(new LatLng(lat, lon));
markerOptions.title("当前位置");
markerOptions.visible(true);
BitmapDescriptor bitmapDescriptor = BitmapDescriptorFactory.fromBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher_background));
markerOptions.icon(bitmapDescriptor);
aMap.addMarker(markerOptions);
} else {
//显示错误信息ErrCode是错误码,errInfo是错误信息,详见错误码表。
Toast.makeText(GaodeMapActivity.this,
amapLocation.getErrorCode() + ", errInfo:"
+ amapLocation.getErrorInfo(), Toast.LENGTH_SHORT).show();
}
}
}
};
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
public void onSaveInstanceState(@NonNull Bundle outState, @NonNull PersistableBundle outPersistentState) {
super.onSaveInstanceState(outState, outPersistentState);
//在activity保存时,同时也保存地图
mapView.onSaveInstanceState(outState);
}
实现后的效果如下
3.实现搜索功能
1.首先我们要创建一个搜索的Activity
<?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"
tools:context=".activity.SearchActivity"
android:orientation="vertical">
<EditText
android:id="@+id/search_edit"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/search_rv"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@+id/search_edit"
app:layout_constraintVertical_bias="1.0"
tools:layout_editor_absoluteX="-51dp"
/>
</LinearLayout>
搜索item 的布局如下
<?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="wrap_content"
android:padding="18dp"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="城市"
android:textSize="18sp"
android:id="@+id/search_adapter_text"/>
</LinearLayout>
3.要有一个Adapter 来给Recyclerview展示数据
public class RvAdapter extends RecyclerView.Adapter<RvAdapter.ViewHolder> implements View.OnClickListener {
private final ArrayList<Tip> list;
private final Context context;
private final RecyclerView rv;
private OnItemClickListener mOnItemClickListener;
public RvAdapter(ArrayList<Tip> list, Context context, RecyclerView rv) {
this.list = list;
this.context = context;
this.rv = rv;
}
@Override
public void onClick(View view) {
int position = rv.getChildAdapterPosition(view);
//程序执行到此,会去执行具体实现的onItemClick()方法
if (mOnItemClickListener != null) {
mOnItemClickListener.onItemClick(rv, view, position, list.get(position));
Log.i("TAG", "onClick: "+position);
}
}
public interface OnItemClickListener{
void onItemClick(RecyclerView recyclerView,View view, int position,Tip data);
}
public void setmOnItemClickListener(OnItemClickListener clickListener) {
this.mOnItemClickListener = clickListener;
}
public void setData(List<Tip> list) {
if (list != null) {
this.list.clear();
this.list.addAll(list);
notifyDataSetChanged();
Log.i("TAG", "setData: "+ list);
}
}
@Override
public RvAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
//View view = LayoutInflater.from(context).inflate(R.layout.search_item, parent ,false);
View view = View.inflate(context, R.layout.search_item, null);
view.setOnClickListener(this);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
Tip tip = list.get(position);
holder.textView.setText(tip.getName());
Log.i("TAG", "onBindViewHolder: getName= "+tip.getName());
}
@Override
public int getItemCount() {
return list.size();
}
static class ViewHolder extends RecyclerView.ViewHolder{
private TextView textView;
public ViewHolder(@NonNull View itemView) {
super(itemView);
textView = itemView.findViewById(R.id.search_adapter_text);
}
}
4.下面就是SearchActivty 的代码
public class SearchActivity extends AppCompatActivity implements Inputtips.InputtipsListener, TextWatcher,RvAdapter.OnItemClickListener {
private RvAdapter rvAdapter;
private Inputtips inputtips;
private AMapNavi aMapNavi;
private EditText editText;
private RecyclerView recyclerView;
private ArrayList<Tip> list = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
editText = findViewById(R.id.search_edit);
editText.addTextChangedListener(this);
recyclerView = (RecyclerView) findViewById(R.id.search_rv);
LinearLayoutManager layoutManager = new LinearLayoutManager(SearchActivity.this, RecyclerView.VERTICAL, false);
recyclerView.setLayoutManager(layoutManager);
rvAdapter = new RvAdapter(list,SearchActivity.this,recyclerView);
rvAdapter.setmOnItemClickListener(this);
recyclerView.setAdapter(rvAdapter);
inputtips = new Inputtips(this,(InputtipsQuery) null);
inputtips.setInputtipsListener(this);
}
@Override
public void onGetInputtips(List<Tip> list, int i) {
Log.i("Tag","onGetInputtips data = "+list);
rvAdapter.setData(list);
}
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
InputtipsQuery inputtipsQuery = new InputtipsQuery(String.valueOf(charSequence),null);
inputtipsQuery.setCityLimit(true);
inputtips.setQuery(inputtipsQuery);
inputtips.requestInputtipsAsyn();
}
@Override
public void afterTextChanged(Editable editable) {
}
@Override
public void onItemClick(RecyclerView parent, View view, int postion, Tip data) {
}
这就完成了搜索功能,效果如下图
4.导航功能
官方文档参考
1.我们需要通过AmapNaviPage来启动,他是一个单例模式
//导航参数对象(起点,途径,终点,导航方式)DRIVER是导航方式(驾驶,步行...当前为驾驶)ROUTE会计算路程选择
AmapNaviParams params = new AmapNaviParams(null, null, poi, AmapNaviType.DRIVER, AmapPageType.ROUTE);
//传递上下文和导航参数
AmapNaviPage.getInstance().showRouteActivity(getApplicationContext(), params, null);
2.声明定位 service 组件需在 AndroidManifest.xml 中声明定位 service 组件。请在application标签中声明service 组件,添加如下代码:
<service android:name="com.amap.api.location.APSService"/>
3.还要再AndroidMainfest 中声明导航组件的Activity
<activity
android:name="com.amap.api.navi.AmapRouteActivity"
android:theme="@android:style/Theme.NoTitleBar"
android:configChanges="orientation|keyboardHidden|screenSize|navigation" />
然后附上完整的SearchActivity的代码
public class SearchActivity extends AppCompatActivity implements Inputtips.InputtipsListener, TextWatcher,RvAdapter.OnItemClickListener {
private RvAdapter rvAdapter;
private Inputtips inputtips;
private AMapNavi aMapNavi;
private EditText editText;
private RecyclerView recyclerView;
private ArrayList<Tip> list = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
editText = findViewById(R.id.search_edit);
editText.addTextChangedListener(this);
recyclerView = (RecyclerView) findViewById(R.id.search_rv);
LinearLayoutManager layoutManager = new LinearLayoutManager(SearchActivity.this, RecyclerView.VERTICAL, false);
recyclerView.setLayoutManager(layoutManager);
rvAdapter = new RvAdapter(list,SearchActivity.this,recyclerView);
rvAdapter.setmOnItemClickListener(this);
recyclerView.setAdapter(rvAdapter);
inputtips = new Inputtips(this,(InputtipsQuery) null);
inputtips.setInputtipsListener(this);
//这是隐私合规接口,如果不加,可能出现地图加载不出来的问题
NaviSetting.updatePrivacyShow(this, true, true);
NaviSetting.updatePrivacyAgree(this, true);
try {
//这个地方也许捕获一下异常,不然编译不过去
aMapNavi = AMapNavi.getInstance(this);
}catch (Exception e){
Log.e("TAG", e.getMessage());
}
if (aMapNavi!=null) {
//设置内置语音播报
aMapNavi.setUseInnerVoice(true, false);
}
}
@Override
public void onGetInputtips(List<Tip> list, int i) {
Log.i("Tag","onGetInputtips data = "+list);
rvAdapter.setData(list);
}
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
InputtipsQuery inputtipsQuery = new InputtipsQuery(String.valueOf(charSequence),null);
inputtipsQuery.setCityLimit(true);
inputtips.setQuery(inputtipsQuery);
inputtips.requestInputtipsAsyn();
}
@Override
public void afterTextChanged(Editable editable) {
}
@Override
public void onItemClick(RecyclerView parent, View view, int postion, Tip data) {
Log.i("TAG", "onItemClick: 点击了"+postion+"条");
//得到点击的坐标
LatLonPoint point = data.getPoint();
Log.i("Tag", "坐标为"+point);
//得到经纬度
Poi poi = new Poi(data.getName(), new LatLng(point.getLatitude(), point.getLongitude()), data.getPoiID());
//导航参数对象(起点,途径,终点,导航方式)DRIVER是导航方式(驾驶,步行...当前为驾驶)ROUTE会计算路程选择
AmapNaviParams params = new AmapNaviParams(null, null, poi, AmapNaviType.DRIVER, AmapPageType.ROUTE);
//传递上下文和导航参数
AmapNaviPage.getInstance().showRouteActivity(getApplicationContext(), params, null);
}
}
下面附上实现效果图
这个地方还要插一句 需要在AndroidMainfest 的 applcation 中添加 这样一段代码不然会点击开始导航会出现奔溃 详情请参考 为啥要添加下面的代码文章来源:https://www.toymoban.com/news/detail-708107.html
android:allowNativeHeapPointerTagging="false"
这就是以上所有的内容,如有前期准备工作搞不定的请参考我的上一篇:Android中集成高德地图SDK实现地图定位和导航功能(一)文章来源地址https://www.toymoban.com/news/detail-708107.html
到了这里,关于Android中集成高德地图SDK实现地图定位和导航功能(二)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!