我正在尝试使用 Android 中的 JobIntentService 上传多个文件。文件似乎已上传,但我无法在进度栏中跟踪进度。进度条在整个上传过程中保持在同一位置,即使在我完成上传后它也不会消失。我试图修改我在https://androidwave.com/upload-files-to-server-using-service-in-android/中找到的实现,但它让我无处可去。
这是我的 FileUploadService.java 类:-
public class FileUploadService extends JobIntentService {
private static final String TAG = "FileUploadService";
private static final int JOB_ID = 102;
NotificationHelper mNotificationHelper;
Disposable mDisposable;
public static final int NOTIFICATION_ID = 1;
public static final int NOTIFICATION_RETRY_ID = 2;
private ArrayList<String> imagePaths;
private static String token,folderId;
@Override
public void onCreate() {
super.onCreate();
mNotificationHelper = new NotificationHelper(this);
}
@Override
protected void onHandleWork(@NonNull Intent intent) {
Log.d(TAG, "onHandleWork: ");
imagePaths = intent.getStringArrayListExtra("mFilePath");
if (imagePaths == null) {
Log.e(TAG, "onHandleWork: Invalid file URI");
return;
}
RetrofitFactory<BaseNetworkResponse> mRetrofitFactory = RetrofitFactory.getInstance();
IRetrofitContract iRetrofitContract = mRetrofitFactory.getRetrofitContract(RetroUtils.APP_ENV);
Flowable<Double>fileObservable = Flowable.create(new FlowableOnSubscribe<Double>() {
@Override
public void subscribe(FlowableEmitter<Double> e) throws Exception {
iRetrofitContract.uploadImage(token,folderId,createMultipart(imagePaths,e)).blockingGet();
}
}, BackpressureStrategy.LATEST);
mDisposable = fileObservable.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Double>() {
@Override
public void accept(Double progress) throws Exception {
// call onProgress()
FileUploadService.this.onProgress(progress);
}
}, new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) throws Exception {
// call onErrors() if error occurred during file upload
FileUploadService.this.onErrors(throwable);
}
}, new Action() {
@Override
public void run() throws Exception {
// call onSuccess() while file upload successful
FileUploadService.this.onSuccess();
}
});
}
private void onErrors(Throwable throwable) {
/**
* Error occurred in file uploading
*/
Intent successIntent = new Intent("com.wave.ACTION_CLEAR_NOTIFICATION");
successIntent.putExtra("notificationId", NOTIFICATION_ID);
sendBroadcast(successIntent);
PendingIntent resultPendingIntent = PendingIntent.getActivity(this,
0 /* Request code */, new Intent(this, StartCameraAndProcessImageActivity.class),
PendingIntent.FLAG_UPDATE_CURRENT);
/**
* Add retry action button in notification
*/
Intent retryIntent = new Intent(this, RetryJobReceiver.class);
retryIntent.putExtra("notificationId", NOTIFICATION_RETRY_ID);
retryIntent.putExtra("mFilePath", imagePaths);
retryIntent.setAction(ACTION_RETRY);
/**
* Add clear action button in notification
*/
Intent clearIntent = new Intent(this, RetryJobReceiver.class);
clearIntent.putExtra("notificationId", NOTIFICATION_RETRY_ID);
clearIntent.putExtra("mFilePath", imagePaths);
clearIntent.setAction(ACTION_CLEAR);
PendingIntent retryPendingIntent = PendingIntent.getBroadcast(this, 0, retryIntent, 0);
PendingIntent clearPendingIntent = PendingIntent.getBroadcast(this, 0, clearIntent, 0);
NotificationCompat.Builder mBuilder = mNotificationHelper.getNotification(getString(R.string.error_upload_failed), getString(R.string.message_upload_failed), resultPendingIntent);
// attached Retry action in notification
mBuilder.addAction(android.R.drawable.ic_menu_revert, getString(R.string.btn_retry_not), retryPendingIntent);
// attached Cancel action in notification
mBuilder.addAction(android.R.drawable.ic_menu_revert, getString(R.string.btn_cancel_not), clearPendingIntent);
// Notify notification
mNotificationHelper.notify(NOTIFICATION_RETRY_ID, mBuilder);
}
/**
* Send Broadcast to FileProgressReceiver with progress
*
* @param progress file uploading progress
*/
private void onProgress(Double progress) {
Intent progressIntent = new Intent(this, FileProgressReceiver.class);
progressIntent.setAction("com.wave.ACTION_PROGRESS_NOTIFICATION");
progressIntent.putExtra("notificationId", NOTIFICATION_ID);
progressIntent.putExtra("progress", (int) (100 * progress));
sendBroadcast(progressIntent);
}
private void onSuccess() {
Intent successIntent = new Intent(this, FileProgressReceiver.class);
successIntent.setAction("com.wave.ACTION_UPLOADED");
successIntent.putExtra("notificationId", NOTIFICATION_ID);
successIntent.putExtra("progress", 100);
sendBroadcast(successIntent);
}
private List<MultipartBody.Part> createMultipart(ArrayList<String> imagePaths, FlowableEmitter<Double> e) {
ArrayList<MultipartBody.Part> partArrayList = new ArrayList<>();
for (int i=0;i<imagePaths.size();i++){
File file = new File(imagePaths.get(i));
partArrayList.add(MultipartBody.Part.createFormData("file[]",file.getName(),createCountingRequestBody(file,"image/*",e)));
}
return partArrayList;
}
private RequestBody createCountingRequestBody(File file, String mimeType, final FlowableEmitter<Double> emitter) {
RequestBody requestBody = createRequestBodyFromFile(file, mimeType);
return new CountingRequestBody(requestBody, new CountingRequestBody.Listener() {
@Override
public void onRequestProgress(long bytesWritten, long contentLength) {
double progress = (1.0 * bytesWritten) / contentLength;
emitter.onNext(progress);
}
});
}
private RequestBody createRequestBodyFromFile(File file, String mimeType) {
return RequestBody.create(MediaType.parse(mimeType), file);
}
public static void enqueueWork(Context context, Intent intent, String t, String id) {
enqueueWork(context, FileUploadService.class, JOB_ID, intent);
token = t;
folderId = id;
}
public static void enqueueWork(Context context, Intent intent) {
enqueueWork(context, FileUploadService.class, JOB_ID, intent);
}
}
FileProgressReceiver 类:-
public class FileProgressReceiver extends BroadcastReceiver {
private static final String TAG = "FileProgressReceiver";
public static final String ACTION_CLEAR_NOTIFICATION = "com.wave.ACTION_CLEAR_NOTIFICATION";
public static final String ACTION_PROGRESS_NOTIFICATION = "com.wave.ACTION_PROGRESS_NOTIFICATION";
public static final String ACTION_UPLOADED = "com.wave.ACTION_UPLOADED";
NotificationHelper mNotificationHelper;
public static final int NOTIFICATION_ID = 1;
NotificationCompat.Builder notification;
@Override
public void onReceive(Context mContext, Intent intent) {
mNotificationHelper = new NotificationHelper(mContext);
// Get notification id
int notificationId = intent.getIntExtra("notificationId", 1);
// Receive progress
int progress = intent.getIntExtra("progress", 0);
switch (Objects.requireNonNull(intent.getAction())) {
case ACTION_PROGRESS_NOTIFICATION:
notification = mNotificationHelper.getNotification(mContext.getString(R.string.uploading), mContext.getString(R.string.in_progress), progress);
mNotificationHelper.notify(NOTIFICATION_ID, notification);
break;
case ACTION_CLEAR_NOTIFICATION:
mNotificationHelper.cancelNotification(notificationId);
break;
case ACTION_UPLOADED:
Intent resultIntent = new Intent(mContext, StartCameraAndProcessImageActivity.class);
PendingIntent resultPendingIntent = PendingIntent.getActivity(mContext,
0 /* Request code */, resultIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
notification = mNotificationHelper.getNotification(mContext.getString(R.string.message_upload_success), mContext.getString(R.string.file_upload_successful), resultPendingIntent);
mNotificationHelper.notify(NOTIFICATION_ID, notification);
break;
default:
break;
}
}
}
RetryJobReceiver 类:-
public class RetryJobReceiver extends BroadcastReceiver {
public static final String ACTION_RETRY = "com.wave.ACTION_RETRY";
public static final String ACTION_CLEAR = "com.wave.ACTION_CLEAR";
NotificationHelper mNotificationHelper;
@Override
public void onReceive(Context context, Intent intent) {
/**
* Handle notification user actions
*/
mNotificationHelper = new NotificationHelper(context);
int notificationId = intent.getIntExtra("notificationId", 0);
ArrayList<String> filePath = intent.getStringArrayListExtra("mFilePath");
switch (Objects.requireNonNull(intent.getAction())) {
case ACTION_RETRY:
mNotificationHelper.cancelNotification(notificationId);
Intent mIntent = new Intent(context, FileUploadService.class);
mIntent.putExtra("mFilePath", filePath);
FileUploadService.enqueueWork(context, mIntent);
break;
case ACTION_CLEAR:
mNotificationHelper.cancelNotification(notificationId);
break;
default:
break;
}
}
}
NotificationHelper 类:-
public class NotificationHelper extends ContextWrapper {
private NotificationManager manager;
public static final String WAVE_CHANNEL = "default";
public NotificationHelper(Context mContext) {
super(mContext);
NotificationChannel mChannel = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
mChannel = new NotificationChannel(WAVE_CHANNEL,
getString(R.string.noti_channel_default), NotificationManager.IMPORTANCE_DEFAULT);
mChannel.setLightColor(Color.GREEN);
mChannel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
getManager().createNotificationChannel(mChannel);
}
}
public NotificationCompat.Builder getNotification(String title, String body, int progress) {
NotificationCompat.Builder mBuilder;
mBuilder = new NotificationCompat.Builder(getApplicationContext(), WAVE_CHANNEL);
mBuilder.setSmallIcon(getSmallIcon());
mBuilder.setColor(ContextCompat.getColor(getApplicationContext(), R.color.colorAccent));
mBuilder.setContentTitle(title)
.setContentText(body)
.setOngoing(true)
//.setContentIntent(resultPendingIntent)
.setDefaults(NotificationCompat.DEFAULT_ALL)
.setPriority(NotificationCompat.PRIORITY_HIGH);
mBuilder.setVibrate(new long[]{0L});
mBuilder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
mBuilder.setProgress(100, progress, false);
if (progress == 100) {
mBuilder.setProgress(0, 0, false);
mBuilder.setContentText(body);
}
return mBuilder;
}
public NotificationCompat.Builder getNotification(String title, String body, PendingIntent resultPendingIntent) {
NotificationCompat.Builder mBuilder;
mBuilder = new NotificationCompat.Builder(getApplicationContext(), WAVE_CHANNEL);
mBuilder.setSmallIcon(getSmallIcon());
mBuilder.setColor(ContextCompat.getColor(getApplicationContext(), R.color.colorAccent));
mBuilder.setContentTitle(title)
.setContentText(body)
.setContentIntent(resultPendingIntent)
.setDefaults(NotificationCompat.DEFAULT_ALL)
.setPriority(NotificationCompat.PRIORITY_HIGH);
mBuilder.setVibrate(new long[]{0L});
mBuilder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
return mBuilder;
}
/**
* Send a notification.
*
* @param id The ID of the notification
* @param notification The notification object
*/
public void notify(int id, NotificationCompat.Builder notification) {
getManager().notify(id, notification.build());
}
/**
* Get the small icon for this app
*
* @return The small icon resource id
*/
private int getSmallIcon() {
return android.R.drawable.stat_notify_sync;
}
/**
* Get the notification manager.
* <p>
* Utility method as this helper works with it a lot.
*
* @return The system service NotificationManager
*/
private NotificationManager getManager() {
if (manager == null) {
manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
}
return manager;
}
public void cancelNotification(int notificationId) {
getManager().cancel(notificationId);
}
}
我的 API:-
@Multipart
@POST("/uploadImage")
Single<BaseNetworkResponse> uploadImage(@Header("Authorization") String token, @Header("fileId") String fileId, @Part List<MultipartBody.Part> file);