Geofences does not work when the application is killed

I know that similar questions were asked before, but the answers were not perfect.

I created an application with geofences using a sample code from the Android developer site. I did not use the general settings for storing geopotentials, since I do not delete geo objects. I am testing the application from geofence, but my smartphone receives notifications every time the application starts, and there are no notifications when the application is killed. Why is this happening? I think I should be notified even when the application is killed.

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

}

+6
source share
1 answer

Well, maybe a little late, but I will send an answer to the question of how I myself fixed this problem. Two things:

1) I added geo objects every time I launch the MainActivity API and geofences, fires the geofencing event if you add geo-images when you are already in the specified geoprobe (i.e., starting from the geofence application when you are already in the geoforum) . Therefore, I changed my code in the onConnected method to add geo objects only if they have not been added before. (Implemented verification using general settings)

  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) . It turned out that the reasons for not receiving notifications when the application is unavailable were

i) Either I switched location services to the device (on / off / battery saving / device only / high accuracy) at least once after adding geo-images or

ii) The device rebooted.

To overcome this, I added a broadcast receiver to listen for device reboots and switching location services. In the receiver, I add geo objects again if the device rebooted or the search services switched.

  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> . . 
+8
source

Source: https://habr.com/ru/post/985250/


All Articles