2015-04-16 4 views
6

Я знаю, что подобные вопросы были заданы раньше, но ответы не были идеальными.Geofences не работает, когда приложение убито

Я создал приложение с geofences, используя образец кода с сайта разработчика Android. Я не использовал общие настройки для хранения геопотенциалов, так как я не удаляю геообъекты. Я тестирую приложение из geofence, но мой смартфон получает уведомления каждый раз, когда приложение запускается, и никаких уведомлений не наблюдается, когда приложение убито. Почему это происходит? Я думаю, что я должен получать уведомления, даже когда приложение будет убито.

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

показать код ... –

+1

Пожалуйста, проверьте это другой вопрос. Ответил здесь: [android geofence работает только с открытым приложением] (http://stackoverflow.com/questions/19434999/android-geofence-only-works-with-opened-app) –

+0

У меня то же самое вы решили я использую ответ ниже, но из трансляции GeofenceTransationService не звонит, я что-то делаю worng –

ответ

8

Хорошо, Может быть немного поздно, но я выложу ответ на то, как я исправил этому вопросу сам. Две вещей:

1) я сложение геозонов каждый раз, когда я бег MainActivity и Геозоны API вызывает событие Geofencing, если вы добавите геозоны, когда вы уже внутри указанной геозоны (т.е. запуска приложения GeoFence когда вы уже находитесь в геофоруме). Поэтому я изменил свой код в методе onConnected, чтобы добавить геообъекты, только если они не добавлены ранее. (Осуществляется проверка с использованием общих предпочтений)

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) Оказывается, причины не получать уведомления, когда приложение не доступно было

я) Либо я переключены службы определения местоположения в устройстве (на/off/battery saving/device only/высокая точность) по крайней мере один раз после того, как я добавил геообъекты или,

ii) Устройство было перезагружено.

Чтобы преодолеть это, я добавил широковещательный приемник, чтобы прослушивать перезагрузку устройств и работу служб определения местоположения. В приемнике я снова добавляю геообъекты, если устройство перезагрузилось или службы поиска переключились.

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

Я использую тот же код, но транслятор приемника не запускает GeofenceTransitionsIntentServic любую помощь? –

+0

ahhh я был GeofencingRequest.INITIAL_TRIGGER_DWELL, и это было триггером уведомления о внесении изменений, я меняю его на GeofencingRequest.INITIAL_TRIGGER_ENTER, и он работает спасибо за помощь. –

+0

Как вы сохранили свою latittude и долготу в файле констант, я в настоящее время храню шахту в hashmap: LANDMARKS.put («Тест», новый LatLng (-29.78976400000001,30.822186999999985)); Так бы не смог получить к ним доступ, используя код, который вы использовали –

Смежные вопросы