我已经将 Android 教程与地理围栏一起使用,显然,当应用程序关闭时,它不起作用。因此,经过搜索后,我注意到 SO 上的用户 b-ryce 使用了 BroadcastReceiver,因此即使应用程序未处于活动状态,地理围栏也会被触发(他的 SO 问题的链接)。
当我移出/移入注册位置时,我无法强制触发地理围栏。这是我的程序:
/**
* GeoLocation library
*/
mGeoLocation = new GeoLocation(sInstance);
/**
* mReceiver init
*/
mReceiver = new Receiver();
sInstance.registerReceiver(mReceiver, mReceiver.createIntentFilter());
在 GeoLocation 类中:
/*
* Create a PendingIntent that triggers an IntentService in your
* app when a geofence transition occurs.
*/
protected PendingIntent getTransitionPendingIntent() {
if (mGeoPendingIntent != null) {
return mGeoPendingIntent;
}
else {
// Create an explicit Intent
// Intent intent = new Intent(mContext,
// ReceiveTransitionsIntentService.class);
Intent intent = new Intent(getClass().getPackage().getName() + ".GEOFENCE_RECEIVE");
/**
* Return the PendingIntent
*/
return PendingIntent.getBroadcast(
mContext,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT);
}
}
这是我创建新地理围栏的方法:
Geofence fence = new Geofence.Builder()
.setRequestId(hashCode)
// when entering this geofence
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER | Geofence.GEOFENCE_TRANSITION_EXIT)
.setCircularRegion(
Double.parseDouble(single.getSetting("latitude")),
Double.parseDouble(single.getSetting("longitude")),
Float.parseFloat(single.getSetting("radius")) // radius in meters
)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.build();
mGeofences.add(fence);
数组被填充,我们在 Geofence 类中调用 AddGeofences 方法
mGeoLocation.AddGeofences(mGeofences);
接收器类的AndroidManifest.xml:
<!-- RECEIVER -->
<receiver android:name=".Receiver" >
</receiver>
Receiver 类应该只在地理围栏触发时记录
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Log.d("sfen", "Broadcast recieved "+ action +" but not needed.");
}
问题是,只有当我在应用程序中打开地图并选择位置时,地理围栏才会触发。关闭应用程序(在后台运行)不会触发任何内容,地理围栏转换也不会触发任何内容。
有人可以告诉我我做错了什么吗?
你应该使用IntentService来接收地理围栏事件(而不是接收器)。我在https://github.com/chenjishi/android_location_demo写了一个演示。
1.首先定义LocationClient
private LocationClient locationClient;
2.初始化它
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
int resp = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
if (resp == ConnectionResult.SUCCESS) {
locationClient = new LocationClient(this, this, this);
locationClient.connect();
}
}
3.连接成功后,注册地理围栏
@Override
public void onConnected(Bundle bundle) {
ArrayList<Store> storeList = getStoreList();
if (null != storeList && storeList.size() > 0) {
ArrayList<Geofence> geofenceList = new ArrayList<Geofence>();
for (Store store : storeList) {
float radius = (float) store.radius;
Geofence geofence = new Geofence.Builder()
.setRequestId(store.id)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER | Geofence.GEOFENCE_TRANSITION_EXIT)
.setCircularRegion(store.latitude, store.longitude, radius)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.build();
geofenceList.add(geofence);
}
PendingIntent geoFencePendingIntent = PendingIntent.getService(this, 0,
new Intent(this, GeofenceIntentService.class), PendingIntent.FLAG_UPDATE_CURRENT);
locationClient.addGeofences(geofenceList, geoFencePendingIntent, this);
}
}
4.最后定义IntentService来接收地理围栏事件
public class GeofenceIntentService extends IntentService {
public static final String TRANSITION_INTENT_SERVICE = "ReceiveTransitionsIntentService";
public GeofenceIntentService() {
super(TRANSITION_INTENT_SERVICE);
}
@Override
protected void onHandleIntent(Intent intent) {
if (LocationClient.hasError(intent)) {
//todo error process
} else {
int transitionType = LocationClient.getGeofenceTransition(intent);
if (transitionType == Geofence.GEOFENCE_TRANSITION_ENTER ||
transitionType == Geofence.GEOFENCE_TRANSITION_EXIT) {
List<Geofence> triggerList = LocationClient.getTriggeringGeofences(intent);
for (Geofence geofence : triggerList) {
generateNotification(geofence.getRequestId(), "address you defined");
}
}
}
}
private void generateNotification(String locationId, String address) {
long when = System.currentTimeMillis();
Intent notifyIntent = new Intent(this, MainActivity.class);
notifyIntent.putExtra("id", locationId);
notifyIntent.putExtra("address", address);
notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.dac_logo)
.setContentTitle(locationId)
.setContentText(address)
.setContentIntent(pendingIntent)
.setAutoCancel(true)
.setDefaults(Notification.DEFAULT_SOUND)
.setWhen(when);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify((int) when, builder.build());
}
}
我看到两个问题。首先是您没有正确创建
PendingIntent
。看起来你正在这样做:
// Create an explicit Intent
// Intent intent = new Intent(mContext,
// ReceiveTransitionsIntentService.class);
Intent intent = new Intent(getClass().getPackage().getName() + ".GEOFENCE_RECEIVE");
首先,评论是错误的。这不是“明确的
Intent
”。这会生成一个仅包含 ACTION 的 Intent
。您需要一个“明确的 Intent
”来启动您的 BroadcastReceiver
。
您需要这样做:
Intent intent = new Intent(mContext, Receiver.class);
第二个问题是您需要允许其他应用程序启动您的
BroadcastReceiver
。为此,您需要在清单中声明它“已导出”。将您的清单条目更改为:
<!-- RECEIVER -->
<receiver android:name=".Receiver"
android:exported="true"/>