地理围栏未触发(未决意图和广播接收器)

Posted

技术标签:

【中文标题】地理围栏未触发(未决意图和广播接收器)【英文标题】:Geofences not triggering (pendingintents and broadcastreceiver) 【发布时间】:2014-11-03 07:45:50 【问题描述】:

我使用了带有 Geofences 的 android 教程,很明显,当应用程序关闭时它不起作用。因此,在四处搜索之后,我注意到用户 b-ryce 在 SO 上使用了 BroadcastReceiver,因此即使应用程序未处于活动状态,也会触发地理围栏 (link for his SO question)。

当我移出/移入注册位置时,我无法强制触发地理围栏。这是我的程序:

    /**
     * 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>

接收器类应该只在地理围栏触发时记录

public void onReceive(Context context, Intent intent) 
    String action = intent.getAction();

    Log.d("sfen", "Broadcast recieved "+ action +" but not needed.");

问题是,只有当我在我的应用程序中打开我选择位置的地图时,才会触发地理围栏。关闭应用(在后台运行)不会触发任何事情,地理围栏转换也不会触发任何事情。

谁能告诉我我做错了什么?

【问题讨论】:

当您打开另一个使用地理定位的应用程序时,地理围栏是否会触发?例如,如果您设置了地理围栏,请关闭您的应用程序,然后打开 Google 地图并移入或移出地理围栏区域。这会触发地理围栏吗? @RussWilde - 是的,当我在后台移动我的应用并打开 Google 地图时,我的两个操作都会被触发。 这很不幸;我对地理围栏的结果非常复杂,包括在 IFTTT 和 Field Trip 等其他应用程序中,每次我想知道为什么一些地理围栏没有可靠地触发并且我猜到 Android 的底层位置服务只是没有更新经常足以捕捉到每个位置。遗憾的是,如果是这种情况,我没有有用的解决方案,但我也对其他人可以提供的任何答案感兴趣。 @gregor - 嗨,你介意分享一下你最终是如何完成这项工作的吗? @Rat-a-tat-a-tatRatatouille 直到今天,我都找不到合适的解决方案。联系谷歌位置服务开发商也没有工作(因为没有人回复)。 【参考方案1】:

你应该使用 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());

【讨论】:

嗨。如前所述,我还将引用 b-ryce 的回复:So after playing around with this a bit, it looks like the ReceiveTransitionsIntentService as defined in the sample code will stop getting the notifications when the app is not around. I think this is a big problem with the example code。所以看起来使用地理围栏的结果非常复杂。仍然不知道为什么这有时对某些人有用,而对另一些人总是有用... @gregor 你确定你手机的定位服务复选框被选中了吗???地理围栏需要启用位置服务,您应该给用户一个启用它的指南。 我做到了。但是,我确实注意到其中一部手机,因为我已将其从 4.4.2 升级到 4.4.4 以更好地工作。将进行更多测试并发布结果(如果有) @JishiChen 你能看一下这个question吗?

以上是关于地理围栏未触发(未决意图和广播接收器)的主要内容,如果未能解决你的问题,请参考以下文章

您可以在本地广播中使用未决意图吗?

从Intent服务发送短信 - 无法接收广播以检查是否发送了短信

实施地理围栏 - 在应用程序未运行时接收地理围栏转换事件

地理围栏 - 触发“GEOFENCE_NOT_AVAILABLE”的问题

广播接收器未接收到意图 (RemoteViews / PendingIntent)

android广播接收器中未调用onReceive()进行静态广播