/**
-
定位状态判断
-
@param name GPS、WiFi、Cell
-
@param status 状态码
-
@return
*/
private String statusUpdate(String name, int status) {
if (“gps”.equals(name)) {
switch (status) {
case 0:
return “GPS开关关闭”;
case 1:
return “GPS开关打开”;
case 3:
return “GPS可用,代表GPS开关打开,且搜星定位成功”;
case 4:
return “GPS不可用”;
default:
return “”;
}
} else if (“wifi”.equals(name)) {
switch (status) {
case 0:
return “Wi-Fi开关关闭”;
case 1:
return “Wi-Fi开关打开”;
case 2:
return “权限被禁止,禁用当前应用的 ACCESS_COARSE_LOCATION 等定位权限”;
case 5:
return “位置信息开关关闭,在android M系统中,此时禁止进行Wi-Fi扫描”;
default:
return “”;
}
} else if (“cell”.equals(name)) {
switch (status) {
case 0:
return “cell 模块关闭”;
case 1:
return “cell 模块开启”;
case 2:
return “定位权限被禁止,位置权限被拒绝通常发生在禁用当前应用的 ACCESS_COARSE_LOCATION 等定位权限”;
default:
return “”;
}
}
return “”;
}
然后改变一下打印中信息
Log.d(TAG, “name:” + name + " desc:" + statusUpdate(name, status));
再运行一下。
现在就知道详细的信息了,开发者可以根据这些信息来查找问题,好了这个方法就介绍到这里,下面进行后台定位。
③ 后台定位
实际使用过程中,后台定位是用的比较多的,你可能无法感知,但是它就是存在,属于一种服务,定位服务,运行在后台Service中,下面来尝试一下。
首先还是来添加一个后台定位的按钮吧。因为是写文章,那么肯定要有一个立体的感受,因此给后台定位放置一个启动按钮。
在activity_main.xml中增加
<Button
android:id=“@+id/btn_background_positioning”
android:layout_width=“match_parent”
android:layout_height=“wrap_content”
android:text=“后台定位” />
放在单次定位按钮的下面。
然后回到MainActivity中。
//后台定位
private Button btnBackgroundPositioning;
//定位模式
private String positioningMode = null;
然后initView中
因为现在已经有三种定位的模式了,为了方便区别所以定义了一个成员变量positioningMode 。下面来看onClick方法。
然后在showLocationInfo中,
这样在显示定位信息的时候就知道当前的定位是什么模式了,下面就该专心的来写这个后台定位了。
首先在AndroidManifest.xml中配置定位服务
<service
android:name=“com.tencent.map.geolocation.s”
android:foregroundServiceType=“location” />
同时为了适配Android9.0和10.0还需要增加两个权限
其中这个ACCESS_BACKGROUND_LOCATION还需要动态申请,因此,在MainActivity中的permissionsRequest方法中,增加这个权限。
实际上,这里应该还需要再判断一下,如果是Android10.0及以上增请求ACCESS_BACKGROUND_LOCATION,不是则和原来一样。不过这个可以自行更改,因为我本身就是Android10.0所以就不改了。
下面定义一些成员变量
//通知管理
private NotificationManager notificationManager;
//通知ID
private static final int LOC_NOTIFICATIONID = 20;
//通知渠道名
private static final String NOTIFICATION_CHANNEL_NAME = “后台定位”;
//是否创建了通知渠道
private boolean isCreateChannel = false;
增加创建通知的方法
/**
-
创建通知
-
@return
*/
private Notification buildNotification() {
Notification.Builder builder = null;
Notification notification = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
//Android 8.0及以后对Notification进行了修改 需要创建通知渠道
if (notificationManager == null) {
notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
}
String channelId = getPackageName();
if (!isCreateChannel) {
NotificationChannel notificationChannel = new NotificationChannel(channelId,
NOTIFICATION_CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT);
//是否在桌面icon右上角展示小圆点
notificationChannel.enableLights(true);
//小圆点颜色
notificationChannel.setLightColor(Color.BLUE);
//是否在久按桌面图标时显示此渠道的通知
notificationChannel.setShowBadge(true);
notificationManager.createNotificationChannel(notificationChannel);
isCreateChannel = true;
}
builder = new Notification.Builder(getApplicationContext(), channelId);
} else {
builder = new Notification.Builder(getApplicationContext());
}
builder.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(“PositionServiceDemo”)
.setContentText(“正在后台运行”)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
.setWhen(System.currentTimeMillis());
if (android.os.Build.VERSION.SDK_INT >= 16) {
notification = builder.build();
} else {
notification = builder.getNotification();
}
return notification;
}
然后看onClick,通过前台定位创建通知,然后开始定位。
可以看到我在图中图停止定位做了更改,增加了一个stopPositioning方法
/**
- 停止定位
*/
private void stopPositioning() {
if (positioningMode == null) {
showMsg(“您还没有开始定位呢?”);
return;
}
if (“单次定位”.equals(positioningMode)) {
showMsg(“单次定位会自动停止,但您想点一下我也没办法!╮(╯▽╰)╭”);
return;
}
mLocationManager.removeUpdates(this);
if (“后台定位”.equals(positioningMode)) {
//关闭后台定位
mLocationManager.disableForegroundLocation(true);
}
showMsg(“定位已停止”);
}
下面来说明一下,当点击后台定位时,启用前台定位,通过定义好的通知id和通知创建通知,将服务由后台转到前台,此时通知会显示,然后开始定位获取定位信息,当
点击停止定位按钮时,如果当前是后台定位则先停止定位,再关闭前台定位,此时通知会消失。
下面来看看实际的运行效果。
可以看状态栏,我相信你能发现这个细节,OK,后台定位就写好了。
④ 地理围栏
地理围栏是通过划定一个区域范围,如果用户进出这片区域,会通过广播的形式通知上层。用户可以创建多个地理围栏,但是一旦不再使用对应围栏,应当尽快将围栏移除。目前腾讯定位SDK只支持划定圆形区域,不支持多边形和不规则形状。
下面来看我的解释,你工作之后用过钉钉吗?钉钉有一个上下班打卡的功能,是要你在规定的打卡时间和空间范围内,打开钉钉会自动打卡,那么这里就是一个地理围栏,你把它当成是一个圆,你的公司处于圆心位置,那么公司会设置打卡的最远距离,由公司向周围辐射,形成一个圆。那么只要上下班时在这个范围内都会自动打卡,现在也有很多的打开软件会模仿这一个业务功能。
OK,通过上面的讲述你对地理围栏有了一个大概的认知了,那么下面进入实操环节,首先修改一下activity_main.xml中的布局代码
<TextView
android:text=“地理围栏”
android:padding=“8dp”
android:textSize=“18sp”
android:layout_width=“wrap_content”
android:layout_height=“wrap_content”/>
<Button
android:id=“@+id/btn_add_fence”
android:layout_width=“match_parent”
android:layout_height=“wrap_content”
android:text=“添加围栏” />
<Button
android:id=“@+id/btn_remove_fence”
android:layout_width=“match_parent”
android:layout_height=“wrap_content”
android:text=“移除围栏” />
放在停止定位按钮的下面,然后进入到MainActivity
//添加围栏
private Button btnAddFence;
//移除围栏
private Button btnRemoveFence;
然后在initView中
onClick中增加
在使用地理围栏时会用到广播,这里在com.llw.demo下右键创建一个receiver包,然后新建一个GeofenceEventReceiver继承BroadcastReceiver,然后重写onReceive方法,代码如下:
package com.llw.demo.receiver;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.location.LocationManager;
import android.widget.Toast;
public class GeofenceEventReceiver extends BroadcastReceiver {
private static final String ACTION_TRIGGER_GEOFENCE = “com.llw.demo.receiver.GeofenceEventReceiver”;
@Override
public void onReceive(Context context, Intent intent) {
if (intent == null
|| !GeofenceEventReceiver.ACTION_TRIGGER_GEOFENCE.equals(intent
.getAction())) {
return;
}
String tag = intent.getStringExtra(“tag”);
double lng = intent.getDoubleExtra(“longitude”, 0);
double lat = intent.getDoubleExtra(“latitude”, 0);
// 进入围栏还是退出围栏
boolean enter = intent.getBooleanExtra(
LocationManager.KEY_PROXIMITY_ENTERING, true);
Toast.makeText(context,“是否进入围栏范围:”+ enter,Toast.LENGTH_SHORT).show();
}
}
然后广播有两种注册方式,静态和动态的,下面先来看静态的注册,打开AndroidManifest.xml
添加如下配置
然后还需要配置一个权限,这个权限不需要动态申请。
下面回到MainActivity,去定义一些变量,并且完成地理围栏的初始化配置。
//地理围栏管理
private TencentGeofenceManager mTencentGeofenceManager;
//围栏别名
private String geofenceName = “测试范围”;
//围栏
private TencentGeofence geofence;
//设置动作
private static final String ACTION_TRIGGER_GEOFENCE = “com.llw.demo.receiver.GeofenceEventReceiver”;
//PendingIntent
private PendingIntent pi;
然后新建一个初始化地理围栏的方法。
/**
- 初始化地理围栏
*/
private void initGeofence() {
//实例