2016-09-26 71 views
1

我需要在用戶靠近指定位置時通知用戶。我爲此使用Geofencing API。當我測試Android模擬器與模擬位置的應用程序時,一切工作正常。具有模擬位置的真實設備也一樣。但是當我走路並且手機處於深度睡眠模式時,Geofence將在5 - 10分鐘後閃光。如果我位於geofences半徑範圍內,並且我解鎖了手機,請立即打開任何使用位置我的地理圍欄觸發器的應用程序。 (是Android 5.1,Motorolla Moto G的1 - 第一代)當設備處於深度睡眠(休眠)模式時,Geofence正在等待意圖啓動太遲

下面是這樣的,我如何註冊我的地理圍欄:

public void registerLocation(RegisterAlarmRequestModel data) { 
    if (isLocationDetectionAllowed() && isConnected) { 
     GeofencingRequest geofencingRequest = prepareGeofencingRequest(prepareGeofence(data)); 
     PendingIntent pendingIntent = prepareIntent(data.getId()); 
     PendingResult<Status> result = GeofencingApi.addGeofences(
       googleApiClient, geofencingRequest, pendingIntent); 
     Status status = result.await(); 
     if (status.isSuccess()) 
      Log.d("Location", "Geofence " + data.getId() + " has been registered"); 
    } 
} 

//preparing Geofence Pending Intent which will be triggered 
private PendingIntent prepareIntent(int alarmId) { 
    Intent intent = new Intent(context, LocationRingingService.class); 
    intent.putExtra(LocationRingingService.KEY_ALARM_ID, alarmId); 
    return PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); 
} 

private GeofencingRequest prepareGeofencingRequest(Geofence geofence) { 
    GeofencingRequest.Builder builder = new GeofencingRequest.Builder() 
      .setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER) 
      .addGeofence(geofence); 
    return builder.build(); 
} 

private Geofence prepareGeofence(RegisterAlarmRequestModel data) { 
    Geofence geofence = new Geofence.Builder() 
      .setRequestId(String.valueOf(data.getId())) 
      .setCircularRegion(data.getLatitude(), data.getLongitude(), data.getRadius()) 
      .setLoiteringDelay(100) 
      .setExpirationDuration(Geofence.NEVER_EXPIRE) 
      .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER) 
      .build(); 
    return geofence; 
} 

對於接收意圖我使用IntentService:

@Override 
protected void onHandleIntent(Intent intent) { 
    Log.d("Location", "accepted intent: " + intent.toString()); 
    //database request 
} 

這我是如何在清單中註冊我的服務的:

<service 
     android:name=".plugin.delivery.ringing.location.service.LocationRingingService" 
     android:enabled="true" 
     android:exported="true" /> 

更新:我需要抓住用戶剛剛進入geofence的時刻,儘可能準確。我有一個想法:註冊半徑大於需要的地理圍欄(例如,如果需要100米半徑,註冊200-300米半徑的地理圍欄)。當用戶進入更大半徑的Geophence時 - 啓動位置更新服務以提高地理圍欄精度。當用戶剛進入時 - 禁用位置服務。

回答

1

對其進行改進,讓我們進行一些檢查

1)使用廣播接收器得到它容易引發的,而不是服務。並設置意圖過濾器的優先級。

對於e.g

<receiver 
     android:name=".youpackage.GeoReceiver" 
     android:exported="true"> 
     <intent-filter android:priority="999"> 
      <action android:name="yourpackage.ACTION_RECEIVE_GEOFENCE" /> 
     </intent-filter> 
    </receiver> 

,待處理的目的將是:

Intent intent = new Intent("yourpackage.ACTION_RECEIVE_GEOFENCE"); 
PendingIntent pendingIntent = PendingIntent.getBroadcast(
       youractivity, 
       0, 
       intent, 
       PendingIntent.FLAG_UPDATE_CURRENT); 

2)當你的GPS進入休眠模式時,我們需要喚醒它在創建地理圍欄。一旦你創建了地理圍欄,你就可以開始Ping你的GPS,直到你進入ENTER狀態。這將有助於觸發它。

public class GPSService extends Service implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener { 

    GoogleApiClient mGoogleApiClient; 
    LocationRequest locationRequest; 

    public GPSService() { 
    } 

    @Override 
    public IBinder onBind(Intent intent) { 
    // TODO: Return the communication channel to the service. 
    throw new UnsupportedOperationException("Not yet implemented"); 
    } 

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


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

    mGoogleApiClient.connect(); 
    } 

    @Override 
    public void onLocationChanged(Location location) { 

    Utility.ReadAndWriteData(this, Utility.readFileName(this), "Still Geofence is not triggered!!!"); 

    } 

    @Override 
    public void onConnected(Bundle bundle) { 

     locationRequest = LocationRequest.create(); 
     locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); 
     locationRequest.setFastestInterval(1000); 
     locationRequest.setInterval(2000); 
    LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient,locationRequest,this); 

    } 

    @Override 
    public void onConnectionFailed(ConnectionResult connectionResult) { 

    } 

    @Override 
    public void onConnectionSuspended(int i) { 

    } 

    @Override 
    public void onDestroy() { 
     super.onDestroy(); 

     if(mGoogleApiClient.isConnected()) { 

    LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this); 

     } 
} 

而且不要忘了立即停止此服務,當你得到ENTER過渡或導致漏電池。此服務僅用於將GPS從睡眠模式喚醒。

+1

謝謝你的快速回答!會嘗試它。祝你有美好的一天:) – kolodach

+0

永遠歡迎! :) – Jai

+0

不幸的是,建議並不能解決我的問題:( – kolodach

1

問題是,當您的手機處於深度睡眠狀態時,它不會準確更新位置。更新位置的最準確方式是GPS,而且這也是電池消耗最多的方式。其他更新位置的方法(如使用蜂窩網絡)將消耗更少的電量,但也不夠準確。默認情況下,geofences希望在發送意圖之前真正確定您處於地理圍欄中。在深度睡眠時很難獲得這種準確性,因爲手機沒有獲得準確的位置數據。

當您解鎖手機並使用位置感知應用時,地理圍欄立即觸發的原因是該應用更新了您的地理圍欄看到的然後發送意圖的LastLocation。當您的手機處於深度睡眠狀態時,該位置不會更新。

使用地理圍欄還有一些設置可以調整以提高響應速度。我看到你已經在使用setLoiteringDelay,試着玩弄不同的值,也許嘗試非常小的值,看看會發生什麼。您也可以爲setNotificationResponsiveness設置一個值,其工作方式與此類似。這樣做會讓你的柵欄響應更快,但它可能會耗費更多的電池壽命。還請閱讀setLoiteringDelaysetNotificationResponsiveness的API參考。如果還沒有,請閱讀geofence troubleshooting部分。

您還可以增加地理圍欄的大小,嘗試加倍並測試。由於在深度睡眠時您的位置精確度較低,這將使您的手機更容易確定它位於地理圍欄內部,並且一旦它確定它位於地理圍欄內部,就會發送該意向。

我希望這有助於!

+0

感謝您的詳細解答!你解釋了許多晦澀的時刻!我想我需要更新我的問題,以便更好地理解我的問題。 – kolodach

相關問題