2016-12-23 18 views
1

我試圖構建一個地理圍欄應用程序接收意圖,但似乎在主要活動開始僅註冊地理圍欄,並意圖服務停止接收他們,當應用程序被關閉。因此,我將添加geofence邏輯移入intent服務(以及意圖處理代碼)並確保服務開始,但現在該服務根本沒有收到任何意圖!Android應用程序添加地理圍欄和相同的服務

服務定義

public class GeofenceTransitionsIntentService extends IntentService implements ConnectionCallbacks, OnConnectionFailedListener, ResultCallback<Status> 

一切在服務(谷歌API客戶端生成並連接)在onCreate完成的,同時與意圖處理程序和地理圍欄登記東西onConnected寄存器地理圍欄等,基本上,我我試圖在同一個服務中實施大量借用的geofencing示例代碼(來自文檔),目的是處理這些意圖。

所有主要的活動確實是啓動該服務,並提請相關的服務接收地理圍欄通知的事情。

如果您需要更多的信息,只是讓我知道。

編輯

好了,所以它看起來像我們需要更多的信息 - 該服務的概述:

public class GeofenceTransitionsIntentService extends IntentService implements ConnectionCallbacks, OnConnectionFailedListener, ResultCallback<Status> { 

    protected static final String TAG = "GeofenceTransitionsIS"; 

    protected GoogleApiClient mGoogleApiClient; 
    protected ArrayList<Geofence> mGeofenceList; 
    private boolean mGeofencesAdded; 
    private PendingIntent mGeofencePendingIntent; 
    private SharedPreferences mSharedPreferences; 

    public GeofenceTransitionsIntentService() { 
     super(TAG); 
    } 

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

     buildGoogleApiClient(); 
     populateGeofenceList(); 
     mGoogleApiClient.connect(); 

    } 

    ... 

    @Override 
    protected void onHandleIntent(Intent intent) { 
     GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent); 
     // handle the intent, send a notification 
    } 


    private void sendNotification(String notificationDetails) { 
     // sends a notification 
    } 

    @Override 
    public void onConnected(Bundle connectionHint) 
    { 
     LocationServices.GeofencingApi.addGeofences(
       mGoogleApiClient, 
       getGeofencingRequest(), 
       getGeofencePendingIntent() 
     ).setResultCallback(this); 
    } 

    // straight out of the example 
    private GeofencingRequest getGeofencingRequest() 
    { 
     ... 
    } 


    // from a branch of the example that reuses the pending intent 
    private PendingIntent getGeofencePendingIntent() 
    { 
     if (mGeofencePendingIntent != null) 
     { 
      return mGeofencePendingIntent; 
     } 

     Intent intent = new Intent(this, GeofenceTransitionsIntentService.class); 
     mGeofencePendingIntent = PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); 
     return mGeofencePendingIntent; 
    } 

    public void populateGeofenceList() { 
     for (thing place : listofplaces) { 
      mGeofenceList.add(...) 
     } 
    } 

    protected synchronized void buildGoogleApiClient() { 
     mGoogleApiClient = new GoogleApiClient.Builder(this) 
       .addConnectionCallbacks(this) 
       .addOnConnectionFailedListener(this) 
       .addApi(LocationServices.API) 
       .build(); 
    } 

    public void onResult(Status status) 
    { 
     // were fences added? usually yes 
    } 
} 

我的研究一直是令人沮喪 - 我看到有人自稱能從廣播接收機(請參閱第一條評論)做這樣的事情,而不是從服務中做到這一點?

我從所有的版本我一直在努力通過一個漂亮的錯位的manifest.xml:

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> 
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> 

<application 
    android:allowBackup="true" 
    android:label="@string/app_name" 
    android:theme="@style/AppTheme"> 

    <activity 
     android:name=".MainActivity" 
     android:label="@string/app_name"> 
     <intent-filter> 
      <action android:name="android.intent.action.MAIN"/> 
      <category android:name="android.intent.category.LAUNCHER"/> 
     </intent-filter> 
    </activity> 

    <service android:name=".GeofenceTransitionsIntentService" 
      android:exported="true" 
      android:enabled="true"> 
     <intent-filter > 
      <action android:name="com.aol.android.geofence.ACTION_RECEIVE_GEOFENCE"/> 
     </intent-filter> 
    </service> 

    ... 

</application> 

無論加入intent-filter也不android:exported="true"來幫助所有的服務定義。

+0

我不是一個Android開發者* – opticaliqlusion

+0

也許這個問題可以幫助你。 http://stackoverflow.com/questions/21090674/android-geofencing-no-coming-intents?rq=1 – TychoTheTaco

+0

@TychoTheTaco感謝您的迴應,但它似乎沒有任何影響 - 添加「導出」,重建和重新啓動應用程序+服務,仍然沒有。更令人憤怒的是,沒有調試輸出來說明爲什麼它可能不工作! – opticaliqlusion

回答

3

第一個,請不要使用IntentService這個。它的唯一目的是獲得一個意圖,在後臺線程中運行,然後自行停止。你正在尋找的是一個Service,因爲這會持續一段時間(直到操作系統開始運行資源不足)。

,一旦你移動你的代碼到服務,請執行下列操作:

public class GeofenceTransitionsService extends Service implements ConnectionCallbacks, OnConnectionFailedListener, ResultCallback<Status> { 
    //Whatever you need to declare 
    .... 
    GeofencingRequest mRequest; 

    //This is only called once per instance of a Service, so use this to instantiate class variables 
    @Override 
    public void onCreate() { 
     super.onCreate(); 
     buildGoogleApiClient(); 
     mGoogleApiClient.connect(); 
    } 

    //Every time you call context.startService(Intent intent) after the service is created, 
    //this function gets called with the intent you have given it. You can use this to modify or change the geofence api, 
    //passing GeofencingRequests in intents by calling intent.putExtra(...) before sending the intent, and retrieving it here. 
    //I just assume you are passing GeofencingRequest objects, since they are pacelable. 
    @Override 
    public int onStartCommand(Intent intent, int flags, final int startId) { 
     mRequest = intent.getParcelableExtra("request"); //Or whatever the key is for your request. 
     if(mGoogleApiClient.isConnected()){ 
      LocationServices.GeofencingApi.addGeofences(
       mGoogleApiClient, 
       mRequest, 
       getGeofencePendingIntent() 
      ).setResultCallback(this); 
     } 
    } 

    @Override 
    public void onConnected(Bundle connectionHint) 
    { 
     LocationServices.GeofencingApi.addGeofences(
      mGoogleApiClient, 
      mRequest, 
      getGeofencePendingIntent() 
     ).setResultCallback(this); 
    } 

    // from a branch of the example that reuses the pending intent 
    private PendingIntent getGeofencePendingIntent() 
    { 
     if (mGeofencePendingIntent != null) 
     { 
      return mGeofencePendingIntent; 
     } 

     mGeofencePendingIntent = PendingIntent.getBroadcast(this, 0, new Intent(this, GoogleGeofenceReceiver.class), PendingIntent.FLAG_UPDATE_CURRENT); 
     return mGeofencePendingIntent; 
    } 

    //The rest of your code 
    .... 
} 

請記住,當資源不足的Android會殺了你的服務,沒有太多的如果任何警告。如果您需要此服務以更高優先級運行,我強烈建議您查看starting in the foreground

,現在我們已經在業務設置,你可能已經注意到了getGeofencePendingIntent()函數現在使用的BroadcastReceiver,而不是它在運行的服務。這裏是你如何設置了:

public class GoogleGeofenceReceiver extends BroadcastReceiver { 

    @Override 
    public void onReceive(final Context context, final Intent intent) { 
     GeofencingEvent event = GeofencingEvent.fromIntent(intent); 
     ... 
     //Do whatever you did in your Service handleIntent function here. 
    } 
} 

,則需要修改清單,讓應用程序知道這個廣播接收器應使用:

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> 
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> 

<application 
    android:allowBackup="true" 
    android:label="@string/app_name" 
    android:theme="@style/AppTheme"> 

    <activity 
     android:name=".MainActivity" 
     android:label="@string/app_name"> 
     <intent-filter> 
      <action android:name="android.intent.action.MAIN"/> 
      <category android:name="android.intent.category.LAUNCHER"/> 
     </intent-filter> 
    </activity> 

    <service android:name=".GeofenceTransitionsService" 
      android:exported="true" 
      android:enabled="true"> 
     <intent-filter > 
      <action android:name="com.aol.android.geofence.ACTION_RECEIVE_GEOFENCE"/> 
     </intent-filter> 
    </service> 
    <receiver android:name=".GoogleGeofenceReceiver"/> 

    ... 

</application> 

我不是確定你爲什麼使用導出和啓用標誌,但不需要聲明,因爲啓用默認設置,如果你有意圖過濾器,導出默認爲「true」。

我建議你閱讀Activity,Service和BroadcastReceiver的生命週期,因爲理解這個項目會大大有利於你,並讓你更好地理解Android的痛苦。

+0

這很完美。絕對解決所有問題的一點是使用接收器來處理未決意圖。 1)爲什麼它需要成爲廣播接收機? 2)廣播接收器似乎在位置發生變化後稱爲「onReceive」很長時間 - 在爲接收器(=滯後)和活動(=無滯後)註冊未決意圖之間是否存在根本差異? – opticaliqlusion

+0

另外一件事 - 在幾個'onReceive'之後,廣播接收器停止工作(不再接收任何意圖)。我正在研究它;這可能只是這個滯後問題的極端情況。 – opticaliqlusion

+0

1)它不一定是BroadcastReceiver,但它是更合適的類,因爲在主線程上調用onReceive方法,onHandleIntent方法在後臺線程中運行。如果您嘗試操作UI,這一點非常重要。 2)長時間延遲的原因是Google geofence API似乎使用網絡位置來驗證設備是否進入/離開地理圍欄,並且網絡位置存在很大程度的不準確性。從最後一次測試開始,我在離開地理圍欄後需要額外50米才能進行註冊。 –

相關問題