封面画师:画师JW     封面ID:78143565

传感器的应用

本节案例需要在真机上进行测试,对于真机测试方法请看到 笔记—— Android图像处理与多媒体

本节案例需要在真机上进行测试,对于真机测试方法请看到 笔记—— Android图像处理与多媒体

什么是传感器

传感器 一种微型的物理设备,能够探测、感受到外界信号,并按一定规律转换成我们需要的信息。

传感器的坐标系统:

传感器的坐标系统

常用的传感器: 光线传感器、磁场传感器、加速度传感器、方向传感器等。

开发传感器应用的步骤:

  1. 获取SensorManager对象:使用getSystemService(Context.SENSOR_SERVICE)
  2. 获取指定类型的传感器:使用SensorManager的getDefaultSensor(int type)方法
  3. 为指定传感器注册监听器:在Activity的onResume()方法中调用SensorManager的registerListener()方法。

在注册监听器时,需要我们实现SensorEventListener接口,然后我们需要重写:

onSensorChanged(SensorEvent event) :传感器的发生变化的时候调用

onAccuracyChanged(Sensor sensor, int accuracy) :传感器的精度发生变化时调动

使用光线传感器获取光的强度

编写布局资源文件activity_main.xml,完成界面布局:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<LinearLayout ...
android:orientation="vertical"
android:gravity="top|center_horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="光线传感器"
android:textSize="40sp"/>
<EditText
android:id="@+id/editText"
android:layout_width="310dp"
android:layout_height="wrap_content"
android:textSize="30sp"/>
</LinearLayout>

编写MainActivity.java实现使用光线传感器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public class MainActivity extends AppCompatActivity implements SensorEventListener {
private EditText textLIGHT;
private SensorManager sensorManager; //传感器管理器对象
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textLIGHT = findViewById(R.id.editText);
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
}

@Override
protected void onResume() {
super.onResume();
//为光线传感器注册监听器
sensorManager.registerListener(this,sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT),
SensorManager.SENSOR_DELAY_GAME);
}

@Override
protected void onPause() {
super.onPause();
//为光线传感器取消注册的监听器
sensorManager.unregisterListener(this);
}

@Override
public void onSensorChanged(SensorEvent event) {
float[] values = event.values;//获取传感器的值
int sensorType = event.sensor.getType();//获取传感器类型
StringBuilder stringBuilder = null;
//判断传感器是否是光线传感器
if (sensorType == Sensor.TYPE_LIGHT){
stringBuilder = new StringBuilder();
stringBuilder.append("光的强度值");
stringBuilder.append(values[0]); //添加获取传感器的值
//将光的强度值显示到屏幕
textLIGHT.setText(stringBuilder.toString());
}
}

@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) { }
}

磁场传感器

我们手机的磁场传感器可以获取在x、y、z方向上的磁场强度。

使用磁场传感器实现指南针

案例在作者的手机上出现闪退且无法运行,因此代码仅供参考。

若找到解决方式请联系作者,一起学习交流。

需要准备一张表示指南针的图片,命名为compass,放置于res/drawable下。

自定义View类PointerView.class,实现指针绘制:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
public class PointerView extends View implements SensorEventListener {
private SensorManager sensorManager;//传感器管理器
private Bitmap pointer = null; //定义指针位图对象
private float[] allValues; //磁场传感器的值

public PointerView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
//获取传感器管理器
sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
//为磁场传感器注册监听器
sensorManager.registerListener(this,
sensorManager
.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
sensorManager.SENSOR_DELAY_GAME);
//指定要绘制的位图
pointer = BitmapFactory.decodeResource(super.getResources(), R.drawable.compass);
}

//传感器的值发生改变时触发
@Override
public void onSensorChanged(SensorEvent event) {
//判断传感器是否是磁场传感器
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
float[] value = event.values; //获取磁场传感器的值
allValues = value;
super.postInvalidate();//刷新界面
}
}

//传感器的进度发生改变时触发
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {

}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//根据X、Y轴磁场强度绘制指针
if (allValues != null) {
float x = allValues[0];//X轴的磁场强度
float y = allValues[1];//Y轴的磁场强度
canvas.restore();//重置绘图对象
//设置旋转中心点为屏幕中心
canvas.translate(super.getWidth() / 2, super.getHeight() / 2);
if (y == 0 && x > 0) {
canvas.rotate(90);//旋转90度
} else if (y == 0 && x < 0) {
canvas.rotate(270);//旋转270度
} else {
if (y >= 0) {
canvas.rotate((float) Math.tanh(x / y) * 90);
} else {
canvas.rotate(180 + (float) Math.tanh(x / y) * 90);
}
}
//绘制指针
canvas.drawBitmap(this.pointer, -this.pointer.getWidth() / 2,
-this.pointer.getHeight() / 2, new Paint());
}
}
}

编写activity_main.xml布局资源文件,自定义界面:

1
2
3
4
5
<FrameLayout ...>
<com.yang.compass.PointerView
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</FrameLayout>

MainActivity.java使用默认即可。

加速度传感器

加速度传感器主要用于测算一些瞬时加速减速的动作。比如:摇一摇、计步等。

手机屏幕向上,当手机横向移动时,会产生X方向的加速度;前后移动,会产生Y方向的加速度;垂直上下移动会产生Z方向的加速度。

加速度传感器的方向

实现摇一摇功能

编写activity_main.xml实现程序主界面:

1
2
3
4
5
6
7
8
9
<LinearLayout ...
android:gravity="center"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="摇一摇试试?"
android:textSize="40sp"/>
</LinearLayout>

编写info.xml界面,实现摇一摇成功后显示的对话框:

1
2
3
4
5
6
7
8
9
<RelativeLayout ...>
<TextView
android:layout_width="500dp"
android:layout_height="500dp"
android:gravity="center"
android:layout_centerInParent="true"
android:text="你上当了!"
android:textSize="40sp" />
</RelativeLayout>

编写MainActivity.java实现摇一摇主逻辑:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public class MainActivity extends AppCompatActivity implements SensorEventListener {
private SensorManager sensorManager;//定义传感器管理器
private Vibrator vibrator; //定义振动器

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//获取传感器管理器
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
//获取振动器
vibrator = (Vibrator) getSystemService(Service.VIBRATOR_SERVICE);
}

@Override
protected void onResume() {
super.onResume();
//为加速度传感器注册监听器
sensorManager.registerListener(
this,sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_GAME);
}

@Override
public void onSensorChanged(SensorEvent event) {
int sensorType = event.sensor.getType();
if (sensorType == Sensor.TYPE_ACCELEROMETER){
float[] values = event.values; //获取传感器的值
if (values[0] > 15 || values[1] > 15 || values[2] > 20){
Toast.makeText(MainActivity.this, "摇一摇", Toast.LENGTH_SHORT).show();
//创建一个对话框构建器
AlertDialog.Builder alertDialog = new AlertDialog.Builder(this);
//设置布局文件
alertDialog.setView(R.layout.info);
alertDialog.show();//显示对话框
vibrator.vibrate(500);//设置振动器频率
sensorManager.unregisterListener(this);
}
}
}

@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {

}
}

测试: 本案例只能实现摇动一次弹出对话框,无法实现多次摇动弹出对话框。

方向传感器

方向传感器主要用于感应手机的摆放状态。

返回值

它可以返回三个角度:

  1. 在Z轴上旋转的角度:手机方向Y轴与地磁场北极方向的角度,当手机绕Z轴旋转时这个值发生变化。
方向传感器的值_1
  1. 在X轴上旋转的角度:手机底部或尾部翘起的角度,当手机绕X轴时这个值发生变化。
方向传感器的值_2
  1. 在Y轴上旋转的角度:表示手机左侧或右侧翘起的角度,当手机绕Y轴时这个值发生变化。
方向传感器的值_3

使用方向传感器

获取方向传感器:getDefaultSensor(Sensor.TYPE_ORIENTATION)新SDK中方法已过期

我们可以使用加速度传感器与磁场传感器结合实现这个功能。如下图:

使用方向传感器

注意:我们使用SensorManager.getOrientation()得到的返回值是弧度,而不是角度,因此我们需要使用Math.toDegrees()将弧度转换换成角度

实现水平仪

步骤

  1. 创建自定义View,并实现SenorEventListener接口
  2. 布局界面
  3. 为磁场传感器和加速度传感器注册监听器,并获取传感器的取值
  4. 获取z、x、y轴的旋转角度,并绘制小球。

素材获取:Android利用Sensor(传感器)实现水平仪功能

代码实现

我们需要准备水平仪的仪表盘图片和气泡图标,分别命名为background和bubble,将它们置于res/drawable目录下,素材可以使用上图连接进行获取。

创建自定义View——SpiritlevelView.class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
public class SpiritlevelView extends View implements SensorEventListener {
private Bitmap bubble;//绘制气泡
private Bitmap back; //绘制水平仪表盘
float[] accelerometerValues = new float[3];//加速度传感器的值
float[] magneticValues = new float[3];//磁场传感器的值
private final int MAX_ANGLE = 30; //最大倾斜角度
private int bubbleX, bubbleY; //气泡的位置坐标

public SpiritlevelView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
//获取传感器管理器
SensorManager sensorManager =
(SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
//为磁场传感器注册监听器
sensorManager.registerListener(this,
sensorManager
.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
SensorManager.SENSOR_DELAY_GAME);
//为加速度传感器注册监听器
sensorManager.registerListener(this,
sensorManager
.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_GAME);
//加载气泡图片
bubble = BitmapFactory.decodeResource(getResources(), R.drawable.bubble);
}

@Override
public void onSensorChanged(SensorEvent event) {//传感器的值改变触发
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
accelerometerValues = event.values.clone(); //获取加速度传感器的值
} else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
magneticValues = event.values.clone();//获取磁场传感器的值
}
float[] R = new float[9]; //保存旋转数据的数组
float[] values = new float[3]; //保存方向数据的数组
//获得一个包含旋转矩阵的R数组
SensorManager.getRotationMatrix(R, null, accelerometerValues, magneticValues);
SensorManager.getOrientation(R, values);//获取方向值
float xAngle = (float) Math.toDegrees(values[1]); //X轴旋转角度
float yAngle = (float) Math.toDegrees(values[2]); //Y轴旋转角度
//获取气泡的位置坐标
getPosition(xAngle, yAngle);
super.postInvalidate();//刷新界面
}

//传感器的精度改变触发
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {

}

//根据x轴和y轴的旋转角度确定气泡的位置
private void getPosition(float xAngle, float yAngle) {
//气泡位于中间时(水平仪完全水平),气泡的X、Y坐标
int x = (super.getWidth() - bubble.getWidth()) / 2;
int y = (super.getHeight() - bubble.getHeight()) / 2;
/************控制小球的X轴位置**************/
if (Math.abs(yAngle) <= MAX_ANGLE) {//如果Y轴的倾斜角度还在最大角度以内
//根据Y轴的倾斜角度计算X坐标的变化值(倾斜角度越大,X坐标变化越大)
int deltaX =
(int) ((super.getWidth() - bubble.getWidth()) / 2 * yAngle / MAX_ANGLE);
x -= deltaX;
} else if (yAngle > MAX_ANGLE) {//如果Y轴的倾斜角度已经大于MAX_ANGLE,气泡在最左边
x = 0;
} else {//如果与Y轴的倾斜角度已经小于负的MAX_ANGLE,气泡在最右边
x = super.getWidth() - bubble.getWidth();
}
/************控制小球的Y轴位置**************/
if (Math.abs(xAngle) <= MAX_ANGLE) {//如果X轴的倾斜角度还在最大角度之内
//根据X轴的倾斜角度计算Y坐标的变化值(倾斜角度越大,Y坐标变化越大)
int deltaY =
(int) ((super.getHeight() - bubble.getHeight()) / 2 * xAngle / MAX_ANGLE);
y += deltaY;
} else if (xAngle > MAX_ANGLE) {//如果X轴的倾斜角度已经大于MAX_ANGLE,气泡在最下边
y = super.getHeight() - bubble.getHeight();
} else {//如果与X轴的倾斜角度已经小于负的MAX_ANGLE,气泡在最上边
y = 0;
}
//更新小球的位置
bubbleX = x;
bubbleY = y;
}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//绘制气泡
canvas.drawBitmap(bubble,bubbleX,bubbleY,new Paint());
}
}

编写activity_main.xml布局界面:

1
2
3
4
5
6
7
8
9
10
<FrameLayout ...>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="@drawable/background"/>
<com.yang.gradienter.SpiritlevelView
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>

MainActivity.java使用默认即可。

位置服务与地图应用

获取LocationProvider

LocationProvider是位置源的意思,用于提供定位信息。

常见的LocationProvider:GPS、network、passive

获取LocationProvider方法

  1. 获取所有可用的LocationProvider:LocationManager对象的getAllProviders()方法
  2. 通过名称获得LocationProvider:LocationManager对象的getProvider()方法
  3. 通过Criteria类获得LocationProvider

我们根据代码来进行方法的测试:

编写布局资源文件activity_main.xml对页面进行布局:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<RelativeLayout ...>
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="可用LocationProvider"
android:textColor="#257678"
android:textSize="26sp"
android:textStyle="bold" />
<TextView
android:id="@+id/provider"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#0B80DD"
android:lineSpacingExtra="18sp"
android:layout_centerInParent="true"
android:textStyle="bold"
android:textSize="18sp"/>
</RelativeLayout>

编写MainActivity.java实现获取LocationProvider的三种方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class MainActivity extends AppCompatActivity {
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.provider);
LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
/********1. 获取所有的LocationManager**********************/
// List<String> providerName = locationManager.getAllProviders();
// StringBuilder stringBuilder = new StringBuilder();//字符串构建器
// for (Iterator<String> iterator = providerName.iterator();iterator.hasNext();){
// stringBuilder.append(iterator.next()+"\n");
// }
// textView.setText(stringBuilder.toString());//显示获取的LocationProvider名称

/************2. 获取基于GPS的LocationProvider***************/
// LocationProvider provider = locationManager.getProvider(LocationManager.GPS_PROVIDER);
// textView.setText(provider.getName());

/**************3. 获取最佳的LocationProvider*****************/
Criteria criteria = new Criteria();//创建一个过滤条件对象
criteria.setCostAllowed(false);//不收费的
criteria.setAccuracy(Criteria.ACCURACY_FINE); //使用精度最准确的
criteria.setPowerRequirement(Criteria.POWER_LOW); //使用耗电量最低的
String provider = locationManager.getBestProvider(criteria,true);
textView.setText(provider);
}
}

在本次案例中我们获取GPS信息,因此我们需要获取GPS的权限

对AndroidManifest.xml进行修改:

1
2
3
4
5
6
7
8
9
<manifest ...>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<application ...
android:requestLegacyExternalStorage="true">
<activity android:name=".MainActivity">
...
</activity>
</application>
</manifest>

同时我们还需要在模拟器内部授予本案例的应用读取位置信息(定位)的权限!

获取定位信息

获取定位信息的步骤

  1. 获取系统的LocationManager对象:getSystemService(LOCATION_SERVICE)
  2. 设置一个监听器:LocationManager对象的requestLocationUpdate()方法
  3. 获取最近的定位信息:LocationManager的getLastKnownLocation()方法

编写布局资源文件activity_main.xml对页面进行布局:

1
2
3
4
5
6
7
8
9
10
<RelativeLayout ...>
<TextView
android:id="@+id/location"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textSize="18sp"
android:textStyle="bold"
android:textColor="#06518C"/>
</RelativeLayout>

编写MainActivity.java实现获取定位信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
public class MainActivity extends AppCompatActivity {
private TextView textView;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.location);
/****第一步****/
LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
//权限检查
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
/****第二步****/
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER, //指定GPS定位提供者
1000, //间隔时间
1, //位置间隔1米
new LocationListener() {//监听GPS定位信息是否改变
//GPS定位信息发生改变时回调
@Override
public void onLocationChanged(Location location) {

}
//GPS定位状态发生改变时回调
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {

}

//定位提供者启动时触发
@Override
public void onProviderEnabled(String provider) {

}

//定位提供者关闭时触发
@Override
public void onProviderDisabled(String provider) {

}
}
);
/****第四步****/
//获取最新的定位信息
Location location = locationManager.
getLastKnownLocation(LocationManager.GPS_PROVIDER);
//将最新的定位信息传递给locationUpdates()方法
locationUpdates(location);
}

/****第三步****/
public void locationUpdates(Location location){
if (location != null){
//字符串构建器用于记录定位信息
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("您的位置是:\n");
stringBuilder.append("经度:");
stringBuilder.append(location.getLongitude());
stringBuilder.append("\n纬度:");
stringBuilder.append(location.getLatitude());
//显示到页面上
textView.setText(stringBuilder.toString());
}else {
textView.setText("没有获取到GPS信息");
}
}
}

在本次案例中我们获取GPS信息,因此我们需要获取GPS的权限

对AndroidManifest.xml进行修改:

1
2
3
4
5
6
7
8
9
10
<manifest ...>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<application ...
android:requestLegacyExternalStorage="true">
<activity android:name=".MainActivity">
...
</activity>
</application>
</manifest>

同时我们还需要在模拟器内部授予本案例的应用读取位置信息(定位)的权限!

应用百度地图API

百度地图API:一套为开发者免费使用的基于百度地图的应用程序接口。它提供了定位服务、地图服务、数据服务、出行服务、鹰眼轨迹服务、分析服务等服务。

准备工作

新版网址在网页最下方,点击“立即注册”进入申请注册。

注册成功后创建应用,应用类型选择Android SDK,启动服务选择默认。

然后获取发布版SHA1,你需要找到你电脑SDK或AVD目录下有个名为.android的目录,**复制当前文件的位置!**比如:D:/avd/.android 就复制这个目录。

如何确定.android目录:在这个目录下有个名为debug.keystore的文件。

然后我们进入AS,进入Terminal面板,切换到刚刚复制的目录中,然后输入:

1
keytool -list -v -keystore debug.keystore -alias androiddebugkey

点击回车后,会让你输入秘钥库口令,一般默认都是android。输入的形式是不回显的。

密码输入成功后,我们可以找到证书指纹,里面就有SHA1,我们复制填写即可。

然后我们还需要填写PackageName,这个值你可以随意填写,但是!你编写的应用的Java代码得放在你填写的这个包目录下。

SHA1和包名会自动构成安全码,我们填写好信息提交就可以了。提交成功后会创建一个应用,应用里面有访问应用(AK这个值就是开发秘钥,它在我们编写代码时有用。

到此,我们就成功申请了秘钥了。

进入网址后,开发文档 > Android地图 SDK > 产品下载 > 自定义下载,选择你需要jar包开发资源。

我在此选择 全量定位、基础地图、检索功能、LBS云检索、计算工具、驾车导航(含TTS)、全景图功能,选择后,点击下方 “开发包” 进行下载。

到此,我们的准备工作就完成了,接下来就该应用百度地图API显示百度地图了。

应用百度地图API显示地图

步骤

  1. 配置百度Android地图API
  2. 布局界面
  3. 初始化SDK应用的Context全局变量
  4. 管理地图生命周期

具体实现

本文未概述清楚的地方请参考:

Android使用百度地图API 利用AS 3.0对于百度地图API的开发

运行应用进行测试时,使用真机测试,真机需要联网!

配置百度地图API:

在AS中将项目切换成project模式。首先找到我们刚下载的 百度LBS Android SDK 然后进行解压,解压成功后如图:

百度LBS Android SDK

我们只使用圈起来的libs目录。打开这个目录,将这个目录下的jar包复制到我们项目中libs目录(AS中)下,然后选中这些jar包,右击,Add As Library,把这些jar包添加到类库中。

在我们项目src/main/目录下(AS中)新建jniLibs目录,把libs目录下的五个文件夹复制进去,即:

配置百度地图API

刚刚复制的jar包就是上图中的那两个。


代码编写:==你编写的应用的Java代码必须放在你申请秘钥时填写的包名目录下。==比如,我申请秘钥时填写的包名是com.yang,因此我将我的Java代码必须放在这个包下。

BaiduAPI_packageName

编写activity_main.xml布局界面:

1
2
3
4
5
6
7
<RelativeLayout ...>
<com.baidu.mapapi.map.MapView
android:id="@+id/bmapview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"/>
</RelativeLayout>

在AndroidManifest.xml中指定开发秘钥、设置权限:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<manifest ...>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!--获取设备网络状态,禁用后无法获取网络状态-->
<uses-permission android:name="android.permission.INTERNET" />
<!--网络权限,当禁用后,无法进行检索等相关业务-->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!--读取设备硬件信息,统计数据-->
<uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" />
<!--读取系统信息,包含系统版本等信息,用作统计-->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!--获取设备的网络状态,鉴权所需网络代理-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!--允许sd卡写权限,需写入地图数据,禁用后无法显示地图-->
<uses-permission android:name="android.permission.WRITE_SETTINGS"
tools:ignore="ProtectedPermissions" />
<!--获取统计数据-->
<uses-permission android:name="android.permission.CAMERA" />
<!--使用步行AR导航,配置Camera权限-->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!-- 这个权限用于进行网络定位 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- 这个权限用于访问GPS定位 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- 用于访问wifi网络信息,wifi信息会用于进行网络定位 -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- 获取运营商信息,用于支持提供运营商信息相关的接口 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- 这个权限用于获取wifi的获取权限,wifi信息会用来进行网络定位 -->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<!-- 用于读取手机当前的状态 -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!-- 写入扩展存储,向扩展卡写入数据,用于写入离线定位数据 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- 访问网络,网络定位需要上网 -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- SD卡读取权限,用户写入离线定位数据 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"
tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application
...
android:requestLegacyExternalStorage="true">
<!--开发秘钥-->
<meta-data
android:name="com.baidu.lbsapi.API_KEY"
android:value="WVbGmRg0YKTz7FEjiVy3H3lgBepGp0rZ"></meta-data>
<!--value就是你申请的AK-->
<!--用别的包名申请的AK在本app中是不能使用的,一个AK对应一个应用-->
<activity android:name=".MainActivity">
...
</activity>
</application>
</manifest>

开发秘钥在<application>标签内指定,使用<meta-data>进行指定。其中,name为固定值,即:com.baidu.lbsapi.API_KEYvalue为你申请的秘钥

编写MainActivity.java初始化地图应用、管理地图生命周期:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class MainActivity extends AppCompatActivity {
private MapView mMapView;//声明地图组件
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/*********注意此处的代码顺序,有严格要求***********/
//初始化SDK应用的Context全局变量
SDKInitializer.initialize(getApplicationContext());
setContentView(R.layout.activity_main);
mMapView = findViewById(R.id.bmapview);
}

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

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

@Override
protected void onDestroy() {
super.onDestroy();
mMapView.onDestroy();
mMapView = null;
}
}

到此,我们并没有全部完成。如果我们就这样去真机上测试,大概率无法进入界面,会直接闪退。

我们需要在创建一个继承至Application的java类,我在此创建MyApplication.java:

1
2
3
4
5
6
7
public class MyApplication extends Application {
@Override
public void onCreate() {
SDKInitializer.initialize(this);
super.onCreate();
}
}

这下,我们是真的完成了代码的编写。

我们可以进入真机测试阶段,但是一定记得要将手机联网,否则无法运行!

定位到我的位置

定位到我的位置的步骤

定位到我的位置步骤

实现在百度地图API上定位我的位置

准备:准备一张定位图标图片资源(也可以不准备,使用默认),将其命名为loc,置于res/drawable目录下。

本案例在 上述应用百度地图API显示地图案例进行修改

布局资源文件activity_main.xml不变,自定义类MyApplication.java不变。

在AndroidManifest.xml中添加两条权限,用于获取GPS定位服务:

1
2
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

修改MainActivity.java,实现定位服务:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
public class MainActivity extends AppCompatActivity {

private MapView mMapView;//声明地图组件
private BaiduMap mBaiduMap;//定义百度地图对象
private boolean isFirstLoc = true;//记录是否是第一次定位
private MyLocationConfiguration.LocationMode locationMode; //当前定位模式

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/*********注意此处的代码顺序,有严格要求***********/
//初始化SDK应用的Context全局变量
SDKInitializer.initialize(getApplicationContext());
setContentView(R.layout.activity_main);
mMapView = findViewById(R.id.bmapview);
mBaiduMap = mMapView.getMap();//获取百度地图对象
//获取系统的LocationManager对象
LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
//添加需要的权限检查
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
//设置每一秒获取一次location信息
locationManager.requestLocationUpdates(
locationManager.GPS_PROVIDER, //GPS定位提供者
1000, //更新数据时间为1秒
1, //位置间隔为1米
//位置监听器
new LocationListener() {//GPS定位信息发生改变时触发,用于更新位置信息

@Override
public void onLocationChanged(Location location) {
locationUpdates(location);//GPS信息发生改变时,更新位置
}

//
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {

}

@Override
public void onProviderEnabled(String provider) {

}

@Override
public void onProviderDisabled(String provider) {

}
}
);
//从GPS中获取最新的定位信息
Location location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
locationUpdates(location); //将最新的定位信息传递给创建的locationUpdates()方法中
}

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

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

@Override
protected void onDestroy() {
super.onDestroy();
mMapView.onDestroy();
mMapView = null;
}

@Override
protected void onStart() {
super.onStart();
//启动定位图层
mBaiduMap.setMyLocationEnabled(true);
}

@Override
protected void onStop() {
super.onStop();
//停止定位图层
mBaiduMap.setMyLocationEnabled(false);
}

//获取指定的查询信息
public void locationUpdates(Location location) {
if (location != null) { //如果location不为空
//获取当前用户的经纬度
LatLng ll = new LatLng(location.getLatitude(), location.getLongitude());
Log.i("Location", "纬度:" + location.getLatitude()
+ "|经度:" + location.getLongitude());
if (isFirstLoc) {
//更新坐标位置
MapStatusUpdate u = MapStatusUpdateFactory.newLatLng(ll);
mBaiduMap.animateMapStatus(u); //设置地图位置
isFirstLoc = false;//取消第一次定位
}
//构造定位数据
MyLocationData locationData =
new MyLocationData.Builder().accuracy(location.getAccuracy())
.direction(100) //设置方向信息
.latitude(location.getLatitude()) //设置纬度坐标
.longitude(location.getLongitude()) //设置经度坐标
.build();
//设置定位数据
mBaiduMap.setMyLocationData(locationData);
//设置自定义图标
BitmapDescriptor bitmapDescriptor =
BitmapDescriptorFactory.fromResource(R.drawable.loc);
//设置定位模式 自定义定位模式 不设置选择默认
locationMode = MyLocationConfiguration.LocationMode.NORMAL;
//设置构造方式 自定义图标 不设置则选择默认
MyLocationConfiguration config =
new MyLocationConfiguration(locationMode, true, bitmapDescriptor);
//显示定位图标
mBaiduMap.setMyLocationConfiguration(config);
} else {
Log.i("Location", "没有获取到GPS信息");
}
}
}

测试要点:使用真机测试,打开位置服务及权限,真机需要联网,尽量在空旷区域、而不是室内进行测试。


Android传感器及LBS完