我正在构建一个应用程序,以使用TransferUtility在后台将照片上传到s3存储桶。我已经实现了使用s3 TranferUtility的上载方法的前台服务,并且仅应在所有上载完成后才停止该服务。
在真实设备上进行测试时,将照片从任务中删除并关闭屏幕后,照片上传将以打ze模式工作(电池节电功能已打开)。但是,由于该服务被提早终止,因此上传的照片有时会失败。 (所有测试和生产设备均为三星)
日志显示尚未调用stopSelf()
和stopForeground(true)
,但是前台服务显示仅调用了onDestroy。没有任何TransferObserver达到失败状态。在调用onDestroy之前,它们所处的状态是“正在等待”,“进行中”或“已完成”。我可以根据日志确认所有上传启动尝试均已成功。
我尝试将TransferUtility的TransferService和我的UploadService放在同一进程中,获取唤醒锁,确保前台通知不会被取消。
我们将不胜感激,以帮助您确定造成我的前台服务中断的原因。
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);
}
}