I am using workmanager
to compress and upload videos in my app in background. The issue is, I wanted to process to run even when app is minimized. It was easily done using this. But in one phone, the app is crashing/closing/restarting when I minimize my app and open other 3-4 apps. I think the ram is not able to handle that.
So, I thought as my process is in workmanager
, it should continue.
Understand this: I have a list of tasks. And each task have list on my UI. Now, each element of that list is used for uploading videos. I have to show the upload progress for each of them. Like if I am uploading 4-5 videos, I should show progress for each of them correctly.
So, what I did? I created a streamController like this:
final orderedFuturesController = StreamController<Future>();
Future preserveOrder(Future future) {
orderedFuturesController.add(future);
return future;
}
So, whenever I tap on a button on the list, it adds a function call to preserveOrder
function. The I created a listener, inside main
function, before runapp
:
final streamSubscription = orderedFuturesController.stream
.asyncMap((future) async => await future)
.listen((_) {}, cancelOnError: false);
Okay. Now, I am calling preserveOrder like this:
await preserveOrder(uploadVideos(uploadVideoData: tempData));
Inside uploadVideos
, I did this:
Future<void> uploadVideos({UploadVideoData? uploadVideoData}) async {
print("Upload videos called");
await Workmanager().registerOneOffTask(
"${uploadVideoData?.pId}_${uploadVideoData?.groupId}", // Unique task key
"uploadVideos", // Task name
inputData: uploadVideoData?.toJson(),
);
}
And I defined my callbackdispatcher
like this:
@pragma('vm:entry-point') // Mandatory if the App is obfuscated or using Flutter 3.1+
void callbackDispatcher() {
Workmanager().executeTask((task, inputData) async {
// Handle background task here
SharedPrefs().init();
print("Background task is running");
if(inputData!=null) {
try {
UploadVideoData? uploadVideoData = UploadVideoData.fromJson(inputData);
print("Inside workmanager for: ${uploadVideoData.name}");
String? compressedPath = await compressVideo(uploadVideoData);
uploadVideoData.mediaPath = compressedPath;
await uploadFiles(uploadVideoData);
} catch (e) {
print("Error in bg task: $e");
}
}
return Future.value(true);
});
}
In my uploadFiles
function, I am using https://pub.dev/packages/files_uploader package to upload my files in background.
Now, to update my UI, I created a provider, in which I made 2 maps to keep track of: which taskId (of file_uploader
task) corresponds to which exact upload. And for each elements in my list, what is the percent of corresponding upload file. Now, as soon as i was calling
await preserveOrder(uploadVideos(uploadVideoData: tempData));
I was adding the corresponding data to my provider maps, and saving them in Shared Preferences. Why? So, if my app crashes/restarts, I can initialize all the data again in my provider, and reflect that to UI.
Oh, and I was updating my ui like this:
final subscription = FlutterUploader().progress.listen((progress) async {
print("Progress is: ${progress.progress}");
List<String>? data =
videoUploadProvider.getCorrespondingUniqueId(progress.taskId);
print("Updating: ${data?[0]} and ${progress.progress}");
videoUploadProvider.updateUploadPercent(
data?[0] ?? '', progress.progress?.toDouble() ?? 0.0);
if(progress.progress==100) {
List<String>? completedData =
videoUploadProvider.getCorrespondingUniqueId(progress.taskId);
if (completedData != null) {
print("completed data is: $completedData");
await whenCompletedUpload(completedData);
}
videoUploadProvider.removeElementFromMap(progress.taskId);
}
});
This is also called before runApp
inside main
function.
The problems are:
- When my app crashes, the task inside my
workmanager
suddenly stops. - When the app opens again after crashing, and suppose 3 uploads were remaining, the upload starts again. So, videos are being uploaded twice. And sometimes, my provider is not being updated, so sometimes the progress is displayed, sometimes not.
And when an upload is completed, I remove that from map and shared prefs
, but sometimes, it is not being deleted.
I just want to uploads videos in a queue, one by one each which should not stop even if the app is crashed/closed and progress should be displayed every time, even after restarting the app. I first tried it using queues and recursive functions, but it was not working. So, I tried this.
Can someone help me with this pleaseeee??? I'm stuck in this for more than 2 weeks and I can't find the solution for this.