Android JobIntentService, кажется, перезапущен - PullRequest
0 голосов
/ 28 июня 2018

У меня есть широковещательный приемник, который прослушивает события подключения питания. Всякий раз, когда устройство подключено к источнику питания, я пытаюсь передать файлы из приложения на сервер на компьютере под управлением Ubuntu. Файлы передаются по Bluetooth. Поскольку передача файлов важна, если по какой-либо причине при передаче произошла ошибка или соединение не было успешным с первой попытки, я повторяю его до 6 раз, позволяя 3 минуты между попытками.

Вначале я использовал асинхронную задачу, которая просто поддерживалась активной до тех пор, пока у нас еще есть доступные повторные попытки и передача файла не была успешно выполнена. Я читал, что наличие асинхронной задачи в приемнике вещания - не очень хорошая практика, которая имеет смысл, тем более, что я заставляю задачу выполняться в течение длительных периодов времени. Поэтому я решил перейти на JobIntentService, чтобы каждый раз, когда получатель регистрировал событие подключения к источнику питания, я выполнял задание, которое передавало файлы на мой компьютер. В рамках задания, сразу после того, как передача файла закончится или не удастся, я установлю будильник, который отправит ожидающее намерение в эфир и снова вызовет задание.

Я выполнял это, и я заметил, что (в отличие от ранее) я получил слишком много ошибок "Сброс соединения по одноранговым узлам" во время передачи, что заставляет меня задуматься, останавливается ли Задание до его завершения или что-то еще как это?. Таких ошибок не было в моей предыдущей реализации. Затем я также заметил, что по какой-то причине ОС, похоже, снова запустила JobIntentService (событие, которое его не запустило), что вызвало несоответствия в моем коде и привело к потере некоторых файлов (я не должен позволять несколько экземпляров этого задания выполняются одновременно)

Мой вопрос: как вы думаете, почему служба была перезапущена? Возможно ли, чтобы JobIntentService был завершен и перезапущен ОС во время передачи по BT? Файлы тяжелые, поэтому их перенос из приложения на компьютер занимает несколько минут. Я думал о том, чтобы попробовать службу переднего плана вместо JobIntent и получить уведомление для службы или вернуться к моей предыдущей реализации.

Есть предложения?

Вот как я называю Intent Job.

FileTransferJob.isJobAlreadyRunning = true;
Intent intent = new Intent(context, FileTransferJob.class);
intent.putExtra(TRANSFER_DATA_RETRIES, retries);
FileTransferJob.enqueueWork(context,intent);

Это класс JobIntentService

public class FileTransferJob extends JobIntentService {
/**
 * Unique job ID for this service.
 */
public static boolean isJobAlreadyRunning = false; //This flag will remain true as soon as this JOB is called and as long as retries are still available
public static final int JOB_ID = 1000;
public static int MAX_NUM_OF_RETRIES = 6;//How many times are we going to retry to send the data
private int MINUTES_TO_WAIT = 3; //The minutes we wait between each attempt
public String TAG = "FileTransferJob";

/**
 * Convenience method for enqueuing work in to this service.
 */
public static void enqueueWork(Context context, Intent work) {
    enqueueWork(context, FileTransferJob.class, JOB_ID, work);
}

@Override
protected void onHandleWork(Intent intent) {

    int retriesRemaining = intent.getIntExtra(TRANSFER_DATA_RETRIES,1); //Get the number of retries we have. Default to 1 (this one)
    Log.d(TAG, "onHandleWork: About to attempt transfer with remaining retries " + String.valueOf(retriesRemaining));


    try {
        BluetoothFileTransfer btio = new BluetoothFileTransfer();
        Log.d(TAG, "onHandleWork: About to send data over Bluetooth");
        btio.sendData(FileTransferJob.this.getApplicationContext());
        FileTransferJob.isJobAlreadyRunning = false; //Success, then this is no longer running
        Log.d(TAG, "onHandleWork: The data has been sent over Bluetooth");
    }catch (Exception e){
        Log.d(TAG, "onHandleWork: There was a problem with the BT transfer: " + e.getMessage());

        retriesRemaining--; //We reduce the number of retries we have

        //If no more retries available, simply do nothing
        if (retriesRemaining > 0) {
            Log.d(TAG, "onHandleWork: Setting up alarm. Retries ramaining: " + String.valueOf(retriesRemaining));
            AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
            Intent alarmIntent = new Intent(this.getApplicationContext(), DataCollectReceiver.class);
            alarmIntent.setAction(TRANSFER_DATA);
            alarmIntent.putExtra(TRANSFER_DATA_RETRIES, retriesRemaining);

            PendingIntent alarmPendingIntent = PendingIntent.getBroadcast( this.getApplicationContext(), PENDING_INTENT_CODE_FILE_TRANSFER_JOB, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
            int totalTime = MINUTES_TO_WAIT*60*1000;
            if(alarmManager != null){
                alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,
                        System.currentTimeMillis() + totalTime,
                        alarmPendingIntent);
                Log.d(TAG, "onHandleWork: Alarm is set, waiting " + String.valueOf(totalTime) + " minutes for next attempt...");
            }else{
                Log.d(TAG, "onHandleWork: Alarm could not be set. Alarm manager is NULL");
            }

        }else{
            Log.d(TAG, "onHandleWork: There are no more retries");
            FileTransferJob.isJobAlreadyRunning = false;
        }
    }
}

@Override
public void onDestroy() {
    super.onDestroy();
    Log.d(TAG, "onDestroy: The file transfer JOB has finished");
}

}

Логкат. Выделенный раздел показывает, что, по моему мнению, ОС создает новый экземпляр JobService и запускает его.

enter image description here

1 Ответ

0 голосов
/ 31 января 2019

Позвольте мне попытаться ответить на него, поскольку я заметил это поведение. JobIntentService / JobService / Worker будет работать только в течение 10 минут, после чего они будут остановлены, и вы можете получить обратный вызов onStopJob / onStopCurrentWork в случае JobService / JobIntentService и OnStopped в случае Worker.

Хотя документ Android объясняет это поведение только для Worker, но JobService / JobIntentServie ведут себя одинаково

Работнику дается максимум десять минут, чтобы завершить его выполнение и вернуть ListenableWorker.Result. По истечении этого времени Работнику будет дан сигнал об остановке.

Следовательно, я могу предположить, что ваша задача не будет выполнена в течение 10 минут, и Android уничтожает JobIntentService. Теперь дело в том, что все эти Jobservice / JobIntentService / Worker запускаются снова (если они преждевременно остановлены) после экспоненциального времени отката, то есть 30 сек, 1 мин, 2 мин, 4 мин ...

Хотя странная часть заключается в том, что старый поток, который умер после 10 минут работы, запустился, как объяснено, но, когда обратный вызов снова приходит на HandleWork, он снова запускает другой поток, который дублирует работу, проделанную этим потоком, и поэтому я думаю, что вы см. несоответствия.

Предполагается, что вы прервете свою работу таким образом, чтобы ее можно было закончить с помощью окна 10 минут. Или мы можем подождать, пока команда Google исправит это.

...