I have a broadcast receiver that listens for power connection events. Whenever the device is connected to power, I attempt to transfer files from the APP to a Server in a machine running Ubuntu. The files are transferred over Bluetooth. Since the transfer of files is important, if for any reason the transfer has an error, or the connection is not successful in a first attempt, I retry it up to 6 times allowing 3 minutes between attempt.
In the beginning, I was using an asynctask which was simply maintained alive as long as we still have retries available and the file transfer has not been successfully done. I read, that having an asynctask in a broadcast receiver is not a good practice which makes total sense, especially since I'm forcing the task to run for long periods of time. Therefore, I decided to change to a JobIntentService such that every time a power connection event was captured by the receiver, I would issue the job that will transfer files to my computer. Within the job, right after the file transfer is finished or failed, I would set an alarm that will send a pending intent to the broadcast and call the job again.
I was running this and I have noticed that (as different from before) I've gotten too many "Connection reset by peer" errors during the transfer, which makes me wonder if the Job is being stopped before its completed or something like that?. Those errors used not to happen in my previous implementation. Then, I also noticed that for some reason the OS seems to have launched the JobIntentService again by itself (there was no event that launched it) which caused inconsistencies on my code and caused me to lose some files (I'm not supposed to allow multiple instances of this job running at the same time)
My question is, why do you think the service was restarted? is it possible for the JobIntentService to be finished and restarted by the OS during the BT transfer? The files are heavy so they take several minutes to transfer from the app to the machine. I was thinking of trying a foreground service instead of the JobIntent and having a notification for the service or going back to my previous implementation.
Any suggestions?
This is how I call the Intent Job.
FileTransferJob.isJobAlreadyRunning = true;
Intent intent = new Intent(context, FileTransferJob.class);
intent.putExtra(TRANSFER_DATA_RETRIES, retries);
FileTransferJob.enqueueWork(context,intent);
This is the JobIntentService class
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");
}
}
The logcat. The highlighted section shows what I believe is the OS creating a new instance of the JobService and running it.