2015-04-16 74 views
6

我知道類似的問題之前已經被問過,但答案並不完美。當應用程序被殺時Geofences無法工作

我使用來自android開發人員網站的示例代碼創建了一個帶geofences的應用程序。我沒有使用任何共享首選項來存儲地理柵欄,因爲我沒有移除地理柵欄。我正在測試地理圍欄內的應用程序,但是我的智能手機每次運行應用程序都會收到通知,並且在應用程序死亡時不會收到通知。爲什麼會發生?我想即使應用程序被殺,我也應該收到通知。

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地理柵欄只適用於打開的應用程序](http://stackoverflow.com/questions/19434999/android-geofence-only-works-with-opened-app) –

+0

我也一樣,你解決它我使用下面的答案,但從廣播GeofenceTransationService不打電話我做了一些事情worng –

回答

8

好,可能有點晚,但我會後我如何解決了這個問題,我自己的答案。兩件事情:

1)我將每一次我跑在MainActivity和地理圍欄API時觸發地理圍欄事件的地理圍欄,如果添加地理圍欄時,你已經指定的地理圍欄內(即啓動地理圍欄應用程序時你已經在地理圍欄內)。 因此,我在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)原來的原因時,應用程序不可用不接收通知是

ⅰ)或者是我在裝置切換位置服務(上/關/節電/僅設備/高精確度)至少一次在我添加地理柵欄之後或者,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清單

. 
. 
. 
<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,它是trigring inital通知我將其更改爲GeofencingRequest.INITIAL_TRIGGER_ENTER,它的工作感謝您的幫助 –

+0

你是如何存儲你的latittude和經度在你的常量文件中,我目前存儲在我的hashmap:LANDMARKS.put(「Test」,新的LatLng(-29.78976400000001,30。822186999999985)); 所以wouldnt能夠訪問它們實現你使用的代碼 –

相關問題