Я создаю приложение для загрузки фотографий в фоновом режиме в корзину s3 с помощью TransferUtility. Я реализовал службу переднего плана, которая использует метод загрузки s3 TranferUtility, и служба должна быть остановлена только после завершения всех загрузок.
При тестировании на реальных устройствах выгрузка фотографий работает в режиме ожидания (экономия батареи включена), при удалении из задач и отключении экрана. Тем не менее, загрузка фотографий иногда не срабатывает, так как сервис рано убивается. (Все тестирующие и производственные устройства - Samsungs)
Журналы показывают, что stopSelf()
и stopForeground(true)
не были вызваны, а служба переднего плана показывает, что вызывался только onDestroy. Ни один из TransferObservers не достиг состояния отказа. Состояния, в которых они находились до вызова onDestroy, были «Ожидание», «Выполняется» или «Завершено». Я могу подтвердить, что все попытки инициирования загрузки были успешными, основываясь на журналах.
Я попытался поместить TransferStility Service TransferUtility и мой UploadService в один и тот же процесс, получить блокировку wakelocks и убедиться, что уведомление переднего плана не отменяется.
Любая помощь будет полезна для определения того, что убивает мою службу переднего плана.
UploadService:
public class UploadService extends Service {
private final static String TAG = UploadService.class.getSimpleName();
private TransferUtility transferUtility;
public final static String INTENT_TRANSFER_OPERATION = "transferOperation";
public final static String INTENT_PHOTOS_UPLOAD = "UploadPhotos";
public final static String TRANSFER_OPERATION_UPLOAD = "upload";
public final static String TRANSFER_OPERATION_DOWNLOAD = "download";
public final static int MAX_ERROR_COUNT = 100;
public final String CHANNEL_ID = "upload_foreground_channel";
public ArrayList<TransferObserver> uploadTransferObservers;
private ArrayList<PhotoUploadModel> photosToUpload;
public static boolean uploadServiceRunning;
private static boolean uploadsCompleted;
public static int uploadCounter = 0;
public static long bytesLeftToTransfer = 0;
private static float uploadProgress = 0;
private static float uploadsInTotal = 0;
private static int onErrorCalled = 0;
private TransferObserver transferObserver;
private NotificationManagerCompat notificationManager;
private NotificationCompat.Builder notification;
private S3Util util;
private PowerManager.WakeLock wakeLock;
@Override
public void onCreate() {
super.onCreate();
Bugfender.d(TAG, "Upload Service Started : ON CREATE");
//reset values
uploadsCompleted = false;
uploadCounter = 0;
bytesLeftToTransfer = 0;
uploadProgress = 0;
uploadsInTotal = 0;
onErrorCalled = 0;
uploadTransferObservers = new ArrayList<>();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Bugfender.d(TAG, "Upload Service Started : ON START COMMAND");
// Foreground notification
if (Build.VERSION.SDK_INT >= 26) {
NotificationChannel channel = new NotificationChannel(CHANNEL_ID,
"Upload Foreground Service",
NotificationManager.IMPORTANCE_LOW);
((NotificationManager) Objects.requireNonNull(getSystemService(Context.NOTIFICATION_SERVICE))).createNotificationChannel(channel);
notificationManager = NotificationManagerCompat.from(getBaseContext());
notification = new NotificationCompat.Builder(getBaseContext(), CHANNEL_ID)
.setContentTitle("Uploading project images")
.setContentText("starting..")
.setSmallIcon(R.mipmap.symbiotic_image_logo);
// Issue the initial notification with zero progress
int PROGRESS_MAX = 100;
int PROGRESS_CURRENT = 0;
notification.setProgress(PROGRESS_MAX, PROGRESS_CURRENT, true);
notificationManager.notify(1, notification.build());
startForeground(1, notification.build());
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
if (powerManager != null) {
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"MyApp::MyWakelockTag");
wakeLock.acquire(1800000);
Bugfender.d(TAG, "Wake lock acquired");
}
}
//Initiating Uploads
util = new S3Util();
transferUtility = util.getTransferUtility(getBaseContext());
final String transferOperation = intent.getStringExtra(INTENT_TRANSFER_OPERATION);
final ArrayList<PhotoUploadModel> photosToUpload = intent.getParcelableArrayListExtra("UploadPhotos");
switch (transferOperation) {
case TRANSFER_OPERATION_UPLOAD:
// Initiate Upload for every photo
for (PhotoUploadModel photoUploadModel : photosToUpload) {
Bugfender.d(TAG, "Uploading " + photoUploadModel.getUploadKey());
File fileToUpload = new File(photoUploadModel.getFileToUploadPath());
try {
transferObserver = transferUtility.upload("symbioticlabs", photoUploadModel.getUploadKey(), fileToUpload);
transferObserver.setTransferListener(new UploadListener());
uploadTransferObservers.add(transferObserver);
Bugfender.d(TAG, "Upload Initiated Successful for : " + photoUploadModel.getFileToUploadPath());
uploadCounter++;
uploadServiceRunning = true;
uploadsInTotal++;
} catch (IllegalArgumentException e) {
Bugfender.e(TAG, e.toString());
Crashlytics.logException(e);
e.printStackTrace();
} catch (AmazonClientException e) {
// Retry upload if failed to initiate due to Timeout
transferObserver = transferUtility.upload("symbioticlabs", photoUploadModel.getUploadKey(), fileToUpload);
transferObserver.setTransferListener(new UploadListener());
uploadTransferObservers.add(transferObserver);
uploadCounter++;
uploadServiceRunning = true;
uploadsInTotal++;
Bugfender.e(TAG, e.toString());
}
}
Bugfender.d(TAG, "After upload initiated, upload observer has size of : " + uploadTransferObservers.size());
break;
}
return START_STICKY;
}
@Override
public void onDestroy() {
Bugfender.d(TAG, "On Destroyed Called");
transferUtility.cancelAllWithType(TransferType.UPLOAD);
uploadServiceRunning = false;
super.onDestroy();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
private class UploadListener implements TransferListener {
@Override
public void onError(int id, Exception e) {
onErrorCalled++;
}
@Override
public void onProgressChanged(int id, long bytesCurrent, long bytesTotal) {
Log.d(TAG, String.format("onProgressChanged: %d, total: %d, current: %d",
id, bytesTotal, bytesCurrent));
Bugfender.d(TAG, String.format("onProgressChanged: %d, total: %d, current: %d",
id, bytesTotal, bytesCurrent));
}
@Override
public void onStateChanged(int id, TransferState state) {
Bugfender.d(TAG, "onStateChanged: for id : " + id + ", STATE : " + state);
if (state == TransferState.COMPLETED) {
// Update Progress Notification
uploadProgress++;
float result = (uploadProgress / uploadsInTotal) * 100;
Log.d(TAG, "setProgressBarState: result " + result);
Bugfender.d(TAG, "setProgressBarState: result " + result);
int progress = Math.round(result);
notification.setProgress(100, progress, false);
notification.setContentText(String.valueOf((int) uploadProgress) + "/" + String.valueOf((int) uploadsInTotal) + " Uploaded");
notificationManager.notify(1, notification.build());
uploadCounter--;
Bugfender.d(TAG, "onStateChanged: upload progress is " + uploadProgress);
Bugfender.d(TAG, "onStateChanged: upload counter " + uploadCounter);
// Check if uploads are completed
isAllUploadCompleted();
} else if (state == TransferState.FAILED && onErrorCalled <= MAX_ERROR_COUNT) {
Bugfender.d(TAG, "onStateChanged: uploading failed " + id);
// Remove failed transferobserver with a new one when retrying
TransferObserver observerToRemove = null;
for (TransferObserver observer : uploadTransferObservers) {
if (observer.getId() == id) {
Bugfender.d(TAG, "onStateChanged: failed - observer with id : " + id + " to be removed found");
observerToRemove = observer;
}
}
if (observerToRemove != null) {
observerToRemove.cleanTransferListener();
uploadTransferObservers.remove(observerToRemove);
Bugfender.d(TAG, "onStateChanged: failed - observer with id : " + id + " removed successfully");
}
Bugfender.d(TAG, "onStateChanged: attempting reupload of id " + id);
TransferObserver newTransferObserver = transferUtility.resume(id);
newTransferObserver.setTransferListener(new UploadListener());
uploadTransferObservers.add(newTransferObserver);
Bugfender.d(TAG, "onStateChanged: new transfer observer of id " + newTransferObserver.getId() + " has been added");
}
}
}
private void isAllUploadCompleted() {
uploadsCompleted = true;
// Check if all upload observer states are Completed
for (TransferObserver observer : uploadTransferObservers) {
observer.refresh();
Bugfender.d(TAG, "onStateChanged: observer list size " + uploadTransferObservers.size());
if (observer.getState() != TransferState.COMPLETED) {
uploadsCompleted = false;
}
}
Bugfender.d(TAG, "onStateChanged: after checking all observer, uploadsCompleted : " + uploadsCompleted);
if (uploadsCompleted) {
Bugfender.d(TAG, "isAllUploadCompleted: Stop service called");
stopUploadService();
}
}
private void stopUploadService() {
if (wakeLock != null) {
Bugfender.d(TAG, "Wake lock released");
wakeLock.release();
}
uploadServiceRunning = false;
stopForeground(true);
stopSelf();
}
}
Начало загрузки:
private void beingUploadInBackground() {
//start upload service
Context context = mActivity.getBaseContext();
Intent intent = new Intent(context, UploadService.class);
intent.putParcelableArrayListExtra(UploadService.INTENT_PHOTOS_UPLOAD, photosToUpload);
intent.putExtra(UploadService.INTENT_TRANSFER_OPERATION, UploadService.TRANSFER_OPERATION_UPLOAD);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
ContextCompat.startForegroundService(context, intent);
} else {
context.startService(intent);
}
}