Пользовательский класс обслуживания с ThreadPoolExecutor убит, когда приложение выключено

Мне нужно выполнять несколько задач параллельно в пользовательской службе, чтобы заставить их работать:
- Служба определения местоположения и API распознавания действий.
- API Geofence и вызовы REST API.

Я новичок в потоках в Java и Android, и я обнаружил, что лучший способ реализовать это — использовать ThreadPoolExecutor вместо того, чтобы создавать свои собственные классы потоков и иметь дело со всеми вещами Handler Looper.

Когда я запускаю свое приложение, служба запускается, обновления местоположения и обновления активности работают нормально внутри потока. но когда я закрываю приложение, служба перезапускается (когда return START_STICKY;), и поток больше не работает. Когда (return START_NOT_STICKY;), служба исчезает. (В моем случае я не могу использовать startforeground())

Я использую эту библиотеку(smart-location-lib) для получения обновлений о местоположении и действиях.

– Вот код моей специальной службы:

public class LocationService extends Service {

    private ThreadPoolExecutor mDecodeThreadPool;
    private BlockingQueue<Runnable> mDecodeWorkQueue;

    private int NUMBER_OF_CORES = Runtime.getRuntime().availableProcessors();
    private final int KEEP_ALIVE_TIME = 1;
    private final TimeUnit KEEP_ALIVE_TIME_UNIT = TimeUnit.SECONDS;

    public LocationService () {
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Toast.makeText(this, "Location services created", Toast.LENGTH_SHORT).show();
        mDecodeWorkQueue = new LinkedBlockingQueue<Runnable>();
        mDecodeThreadPool = new ThreadPoolExecutor(
                NUMBER_OF_CORES * 2, // Initial pool size
                NUMBER_OF_CORES * 2, // Max pool size
                KEEP_ALIVE_TIME,
                KEEP_ALIVE_TIME_UNIT,
                mDecodeWorkQueue);    
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Toast.makeText(this, "Location services started", Toast.LENGTH_SHORT).show();
        mDecodeThreadPool.execute(new LocationRunnable(getApplicationContext()));
        return START_STICKY;
    }

    @Override
    public void onLowMemory() {
        super.onLowMemory();
        Log.v("LOW MEMORY", "|||||||||||||||||||||||||||||||||||||");

    }

    @Override
    public IBinder onBind(Intent intent) {
        throw new UnsupportedOperationException("Not yet implemented");
    }


    @Override
    public void onDestroy() {
        Toast.makeText(this, "Location services stopped", Toast.LENGTH_LONG).show();
        mDecodeThreadPool.shutdown();
        mDecodeThreadPool.shutdownNow();
        super.onDestroy();
    }
}

- Вот мой код класса Runnable:

public class LocationRunnable implements Runnable, OnLocationUpdatedListener, OnActivityUpdatedListener {

     SmartLocation smartLocation;
     public LocationRunnable(Context ctx) {
          smartLocation = new SmartLocation.Builder(ctx).logging(true).build();

     }

    @Override
    public void run() {
        Log.v("THREAD", "THREAD STARTED");
        startLocation();
     }


    private void startLocation() {
        smartLocation.location().start(this);
        smartLocation.activity().start(this);
    }

    @Override
    public void onActivityUpdated(DetectedActivity detectedActivity) {
        if (detectedActivity != null) {
            Log.v("ACTIVITY", "ACTIVITY UPDATED");
        } else {
            Log.v("ACTIVITY", "NULL");
        }

    }
    int i = 0;
    @Override
    public void onLocationUpdated(Location location) {
        Log.v("LOCATION", "LOCATION UPDATED" + i++);
    }

    private String getNameFromType(DetectedActivity activityType) {
        switch (activityType.getType()) {
            case DetectedActivity.IN_VEHICLE:
                return "in_vehicle";
            case DetectedActivity.ON_BICYCLE:
                return "on_bicycle";
            case DetectedActivity.ON_FOOT:
                return "on_foot";
            case DetectedActivity.STILL:
                return "still";
            case DetectedActivity.TILTING:
                return "tilting";
            default:
                return "unknown";
        }
    }

}

Я не совсем уверен, что это правильный или лучший способ получить то, что мне нужно.
Любая помощь очень ценится!


person Rami Jemli    schedule 02.06.2015    source источник
comment
Вы не закрываете приложение в Android. Объясните, точно что вы имеете в виду под закрытием приложения.   -  person CommonsWare    schedule 03.06.2015
comment
Это просто кнопка многозадачности (та, которая показывает открытые приложения). Итак, я смахиваю его, и он должен продолжать работать в фоновом режиме.   -  person Rami Jemli    schedule 03.06.2015
comment
Это завершает фоновый процесс, как если бы процесс был завершен из-за нехватки памяти.   -  person CommonsWare    schedule 03.06.2015
comment
Да, но при перезапуске службы (возвратите START_STICKY;) обновления местоположения больше не работают.   -  person Rami Jemli    schedule 03.06.2015
comment
Я не знаю, что именно означает «обновления местоположения больше не работают». Вам нужно будет снова настроить обновления местоположения, которые находятся в коде, которого нет в вашем вопросе. Ваш процесс может быть остановлен в любой момент, даже со службой, так что это сценарий, который ваше приложение должно уметь обрабатывать.   -  person CommonsWare    schedule 03.06.2015


Ответы (1)


Я понимаю, что вопрос старый, но он может помочь другим.

Я думаю, это связано с тем, что код из Runnable.run() немедленно завершает работу, тем самым завершая родительский поток, так что изменения в местоположении больше не имеют объекта для публикации.

smartLocation.location().start(это); // это ‹-- Runnable

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

person TudorT    schedule 22.12.2016