地理围栏无法触发

6

我正在尝试在我的应用程序中实现Geofence,但问题是当我在标记的位置时它没有触发。

我所做的是从Place Picker中设置纬度经度

我获取的值是正确的,因为我在Google Maps上放置了这个位置,因为我读到很多答案说人们设置了错误的经纬度值

我有两个类:GeofenceSingleton.classGeofenceTransitionsIntentService

GeofenceSingleton.class看起来像:

public class GeofenceSingleton implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, ResultCallback<Status> {

private GoogleApiClient googleApiClient;
private static GeofenceSingleton _singleInstance;
private static Context appContext;
private static final String ERR_MSG = "Application Context is not set!! " +
        "Please call GeofenceSngleton.init() with proper application context";
private PendingIntent mGeofencePendingIntent;
private static ArrayList<Geofence> mGeofenceList;


private GeofenceSingleton() {
    if (appContext == null)
        throw new IllegalStateException(ERR_MSG);

    this.googleApiClient = new GoogleApiClient.Builder(this.appContext)
            .addApi(LocationServices.API)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .build();
    this.googleApiClient.connect();
    mGeofenceList = new ArrayList<Geofence>();
}

/**
 * @param applicationContext
 */
public static void init(Context applicationContext) {
    appContext = applicationContext;
}

public static GeofenceSingleton getInstance() {
    if (_singleInstance == null)
        synchronized (GeofenceSingleton.class) {
            if (_singleInstance == null)
                _singleInstance = new GeofenceSingleton();
        }
    return _singleInstance;
}

@Override
public void onConnected(Bundle bundle) {

}

@Override
public void onConnectionSuspended(int i) {

}

@Override
public void onConnectionFailed(ConnectionResult connectionResult) {

}

public void addGeofence(Location location, String uid) {
    mGeofenceList.add(new Geofence.Builder()
            .setRequestId(uid)
            .setCircularRegion(
                    location.getLatitude(),
                    location.getLongitude(),
                    500
            )
            .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER)
            .setExpirationDuration(1000000)
            .build());
}

private GeofencingRequest getGeofencingRequest() {
    GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
    builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER);
    builder.addGeofences(mGeofenceList);
    return builder.build();
}

private PendingIntent getGeofencePendingIntent() {
     // Reuse the PendingIntent if we already have it.
    if (mGeofencePendingIntent != null) {
        return mGeofencePendingIntent;
    }
    Intent intent = new Intent(appContext, GeofenceSingleton.class);
    // We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when calling
    // addGeofences() and removeGeofences().
    return PendingIntent.getService(appContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}

public void startGeofencing() {
    if (!googleApiClient.isConnected()) {
        Toast.makeText(appContext, "API client not connected", Toast.LENGTH_SHORT).show();
        return;
    }

    LocationServices.GeofencingApi.addGeofences(
            googleApiClient,
     // The GeofenceRequest object.
            getGeofencingRequest(),
    // A pending intent that that is reused when calling removeGeofences(). This
    // pending intent is used to generate an intent when a matched geofence
    // transition is observed.
            getGeofencePendingIntent()
    ).setResultCallback(this); // Result processed in onResult().
    Toast.makeText(appContext,"Geofencing started", Toast.LENGTH_LONG).show();
}



public void removeGeofence(){
    LocationServices.GeofencingApi.removeGeofences(
            googleApiClient,
// This is the same pending intent that was used in addGeofences().
            getGeofencePendingIntent()
    );
}

@Override
public void onResult(Status status) {
    if (status.isSuccess()) {
// Update state and save in shared preferences.

        Toast.makeText(
                appContext,
                "YO",
                Toast.LENGTH_SHORT
        ).show();
    } else {
        Toast.makeText(
                appContext,
                "NOO",
                Toast.LENGTH_SHORT
        ).show();
    }
}
}

并且 GeofenceTransitionsIntentService

public class GeofenceTransitionsIntentService extends IntentService {

private static final String TAG = "Geofence-Service";
private Handler handler;
SharedPreferences sp;
SharedPreferences.Editor editor;
String EmailName, MessageEmail;
Context mContext;
Boolean EmailSent = false;

public GeofenceTransitionsIntentService() {
    super(TAG);
}

@Override
public void onCreate() {
    super.onCreate();
    this.mContext = this;
    sp = PreferenceManager.getDefaultSharedPreferences(this);
    handler = new Handler();
}

@Override
protected void onHandleIntent(Intent intent) {

    final GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
    if (geofencingEvent.hasError()) {
        Log.e(TAG, "Error in geofencing event");
        return;
    }

      // Get the transition type.
    final int geofenceTransition = geofencingEvent.getGeofenceTransition();

      // Test that the reported transition was of interest.
    if (geofenceTransition == 1) {

        handler.post(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(getApplicationContext(), "Entered", Toast.LENGTH_SHORT).show();
                sendNotification();
            }
        });
        Log.i(TAG, "Entered");


    }

    else {
        // Log the error.
        handler.post(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(getApplicationContext(), "Sorry you are out", Toast.LENGTH_SHORT).show();
            }
        });
        Log.e(TAG, String.valueOf(geofenceTransition));
    }

}

private void sendNotification() {
    Toast.makeText(GeofenceTransitionsIntentService.this, "HEEEEEEEY I'M IN", Toast.LENGTH_SHORT).show();



}

在我的MainActivity中,我有以下内容:
GeofenceSingleton.init(this); //If I don't call this the class doesn't work
this.geofenceSingleton = GeofenceSingleton.getInstance();

接下来我会按如下方式建立一个地理围栏(Geofence)

Location geofence = new Location("");
geofence.setLatitude(Double.parseDouble(latitude));
geofence.setLongitude(Double.parseDouble(longitude));
geofenceSingleton.addGeofence(geofence, GeofenceKey);
geofenceSingleton.startGeofencing();

注意事项

我在我的manifest.xml中添加了<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

我将service声明为<service android:name=".GeofenceTransitionsIntentService"/>

并且我在我的build.gradle文件中添加了这一行: compile 'com.google.android.gms:play-services:7.8.0'

它只显示了Toast.makeText(appContext,"YO",Toast.LENGTH_SHORT).show();,这是因为状态是成功的,并且还显示了Toast.makeText(appContext,"Geofencing started", Toast.LENGTH_LONG).show();,这意味着已经开始。

问题

为什么我的IntentService从未被调用过?

我测试了一下,输入了我家的Lat/Long,应该会触发,不是吗?


它有效吗?顺便说一下,我创建了一个新项目,并使用这三个文件尝试了一下,它可以工作,所以对你也会有用。 - varunkr
也许你还没有“进入”区域,这就是为什么没有事件的原因。当地理围栏被创建时,你已经在里面了。为了在创建区域时触发它,并且你已经在里面,你需要这样设置:builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER); - Carlos López Marí
3个回答

6
这永远不会奏效,因为你所做的是...
Intent intent = new Intent(appContext, GeofenceSingleton.class);

传递意图到GeofenceSingleton?

您需要做的是:

Intent intent = new Intent(appContext, GeofenceTransitionsIntentService.class);

@Skizo-ozᴉʞS 我能够获得“ENTER NOTIFICATION”,但是“EXIT NOTIFICATION”没有被触发。 - KK_07k11A0585
@Skizo-ozᴉʞS 当我提供的半径小于25米时,为什么没有收到“ENTER NOTIFICATION”通知?你有什么想法为什么它不起作用? - KK_07k11A0585
您设置了setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER),因此退出通知未被触发。您需要添加GEOFENCE_TRANSITION_ENTER以便获取退出转换。 - Shubham AgaRwal

0

请确保您的服务和广播在清单文件中启用了这些属性。

  android:enabled="true"
  android:exported="true"

1
导出时不需要分配权限吗? - Brill Pappin

0
如果您的Intent已经使用正确的类构建(请参见varunkr's answer),您还需要确保该服务也包含在您的AndroidManifest.xml中。
<application
    ...

    <service android:name=".GeofencingTransitionIntentService" />

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接