首先参考高德开放平台SDK开发指南:
在文档与支持-Android平台下可自行选择参考哪类开发。
第一步:配置Android Studio
Android Studio配置起来很麻烦,难免会出现各种问题,把我搞得几度崩溃。
进入正题:
1. 新建工程
New-New Project-Empty Views Activity,记住这个Package name,等会要用。
language选择Java,最后一栏选择Groovy DSL,点击Finish完成工程创建
第二步:准备工作
1. 申请Key
在高德平台控制台中,创建自己的应用
2. 编辑应用信息
Package name用上面步骤中的。
标红的这两项有问题的可以网上搜一搜很多解决办法。
这里提一嘴,这里一定要确保机器上的SHA1和签名apk的是同一个,不然应用会显示算路失败。后面会讲到这个问题,当时困扰了我好久。
第三步:导入高德SDK
1. 从官网下载下载开发包
我下载的是3D包
2. 添加 jar 文件
将下载的地图 SDK 的 jar包复制到工程的 libs 目录下。如果有老版本 jar 包在其中,请删除。
3. 编辑dependencies
添加这行代码到build.gradle(:app)中,让SDK的文件能被检索到
implementation fileTree(include: ['*.jar'], dir: 'libs')
同样在build.gradle(:app)中添加这一段代码
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
第三步:配置权限文件
1. 编辑AndroidManifest.xml
把这段代码粘贴到<manifest>标签中
<!--允许访问网络,必选权限-->
<uses-permission android:name="android.permission.INTERNET" />
<!--允许获取粗略位置,若用GPS实现定位小蓝点功能则必选-->
<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.WRITE_EXTERNAL_STORAGE" />
<!--允许读设备等信息,用于问题排查-->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!--允许访问网络,必选权限-->
<uses-permission android:name="android.permission.INTERNET" />
<!--允许读设备等信息,用于问题排查-->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!--允许获取网络状态-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!--允许获取wifi网络信息-->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!--允许写入扩展存储,用于搜索结果缓存,若无此权限则写到私有目录-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!--允许读设备等信息,用于问题排查-->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
接下来将name和value添加进meta-data>标签中。
value就是上面申请的Key,name不用管
<meta-data
android:name="com.amap.api.v2.apikey"
android:value="Your Key">
</meta-data>
2. 编辑activity_main.xml
接下来初始化地图容器
在activity_main.xml中添加地图控件代码
<com.amap.api.maps.MapView
android:id="@+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</com.amap.api.maps.MapView>
添加完后,activity_main.xml是如下这样
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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=".MainActivity">
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<com.amap.api.maps.MapView
android:id="@+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</com.amap.api.maps.MapView>
</RelativeLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
3. 编辑主函数MainActivity.java
管理地图生命周期,添加以下代码
public class MainActivity extends Activity {
MapView mMapView = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//获取地图控件引用
mMapView = (MapView) findViewById(R.id.map);
//在activity执行onCreate时执行mMapView.onCreate(savedInstanceState),创建地图
mMapView.onCreate(savedInstanceState);
}
@Override
protected void onDestroy() {
super.onDestroy();
//在activity执行onDestroy时执行mMapView.onDestroy(),销毁地图
mMapView.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 onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
//在activity执行onSaveInstanceState时执行mMapView.onSaveInstanceState (outState),保存地图当前的状态
mMapView.onSaveInstanceState(outState);
}
}
第四步:显示地图
1. 编辑主函数
构造 AMap 对象,添加代码
private void initializeMapView(Bundle savedInstanceState) {
mMapView = findViewById(R.id.map);
if (mMapView != null) {
mMapView.onCreate(savedInstanceState);
aMap = mMapView.getMap();
}
}
@Override
protected void onResume() {
super.onResume();
if (mMapView != null) {
mMapView.onResume();
}
}
@Override
protected void onPause() {
super.onPause();
if (mMapView != null) {
mMapView.onPause();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mMapView != null) {
mMapView.onDestroy();
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (mMapView != null) {
mMapView.onSaveInstanceState(outState);
}
}
编辑onCreate()函数
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initializeMapView(savedInstanceState);
}
2. 显示效果
第五步:显示定位
1. 设置定位权限获取
编辑MainActivity.java,在MainActivity类中添加代码
private void requestLocationPermissions() {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, LOCATION_PERMISSION_REQUEST_CODE);
}
}
private void setupAmapPrivacy() {
MapsInitializer.updatePrivacyShow(this, true, true);
MapsInitializer.updatePrivacyAgree(this, true);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == LOCATION_PERMISSION_REQUEST_CODE) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "权限已授予", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "权限被拒绝,应用可能无法正常工作", Toast.LENGTH_SHORT).show();
finish();
}
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
2. 显示定位蓝点
编辑MainActivity.java,在MainActivity类中添加代码
private void configureMap() {
if (aMap == null) return;
MyLocationStyle locationStyle = MapConfigurator.createDefaultLocationStyle();
aMap.setMyLocationStyle(locationStyle);
aMap.getUiSettings().setMyLocationButtonEnabled(true);
aMap.setMyLocationEnabled(true);
aMap.moveCamera(CameraUpdateFactory.zoomTo(16));
}
修改onCreate()
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestLocationPermissions();
setupAmapPrivacy();
setContentView(R.layout.activity_main);
initializeMapView(savedInstanceState);
configureMap();
}
3. 显示效果
第六步:启动导航组件
1. 添加xml文件
在layout文件夹中新建3个xml文件
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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=".MainActivity">
<RelativeLayout
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<com.amap.api.maps.MapView
android:id="@+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
<Button
android:id="@+id/btnGotoNavi"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="前往导航"
android:onClick="gotoNavi"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="MissingConstraints,OnClick" />
</androidx.constraintlayout.widget.ConstraintLayout>
activity_search.xml
<?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=".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>
activity_item.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="18dp">
</TextView>
2. 添加两个类
在App-Java-com.amap.navi.map 文件夹中新建两个Java类: RvAdapter.java与SearchActivity.java
RvAdapter.java
package com.amap.navi.map;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.amap.api.services.help.Tip;
import java.util.List;
import java.util.Map;
public class RvAdapter extends RecyclerView.Adapter<RvAdapter.MyViewHolder> implements View.OnClickListener {
private final List<Tip> list;
private final Context context;
private final RecyclerView rv;
private OnItemClickListener mOnItemClickListener;
@Override
public void onClick(View v) {
int position = rv.getChildAdapterPosition(v);
//程序执行到此,会去执行具体实现的onItemClick()方法
if (mOnItemClickListener != null) {
mOnItemClickListener.onItemClick(rv, v, position, list.get(position));
}
}
public interface OnItemClickListener {
void onItemClick(RecyclerView parent, View view, int position, Tip data);
}
public RvAdapter(Context context, RecyclerView rv, List<Tip> list) {
this.context = context;
this.rv = rv;
this.list = list;
}
public void setOnItemClickListener(OnItemClickListener clickListener) {
this.mOnItemClickListener = clickListener;
}
public void setData(List<Tip> list) {
if (list == null) return;
this.list.clear();
this.list.addAll(list);
notifyDataSetChanged();
}
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.search_item, parent, false);
view.setOnClickListener(this);
return new MyViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
Tip tip = list.get(position);
((TextView) holder.itemView).setText(tip.getName());
}
@Override
public int getItemCount() {
return list.size();
}
static class MyViewHolder extends RecyclerView.ViewHolder {
public MyViewHolder(@NonNull View itemView) {
super(itemView);
}
}
}
SearchActivity.java
package com.amap.navi.map;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import com.amap.api.services.help.Inputtips;
import com.amap.api.services.help.InputtipsQuery;
import com.amap.api.services.help.Tip;
import java.util.ArrayList;
import java.util.List;
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(this, recyclerView, new ArrayList<>());
rvAdapter.setOnItemClickListener(this);
recyclerView.setAdapter(rvAdapter);
inputtips = new Inputtips(this, (InputtipsQuery) null);
inputtips.setInputtipsListener(this);
}
//通过适配器把数据展示到recyclerView中去
@Override
public void onGetInputtips(List<Tip> list, int i) {
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) {
}
@Override
public void onBackPressed() {
Log.d("SearchActivity", "onBackPressed Called");
super.onBackPressed();
}
}
3. 编辑MainActivity.java
编辑onCreate()函数,添加以下代码
// 无起终点启动导航组件的代码
findViewById(R.id.btnGotoNavi).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 无起终点启动导航
AmapNaviParams params = new AmapNaviParams(null, null, null, AmapNaviType.DRIVER, AmapPageType.ROUTE);
AmapNaviPage.getInstance().showRouteActivity(getApplicationContext(), params, null);
}
});
}
// 在 MainActivity 中,或者任何合适的地方
private void exitNavigation() {
AmapNaviPage.getInstance().exitRouteActivity();
}
4. 在MainActivity类中添加新方法
gotoNavi()
public void gotoNavi(View view) {
// Start the SearchActivity without finishing the current activity
Intent intent = new Intent(this, SearchActivity.class);
startActivity(intent);
}
5. 更新AndroidManifest.xml
在application标签中添加
android:allowNativeHeapPointerTagging="false"
新建一个activity
<activity
android:name="com.amap.api.navi.AmapRouteActivity"
android:theme="@android:style/Theme.NoTitleBar"
android:configChanges="orientation|keyboardHidden|screenSize|navigation" />