2017-02-23 75 views
2

Я использовал геофоны с помощью GoogleApiClient -> при срабатывании, Служба подключается к GoogleApiClient и добавляет несколько Geofences.Android geofence BroadcastReceiver

Перед тем, как я получил еще один IntentService, зарегистрированный как «обратный вызов» для событий геозонности. Это работало более или менее, но только тогда, когда приложение было на переднем плане. Поскольку я хочу получать события геофранции также, когда приложение находится в фоновом режиме/закрыто, я немного исказил и переместил обратный вызов из IntentService в BroadcastReceiver, теперь я даже не получаю события геозонности, когда приложение находится на переднем плане.

Я уже задавала в интернете для решения (наиболее распространенный ответ: изменение слушателя событий от службы до BroadcastReceiver - но это сделало вещи хуже)

Вот мои настройки:

Manifest:

<receiver 
     android:name=".service.GeofenceReceiver"> 
     <intent-filter> 
      <action android:name="com.example.geofence.ACTION_RECEIVE" /> 
     </intent-filter> 
    </receiver> 

    <receiver android:name=".service.BootReceiver"> 
     <intent-filter> 
      <action android:name="android.intent.action.BOOT_COMPLETED" /> 
     </intent-filter> 
    </receiver> 

    <service 
     android:name=".service.GeofenceRegistrationService" 
     android:enabled="true" 
     android:exported="false" /> 

BootReceiver:

public class BootReceiver extends BroadcastReceiver { 

    @Override 
    public void onReceive(Context context, Intent intent) { 
     GeofenceRegistrationService.startService(context,true); 
    } 
} 

GeofenceReceiver:

public class GeofenceReceiver extends BroadcastReceiver { 

    @Override 
    public void onReceive(Context context, Intent intent) { 

     Logger.e(this, "GeofenceReceiver called"); 

     GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent); 

     if (geofencingEvent.hasError()) { 
      Logger.e(this, String.valueOf(geofencingEvent.getErrorCode())); 

     } else { 
     Logger.i(this, geofencingEvent.getTriggeringLocation().getLatitude() + ", " +geofencingEvent.getTriggeringLocation().getLongitude()); 

     } 
    } 
} 

GeofenceRegistrationService:

public class GeofenceRegistrationService extends Service implements ConnectionCallbacks, OnConnectionFailedListener, ResultCallback<Status> { 


    public static final String KEY_FORCE_CLEAN = "FORCE_CLEAN"; 

    public static void startService(Context context, boolean forceClean) { 

     Intent intent = new Intent(context, GeofenceRegistrationService.class); 

     intent.putExtra(KEY_FORCE_CLEAN, forceClean); 

     context.startService(intent); 

    } 

    private GoogleApiClient mGoogleApiClient; 
    private PendingIntent mGeofencePendingIntent; 

    @Nullable 
    @Override 
    public IBinder onBind(Intent intent) { 
    return null; 
    } 

    @Override 
    public int onStartCommand(Intent intent, int flags, int startId) { 

    if (isLocationPermissionGranted() && intent != null) { 

     startGeofenceRegistration(); 

    } else { 

     this.stopSelf(startId); 

    } 

    return START_REDELIVER_INTENT; 
    } 

    public void startGeofenceRegistration() { 

    if (mGoogleApiClient == null) { 
     mGoogleApiClient = buildAPIClient(); 
    } 

    if (!mGoogleApiClient.isConnected() && !mGoogleApiClient.isConnecting()) { 
     mGoogleApiClient.connect(); 
    } else { 
     registerGeofences(); 
    } 
    } 


    private boolean isLocationPermissionGranted() { 
    return ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED; 
    } 

    private synchronized GoogleApiClient buildAPIClient() { 

    return new GoogleApiClient.Builder(this) 
      .addConnectionCallbacks(this) 
      .addOnConnectionFailedListener(this) 
      .addApi(LocationServices.API) 
      .build(); 

    } 

    private void addGeoFences() { 
    if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) { 
     try { 
      LocationServices.GeofencingApi.addGeofences(
        mGoogleApiClient, 
        createGeofencesRequest(), 
        getGeofencePendingIntent() 
      ).setResultCallback(this); 
     } catch (SecurityException securityException) { 
      Logger.e(this, securityException); 
     } 
    } 
    } 

    private void removeGeoFences() { 
    if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) { 
     try { 
      LocationServices.GeofencingApi.removeGeofences(
        mGoogleApiClient, 
        getGeofencePendingIntent() 
      ).setResultCallback(this); 
     } catch (SecurityException securityException) { 
      Logger.e(this, securityException); 
     } 
    } 
} 

private PendingIntent getGeofencePendingIntent() { 
    if (mGeofencePendingIntent != null) { 
     return mGeofencePendingIntent; 
    } 
    //Intent intent = new Intent(this, GeofenceEventHandlingService.class); 
    Intent intent = new Intent("com.example.geofence.ACTION_RECEIVE"); 
    mGeofencePendingIntent = PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); 
    return mGeofencePendingIntent; 
    } 

    @Override 
    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) { 
    Logger.d(this, "CONNECTION_FAILED"); 
    } 

    @Override 
    public void onConnected(@Nullable Bundle bundle) { 
    Logger.d(this, "CONNECTED"); 
    registerGeofences(); 

    } 

    private void registerGeofences() { 
    removeGeoFences(); 
    addGeoFences(); 
    } 

    @Override 
    public void onConnectionSuspended(int i) { 
    Logger.d(this, "connection suspended"); 
    } 

    private GeofencingRequest createGeofencesRequest() { 
    GeofencingRequest.Builder builder = new GeofencingRequest.Builder(); 

    List<Poi> pois = Config.getPersistenceService().getPois(); 

    int counter = 0; 
    for (Poi p : pois) { 
     if (p.isCoordinateSet()) { 
      Geofence fence = new Geofence.Builder() 
        .setRequestId(String.valueOf(p.getId())) 
        .setCircularRegion(p.getLat(), p.getLon(), 2500) // TODO 
        .setExpirationDuration(Geofence.NEVER_EXPIRE) 
        .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER) 
        .build(); 

      builder.addGeofence(fence); 

      counter++; 
     } 
    } 

    Logger.i(this, "added geofences: " + counter); 

    return builder.build(); 
    } 


    @Override 
    public void onDestroy() { 

    if (mGoogleApiClient != null && (mGoogleApiClient.isConnected() || mGoogleApiClient.isConnecting())) { 
     mGoogleApiClient.disconnect(); 
    } 

    super.onDestroy(); 
    } 

    @Override 
    public void onResult(@NonNull Status status) { 
    if (status.isSuccess()) { 
     Logger.d(this, "Geofences added"); 

    } else { 
     Logger.d(this, "Failed to add geofences"); 
    } 
    } 


} 

Что я делаю неправильно? Что я наблюдаю?

ответ

2

Вот что я получил для работы, но имейте в виду, что я добавляю и удаляю свои Geofences из Activity и получаю Geofence Transitions в IntentService.

Я думаю, вы должны попробовать создать свой Intent указав new Intent(context, YourReceiverClass) и создать PendingIntent с помощью PendingIntent.getBroadcast(). Вот что я использовал, хотя:

private PendingIntent getGeofencePendingIntent(){ 
    // Re-use the Pending Intent if it already exists 
    if(mGeofencePendingIntent != null){ 
     return mGeofencePendingIntent; 
    } 

    // The intent for the IntentService to receive the transitions 
    Intent intent = new Intent(getContext(), GeofenceTransitionsIntentService.class); 

    // Create the pending intent 
    mGeofencePendingIntent = PendingIntent 
      .getService(getContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); 

    return mGeofencePendingIntent; 
} 

А внутри моего IntentService:

@Override 
protected void onHandleIntent(Intent intent) { 
    GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent); 
    if (geofencingEvent.hasError()) { 
     String errorMessage = GeofenceErrorMessages.getErrorString(this, 
       geofencingEvent.getErrorCode()); 
     Log.e(LOG_TAG, errorMessage); 
     return; 
    } 

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

    // Test that the reported transition was of interest. 
    if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER || 
      geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) { 

     // Get the geofences that were triggered. A single event can trigger multiple geofences. 
     List<Geofence> triggeringGeofences = geofencingEvent.getTriggeringGeofences(); 

     // Do something with geofences 

    } 
} 
+1

Это сделал трюк - благодаря Сэмми. Меняя все возможные части, я наблюдал за PendingIntent.getService(), который действительно должен быть PendingIntent.getBroadcast(). –

1

Ну, я столкнулся с подобной проблемой, но в моем случае я хотел бы сделать наоборот, переход от службы к Broadcast. И, проверив свой вопрос, я заметил, что, возможно, вы не получили переход на геосферу на трансляцию, потому что вы запрашивали услугу в методе getPendingIntent.

private PendingIntent getGeofencePendingIntent() { 
    (...) 
    mGeofencePendingIntent = PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); 
    (...) 
    } 

В моем случае я положил getBroadcast вместо этого и работал нормально.

mGeofencePendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); 

Надеюсь, это вам помогло.

Cheers.

0

в вашем опубликованном коде, ваш фильтр намерений был неправильным.

Вместо:

<receiver 
    android:name=".service.GeofenceReceiver"> 
    <intent-filter> 
     <action android:name="com.example.geofence.ACTION_RECEIVE" /> 
    </intent-filter> 
    </receiver> 

вы должны были использовать:

<receiver 
    android:name=".service.GeofenceReceiver"> 
    <intent-filter> 
     <action android:name="com.example.geofence.ACTION_RECEIVE_GEOFENCE" /> 
    </intent-filter> 
    </receiver> 
Смежные вопросы