2015-04-16 39 views
6

So che domande simili sono già state fatte prima, ma le risposte non erano perfette.Geofences non funziona quando l'app viene uccisa

Ho creato un'app con geofences utilizzando il codice di esempio dal sito Web degli sviluppatori Android. Non ho usato alcuna preferenza condivisa per archiviare i geofischi perché non sto rimuovendo i geofences. Sto testando l'app dall'interno del geofence, ma il mio smartphone riceve notifiche ogni volta che l'app viene eseguita e non vengono rilevate notifiche quando l'app viene uccisa. Perché succede? Penso che dovrei ricevere le notifiche anche quando l'app viene uccisa.

MainActivity

public class MainActivity extends ActionBarActivity { 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.drawer_layout); 
    ..... 
GeofencingTask myTask = new GeofencingTask(); 
    myTask.execute(); 
} 
private class GeofencingTask extends AsyncTask<String,Void,String> implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener { 

    @Override 
    protected void onPreExecute() { 


    } 


    @Override 
    protected String doInBackground(String... params) { 


     mGoogleApiClient = new GoogleApiClient.Builder(MainActivity.this) 
       .addConnectionCallbacks(this) 
       .addOnConnectionFailedListener(this) 
       .addApi(LocationServices.API) 
       .build(); 

     mGoogleApiClient.connect(); 
     mGeofenceList = new ArrayList<Geofence>(); 

     mGeofenceList.add(new Geofence.Builder() 
       .setRequestId("1") 

       .setCircularRegion(
         Constants.MyAPP_LOCATION_LATITUDE, 
         Constants.MyAPP_LOCATION_LONGITUDE, 
         Constants.MyAPP_RADIUS 
       ) 
       .setExpirationDuration(Constants.GEOFENCE_EXPIRATION_TIME) 
       .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER | 
         Geofence.GEOFENCE_TRANSITION_EXIT) 
       .build()); 
     return null; 

    } 

    protected void onPostExecute(String s) { 
     if (s == null) { 
      return; 

     } 
    } 

    @Override 
    public void onConnected(Bundle bundle) { 

     LocationServices.GeofencingApi.addGeofences(
       mGoogleApiClient, 
       getGeofencingRequest(), 
       getGeofencePendingIntent() 
     ); 

     Toast.makeText(MainActivity.this, "Starting gps", Toast.LENGTH_SHORT).show(); 
    } 

    @Override 
    public void onConnectionSuspended(int i) { 

    } 

    @Override 
    public void onConnectionFailed(ConnectionResult connectionResult) { 

     if (connectionResult.hasResolution()) { 
      try { 
       connectionResult.startResolutionForResult(MainActivity.this, 
         Constants.CONNECTION_FAILURE_RESOLUTION_REQUEST); 
      } catch (IntentSender.SendIntentException e) { 
       Log.e(TAG, "Exception while resolving connection error.", e); 
      } 
     } else { 
      int errorCode = connectionResult.getErrorCode(); 
      Log.e(TAG, "Connection to Google Play services failed with error code " + errorCode); 
     } 
    } 

} 

GeofenceTransitionsIntentService.java

public class GeofenceTransitionsIntentService extends IntentService{ 

String TAG = "GeofenceTransitionsIntentService"; 
int geofenceTransition; 

public GeofenceTransitionsIntentService() { 
    super("name"); 

} 

@Override 
public void onCreate() { 
    super.onCreate(); 
} 

@Override 
protected void onHandleIntent(Intent intent) { 
    GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent); 
    if (geofencingEvent.hasError()) { 
     int errorCode = geofencingEvent.getErrorCode(); 
     Log.e(TAG, "Location Services error: " + errorCode); 
    } 
    geofenceTransition = geofencingEvent.getGeofenceTransition(); 

    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 triggeringGeofences = geofencingEvent.getTriggeringGeofences(); 

     // Get the transition details as a String. 
     String geofenceTransitionDetails = getGeofenceTransitionDetails(
       this, 
       geofenceTransition, 
       triggeringGeofences 
     ); 
     Log.i("GeofenceTransitionDetails",geofenceTransitionDetails); 

     // Send notification and log the transition details. 
     sendNotification(geofenceTransitionDetails); 
     sendInOutsTask myTask = new sendInOutsTask(); 
     myTask.execute(); 

     Log.i(TAG, geofenceTransitionDetails); 
    } else { 
     // Log the error. 
     Log.e(TAG, getString(R.string.geofence_transition_invalid_type, 
       geofenceTransition)); 
    } 

} 

private String getGeofenceTransitionDetails(
     Context context, 
     int geofenceTransition, 
     List<Geofence> triggeringGeofences) { 

    String geofenceTransitionString = getTransitionString(geofenceTransition); 

    // Get the Ids of each geofence that was triggered. 
    ArrayList triggeringGeofencesIdsList = new ArrayList(); 
    for (Geofence geofence : triggeringGeofences) { 
     triggeringGeofencesIdsList.add(geofence.getRequestId()); 
    } 
    String triggeringGeofencesIdsString = TextUtils.join(", ", triggeringGeofencesIdsList); 

    return geofenceTransitionString; 

} 

/** 
* Posts a notification in the notification bar when a transition is detected. 
* If the user clicks the notification, control goes to the MainActivity. 
*/ 
private void sendNotification(String notificationDetails) { 

    Intent notificationIntent = new Intent(getApplicationContext(), MainActivity.class); 
    TaskStackBuilder stackBuilder = TaskStackBuilder.create(this); 
    stackBuilder.addParentStack(MainActivity.class); 
    stackBuilder.addNextIntent(notificationIntent); 
    PendingIntent notificationPendingIntent = 
      stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT); 
    NotificationCompat.Builder builder = new NotificationCompat.Builder(this); 
    builder.setSmallIcon(R.mipmap.zemoso_logo) 
      .setLargeIcon(BitmapFactory.decodeResource(getResources(), 
        R.mipmap.zemoso_logo)) 
      .setColor(Color.RED) 
      .setContentTitle(notificationDetails) 
      .setContentText(getString(R.string.geofence_transition_notification_text)) 
      .setContentIntent(notificationPendingIntent); 
    builder.setAutoCancel(true); 

    NotificationManager mNotificationManager = 
      (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); 

    mNotificationManager.notify(0, builder.build()); 
} 

private String getTransitionString(int transitionType) { 
    switch (transitionType) { 
     case Geofence.GEOFENCE_TRANSITION_ENTER: 
      return Constants.WELCOME_NOTIFICATION; 
     case Geofence.GEOFENCE_TRANSITION_EXIT: 
      return Constants.EXIT_NOTIFICATION; 
     default: 
      return null; 
    } 
} 

}

+0

mostrare il codice ... –

+1

prega di consultare questo altro problema. Risposta: [Android geofence funziona solo con l'app aperta] (http://stackoverflow.com/questions/19434999/android-geofence-only-works-with-opened-app) –

+0

ho lo stesso l'hai risolto io uso la risposta qui sotto ma da broadcast il GeofenceTransationService non sta chiamando sto facendo qualcosa usg –

risposta

8

Ok, può essere un po 'tardi, ma vi posterò la risposta su come ho risolto questo problema io stesso. Due cose:

1) stavo aggiungendo le geofences ogni volta che faccio funzionare il MainActivity e geofences API attiva l'evento Geofencing, se si aggiungono i geofences quando si è già all'interno del geofence specificato (cioè a partire l'applicazione geofence quando sei già dentro il Geofence). Così ho cambiato il mio codice nel metodo onConnected per aggiungere i geofence solo se non sono stati aggiunti in precedenza. (Implementato un controllo utilizzando le preferenze condivise)

public void onConnected(Bundle bundle) { 

    Log.i(TAG, "Connected to GoogleApiClient"); 
    SharedPreferences sharedPrefs = MainActivity.this.getSharedPreferences("GEO_PREFS", Context.MODE_PRIVATE); 
    String geofencesExist = sharedPrefs.getString("Geofences added", null); 

    if (geofencesExist == null) { 
     LocationServices.GeofencingApi.addGeofences(
       mGoogleApiClient, 
       getGeofencingRequest(), 
       getGeofencePendingIntent(this) 
     ).setResultCallback(new ResultCallback<Status>()   { 
      @Override 
      public void onResult(Status status) { 
       if (status.isSuccess()) { 
        SharedPreferences sharedPrefs = MainActivity.this.getSharedPreferences("GEO_PREFS", Context.MODE_PRIVATE); 
        SharedPreferences.Editor editor = sharedPrefs.edit(); 
        editor.putString("Geofences added", "1"); 
        editor.commit(); 
       } 
      } 
     }); 
    } 
} 

2) Attiva le ragioni per non ricevere notifiche quando l'applicazione non è disponibile erano

i) O io attivata servizi di localizzazione nel dispositivo (su/off/risparmio batteria/solo dispositivo/alta precisione) almeno una volta dopo aver aggiunto i geofence o,

ii) Il dispositivo è stato riavviato.

Per ovviare a ciò, ho aggiunto un ricevitore di trasmissione per ascoltare i riavvii del dispositivo ei servizi di localizzazione attivati. Nel ricevitore, aggiungo di nuovo i Geofence se il dispositivo è stato riavviato o i servizi di localizzazione sono stati attivati.

public class BootReceiver extends BroadcastReceiver implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, ResultCallback<Status> { 

private static GoogleApiClient mGoogleApiClient; 
private static List<Geofence> mGeofenceList; 
private static PendingIntent mGeofencePendingIntent; 
private static final String TAG = "BootReceiver"; 
Context contextBootReceiver; 

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


    contextBootReceiver = context; 

    SharedPreferences sharedPrefs; 
    SharedPreferences.Editor editor; 
    if ((intent.getAction().equals("android.location.MODE_CHANGED") && isLocationModeAvailable(contextBootReceiver)) || (intent.getAction().equals("android.location.PROVIDERS_CHANGED") && isLocationServciesAvailable(contextBootReceiver))) { 
     // isLocationModeAvailable for API >=19, isLocationServciesAvailable for API <19 
     sharedPrefs = context.getSharedPreferences("GEO_PREFS", Context.MODE_PRIVATE); 
     editor = sharedPrefs.edit(); 
     editor.remove("Geofences added"); 
     editor.commit(); 
     if (!isGooglePlayServicesAvailable()) { 
      Log.i(TAG, "Google Play services unavailable."); 
      return; 
     } 

     mGeofencePendingIntent = null; 
     mGeofenceList = new ArrayList<Geofence>(); 

     mGeofenceList.add(new Geofence.Builder() 
       .setRequestId("1") 

       .setCircularRegion(
         Constants.MyAPP_LOCATION_LATITUDE, 
         Constants.MyAPP_LOCATION_LONGITUDE, 
         Constants.MyAPP_LOCATION_RADIUS 
       ) 
       .setExpirationDuration(Constants.GEOFENCE_EXPIRATION_TIME) 
       .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_DWELL | 
         Geofence.GEOFENCE_TRANSITION_EXIT) 
       .setLoiteringDelay(30000) 
       .build()); 


     mGoogleApiClient = new GoogleApiClient.Builder(contextBootReceiver) 
       .addConnectionCallbacks(this) 
       .addOnConnectionFailedListener(this) 
       .addApi(LocationServices.API) 
       .build(); 


     mGoogleApiClient.connect(); 
    } 
} 

private boolean isLocationModeAvailable(Context context) { 

    if (Build.VERSION.SDK_INT >= 19 && getLocationMode(context) != Settings.Secure.LOCATION_MODE_OFF) { 
     return true; 
    } 
    else return false; 
} 

public boolean isLocationServciesAvailable(Context context) { 
    if (Build.VERSION.SDK_INT < 19) { 
     LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); 
     return (lm.isProviderEnabled(LocationManager.GPS_PROVIDER) || lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER)); 

    } 
    else return false; 
} 

public int getLocationMode(Context context) { 
    try { 
     return Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.LOCATION_MODE); 
    } catch (Settings.SettingNotFoundException e) { 
     e.printStackTrace(); 
    } 

    return 0; 
} 

@Override 
public void onConnected(Bundle bundle) { 
    Log.i(TAG, "Connected to GoogleApiClient"); 
    SharedPreferences sharedPrefs = contextBootReceiver.getSharedPreferences("GEO_PREFS", Context.MODE_PRIVATE); 
    String geofencesExist = sharedPrefs.getString("Geofences added", null); 

    if (geofencesExist == null) { 
     LocationServices.GeofencingApi.addGeofences(
       mGoogleApiClient, 
       getGeofencingRequest(), 
       getGeofencePendingIntent(contextBootReceiver) 
     ).setResultCallback(new ResultCallback<Status>() { 
      @Override 
      public void onResult(Status status) { 
       if (status.isSuccess()) { 
        SharedPreferences sharedPrefs = contextBootReceiver.getSharedPreferences("GEO_PREFS", Context.MODE_PRIVATE); 
        SharedPreferences.Editor editor = sharedPrefs.edit(); 
        editor.putString("Geofences added", "1"); 
        editor.commit(); 
       } 
      } 
     }); 

    } 

} 

@Override 
public void onConnectionSuspended(int i) { 

} 

@Override 
public void onConnectionFailed(ConnectionResult connectionResult) { 
    if (connectionResult.hasResolution()) { 
     try { 
      connectionResult.startResolutionForResult((android.app.Activity) contextBootReceiver, 
        Constants.CONNECTION_FAILURE_RESOLUTION_REQUEST); 
     } catch (IntentSender.SendIntentException e) { 
      Log.i(TAG, "Exception while resolving connection error.", e); 
     } 
    } else { 
     int errorCode = connectionResult.getErrorCode(); 
     Log.i(TAG, "Connection to Google Play services failed with error code " + errorCode); 
    } 

} 

@Override 
public void onResult(Status status) { 

} 

private boolean isGooglePlayServicesAvailable() { 
    int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(contextBootReceiver); 
    if (resultCode != ConnectionResult.SUCCESS) { 
     if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) { 
      GooglePlayServicesUtil.getErrorDialog(resultCode, (android.app.Activity) contextBootReceiver, 
        Constants.PLAY_SERVICES_RESOLUTION_REQUEST).show(); 
     } else { 
      Log.i(TAG, "This device is not supported."); 
     } 
     return false; 
    } 
    return true; 
} 

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


static PendingIntent getGeofencePendingIntent(Context context) { 

    if (mGeofencePendingIntent != null) { 
     return mGeofencePendingIntent; 
    } 
    Intent intent = new Intent(context, GeofenceTransitionsIntentService.class); 
    return PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); 
} 

}

Android Manifest

. 
. 
. 
<receiver 
     android:name=".BootReceiver" 
     android:enabled="true" 
     android:exported="false" > 
     <intent-filter> 
      <action android:name="android.intent.action.BOOT_COMPLETED" /> 
      <action android:name="android.location.MODE_CHANGED" /> 
      <action android:name="android.location.PROVIDERS_CHANGED" /> 
     </intent-filter> 
    </receiver> 
. 
. 
+0

io uso lo stesso codice ma il ricevitore broadcast non avvia GeofenceTransitionsIntentServic alcun aiuto? –

+0

ahhh ero GeofencingRequest.INITIAL_TRIGGER_DWELL e stava attivando notifica iniziale lo ho cambiato in GeofencingRequest.INITIAL_TRIGGER_ENTER e funziona grazie per l'aiuto –

+0

Come hai archiviato la latittude e la longitudine nel tuo file di costanti, sto attualmente memorizzando il mio in un hashmap: LANDMARKS.put ("Test", new LatLng (-29.78976400000001,30.822186999999985)); Quindi non sarei in grado di accedervi implementando il codice che hai usato –