赞
踩
我们接着上一篇文章开始继续实现android中集成高德地图的SDK实现地图 定位,搜索,导航的功能
<!--允许访问网络,必选权限--> <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以后需要动态申请权限 这里我就不做详细解释了
在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); }
效果如上图所示,这就完成了第一步地图的展示
参考官方文档
完整的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); }
实现后的效果如下
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) { }
这就完成了搜索功能,效果如下图
官方文档参考
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 中添加 这样一段代码不然会点击开始导航会出现奔溃 详情请参考 为啥要添加下面的代码
android:allowNativeHeapPointerTagging="false"
这就是以上所有的内容,如有前期准备工作搞不定的请参考我的上一篇:Android中集成高德地图SDK实现地图定位和导航功能(一)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。