2015-04-16 7 views
6

Ich weiß, dass ähnliche Fragen schon einmal gestellt wurden, aber die Antworten waren nicht perfekt.Geofences funktioniert nicht, wenn App getötet wird

Ich habe eine App mit Geofences mit dem Beispielcode von Android-Entwickler-Website erstellt. Ich habe keine geteilten Einstellungen zum Speichern von Geofences verwendet, da ich die Geofences nicht lösche. Ich teste die App im Geofence, aber mein Smartphone erhält jedes Mal Benachrichtigungen, wenn die App ausgeführt wird, und es werden keine Benachrichtigungen angezeigt, wenn die App beendet wird. Warum passiert das? Ich denke, ich sollte Benachrichtigungen erhalten, auch wenn die App getötet wird.

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

zeigen Sie Ihren Code ... –

+1

Bitte diese andere Frage prüfen. Beantwortete hier: [Android Geofence funktioniert nur mit geöffneter App] (http://StackOverflow.com/Questions/19434999/android-geofence-only-works-with-opened-app) –

+0

Ich habe das gleiche haben Sie gelöst Ich benutze die Antwort unten, aber von Broadcast der GeofenceTransationService ist nicht anrufen bin ich etwas tun worng –

Antwort

8

Ok, vielleicht ein bisschen spät, aber ich werde die Antwort auf schreiben, wie ich dieses Problem selbst behoben. Zwei Dinge:

1) Ich war Addieren der geofences jedes Mal, wenn ich laufen die MainActivity und geofences API die Geofencing Ereignis auslöst, wenn Sie die geofences hinzufügen, wenn Sie bereits im angegebenen Geofence (dh Start der Geofence App, wenn Du bist bereits im Geofence). Also habe ich meinen Code in der onConnected-Methode geändert, um die Geofences nur hinzuzufügen, wenn sie vorher nicht hinzugefügt wurden. (Implementiert einen Scheck mit Gemeinschafts-Präferenzen)

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) aus Schaltet die Gründe für die keine Benachrichtigungen empfangen, wenn der App nicht verfügbar waren

i) Entweder ich hin- und Ortungsdienste im Gerät (auf/aus/Batteriesparen/nur Gerät/hohe Genauigkeit) mindestens einmal nach dem Hinzufügen der Geofences oder,

ii) Das Gerät wurde neu gestartet.

Um dies zu beheben, habe ich einen Broadcast-Empfänger hinzugefügt, um Geräte-Neustarts und Standortdienste anzuhören, die umgeschaltet werden. Im Empfänger füge ich die Geofences erneut hinzu, wenn das Gerät entweder neu gestartet oder die Standortdienste umgeschaltet wurden.

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

Ich benutze den gleichen Code, aber Broadcast-Empfänger nicht starten GeofenceTransitionsIntentServic keine Hilfe? –

+0

ahhh ich war GeofencingRequest.INITIAL_TRIGGER_DWELL und es war Triggerung erste Benachrichtigung ich ändere es zu GeofencingRequest.INITIAL_TRIGGER_ENTER und es funktioniert Danke für die Hilfe –

+0

Wie hast du deine Größe und Länge in Ihrer Konstanten-Datei gespeichert, ich bin derzeit speichern meine in einem hashmap: LANDMARKS.put ("Test", neuer LatLng (-29.78976400000001,30.822186999999985)); So wäre nicht in der Lage, darauf zuzugreifen, die Umsetzung des Codes, den Sie verwendet –