1

我有一个监听电源连接事件的广播接收器。每当设备连接到电源时,我都会尝试将文件从 APP 传输到运行 Ubuntu 的机器上的服务器。文件通过蓝牙传输。由于文件传输很重要,如果由于任何原因传输出错,或者第一次尝试连接不成功,我最多重试 6 次,每次尝试之间留出 3 分钟。

一开始,我使用的是一个异步任务,只要我们仍然可以重试并且文件传输没有成功完成,它就会保持活动状态。我读到,在广播接收器中有一个 asynctask 并不是一个完全有意义的好习惯,特别是因为我强迫任务运行很长时间。因此,我决定更改为 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 的新实例并运行它。

在此处输入图像描述

4

1 回答 1

1

Let me try to answer it as i have noticed this behavior. The JobIntentService/JobService/Worker will run only for 10 mins after that they will be stopped and you can get a call back on onStopJob/onStopCurrentWork in case of JobService/JobIntentService and OnStopped in case of Worker.

Though the android document has explained this behavior for Worker only but JobService/JobIntentServie both behaves the same way

A Worker is given a maximum of ten minutes to finish its execution and return a ListenableWorker.Result. After this time has expired, the Worker will be signalled to stop.

Hence i can assume that your task is not finished within 10 mins and Android is destroying the JobIntentService. Now the thing is that All of these Jobservice/JobIntentService/Worker are started again (If stopped prematurely) after the exponential backoff time i.e. 30secs , 1 min, 2 mins,4 mins...

Although the weird part is that the old thread which died after running 10 mins started as explained but as the call back comes again on HandleWork it starts another thread again which duplicates the work done by the thread and that is why i think you see inconsistencies.

The suggestion is that you break your work in such a way that can be finished withing the 10 mins window. Or We can wait for Google team to fix this.

于 2019-01-31T13:58:03.563 回答