6 Stimmen

Geofences werden nicht ausgelöst (PendingIntents und BroadcastReceiver)

Ich habe das Android-Tutorial mit Geofences verwendet, das offensichtlich nicht funktioniert, wenn die App geschlossen ist. Also, nachdem ich mich umgesehen habe, habe ich festgestellt, dass Benutzer bryce auf SO BroadcastReceiver verwendet hat, damit Geofences ausgelöst werden, auch wenn die App nicht aktiv ist (Link zu seiner SO-Frage).

Ich kann einfach nicht die Geofences auslösen, wenn ich mich außerhalb/innerhalb des registrierten Standorts bewege. Hier ist mein Vorgehen:

    /**
     * GeoLocation-Bibliothek
     */
    mGeoLocation = new GeoLocation(sInstance);

    /**
     * Initialisierung von mReceiver
     */
    mReceiver = new Receiver();
    sInstance.registerReceiver(mReceiver, mReceiver.createIntentFilter());

Und innerhalb der GeoLocation-Klasse:

/*
 * Erstellen Sie ein PendingIntent, das ein IntentService in Ihrer
 * App auslöst, wenn ein Geofence-Übergang auftritt.
 */
protected PendingIntent getTransitionPendingIntent() {
    if (mGeoPendingIntent != null) {
        return mGeoPendingIntent;
    }

    else {

        // Erstellen Sie einen expliziten Intent
        //  Intent intent = new Intent(mContext,
        //          ReceiveTransitionsIntentService.class);

        Intent intent = new Intent(getClass().getPackage().getName() + ".GEOFENCE_RECEIVE");

        /**
         * Rückgabe des PendingIntents
         */
        return PendingIntent.getBroadcast(
                mContext,
                0,
                intent,
                PendingIntent.FLAG_UPDATE_CURRENT);

    }
}

So erstelle ich einen neuen Geofence:

                        Geofence fence = new Geofence.Builder()
                                .setRequestId(hashCode)
                                        // beim Betreten dieses 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 Metern
                                )
                                .setExpirationDuration(Geofence.NEVER_EXPIRE)
                                .build();

                        mGeofences.add(fence);

Das Array wird gefüllt und wir rufen die Methode AddGeofences in der Geofence-Klasse auf

mGeoLocation.AddGeofences(mGeofences);

AndroidManifest.xml für die Receiver-Klasse:

Und die Receiver-Klasse soll einfach protokollieren, wenn der Geofence ausgelöst wird

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

    Log.d("sfen", "Broadcast empfangen "+ action +" aber nicht benötigt.");
}

Das Problem ist, dass die Geofences NUR ausgelöst werden, wenn ich die Karte in meiner App öffne, wo ich die Standorte auswähle. Wenn ich die App schließe (im Hintergrund laufen lasse), wird nichts ausgelöst und die Geofence-Übergänge lösen nichts aus.

Kann mir jemand sagen, was ich falsch mache?

0voto

Jishi Chen Punkte 624

Du solltest IntentService verwenden, um Geofencing-Ereignisse zu empfangen (nicht den Empfänger). Ich habe ein Demo unter https://github.com/chenjishi/android_location_demo geschrieben.

1. Definiere zunächst LocationClient

    private LocationClient locationClient;

2. Initialisiere es

@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. Bei erfolgreicher Verbindung, registriere Geofences

@Override
public void onConnected(Bundle bundle) {
    ArrayList storeList = getStoreList();
    if (null != storeList && storeList.size() > 0) {
        ArrayList geofenceList = new ArrayList();
        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. Definiere schließlich den IntentService zum Empfangen von Geofencing-Ereignissen

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 Fehlerbehandlung
    } else {
        int transitionType = LocationClient.getGeofenceTransition(intent);
        if (transitionType == Geofence.GEOFENCE_TRANSITION_ENTER ||
                transitionType == Geofence.GEOFENCE_TRANSITION_EXIT) {
            List triggerList = LocationClient.getTriggeringGeofences(intent);

            for (Geofence geofence : triggerList) {
                generateNotification(geofence.getRequestId(), "Adresse, die Sie definiert haben");
            }
        }
    }
}

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());
}

}

0voto

David Wasser Punkte 89884

Ich sehe 2 Probleme. Erstens erstellen Sie das PendingIntent nicht richtig. Es sieht so aus, als ob Sie dies tun:

    // Erstellen Sie ein explizites Intent
    //  Intent intent = new Intent(mContext,
    //          ReceiveTransitionsIntentService.class);

    Intent intent = new Intent(getClass().getPackage().getName() + ".GEOFENCE_RECEIVE");

Erstens ist der Kommentar inkorrekt. Dies ist NICHT ein "explizites Intent". Dies erzeugt ein Intent, das nur eine Aktion enthält. Sie benötigen ein "explizites Intent", das Ihren BroadcastReceiver startet.

Sie müssen stattdessen dies tun:

    Intent intent = new Intent(mContext, Receiver.class);

Das zweite Problem ist, dass Sie Ihrem BroadcastReceiver erlauben müssen, von anderen Apps gestartet zu werden. Dazu müssen Sie es im Manifest als "exportiert" deklarieren. Ändern Sie Ihren Manifesteintrag wie folgt:

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X