2016-12-23 15 views
1

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

Определение сервиса

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

Все в службе (апи клиент Google построен и подключен) осуществляется в onCreate, как с намерением обработчиков и регистрации геозоны вещи onConnected регистры Геозоны и т.д. В принципе, я ve попытался внедрить тяжелый заимствованный пример кода геофикации (из документов) в той же службе, которая предназначена для обработки этих намерений.

Все основные виды деятельности - это запуск службы и привлечение тех, которые связаны с уведомлениями о геозонности, полученными в сервисе.

Если вам нужна дополнительная информация, просто дайте мне знать.

редактировать

Ok, так что кажется, что нам нужно больше информации - план службы:

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 dev * – 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. 
    } 
} 

Четвертой, вам нужно изменить ваш манифест, чтобы позволить приложению знать, что это BroadcastReceiver следует использовать:

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

Я не убедитесь, что вы используете флаги export и enabled, но их не нужно объявлять, потому что включен по умолчанию, а экспортированный по умолчанию имеет значение «true», если у вас есть фильтр намерений.

Я бы посоветовал вам ознакомиться с жизненными циклами Activity, Service и BroadcastReceiver, так как понимание поможет вам в этом проекте и даст вам лучшее понимание боли Android в целом.

+0

Это прекрасно. Бит, который полностью фиксирует все, использует приемник для ожидающего намерения. 1) Зачем нужен вещательный приемник? 2) Приемник вещания кажется, что 'onReceive' вызвал довольно долго после изменения местоположения - существует ли принципиальное различие между регистрацией ожидающего намерения для получателя (= lag) и активности (= без задержки)? – opticaliqlusion

+0

еще одна вещь - после нескольких «onReceive» приемник вещания перестает работать (больше не получает намерений). Я изучаю это; это может быть просто крайний случай этой проблемы с задержкой. – opticaliqlusion

+0

1) Это не должно быть BroadcastReceiver, но это более подходящий класс для использования, поскольку метод onReceive вызывается в основном потоке, где метод onHandleIntent запускается в фоновом потоке. Это очень важно, если вы пытаетесь манипулировать пользовательским интерфейсом. 2) Причина долгой задержки заключается в том, что Google geofence API, похоже, использует сетевые местоположения для проверки того, ввело ли устройство/покинуло геозонность, и существует высокая степень неточности в отношении местоположения в сети. В последний раз, когда я тестировал, он потребовал дополнительные 50 м после того, как я вышел из геофлоны для его регистрации. –