Home > OS >  Firebase task.snapshotEvents.listen StateProvider not getting updated progress for upload
Firebase task.snapshotEvents.listen StateProvider not getting updated progress for upload

Time:11-27

All screens in my app have access to the Uploading State Provider. When I upload an object from my uploads screen I am using FlutterFire Handling Tasks to get upload progress.

The upload task works just fine, but when I navigate away from the uploading screen to the home screen, where I am displaying the Uploading StateProvider's progress, it only displays the current progress and does not get the updates happening in the background.

How do I configure RiverPod to listen to the background snapshot still running or should I just avoid using RiverPod for this and just use Firebase storage listener?

Uploading StateProvider

final uploadingStateProvider = StateProvider<String?>((ref) => null);

Firebase storage upload task is sending progress string to my StateProvider

task.snapshotEvents.listen((TaskSnapshot snapshot) {
  if (displayProgressNotification) {
    final int percent =
        ((snapshot.bytesTransferred / snapshot.totalBytes) * 100).round();
    if (percent >= 100) {
      context.read(uploadingStateProvider).state = null;
    } else {
      context.read(uploadingStateProvider).state =
          percent.toString();
    }
  } else {
    context.read(uploadingStateProvider).state = null;
  }
}, onDone: () async {
  context.read(uploadingStateProvider).state = null;
  if (deleteAfterUpload) {
    await file.delete();
  }
}, one rror: (e) {
  context.read(uploadingStateProvider).state = null;
  debugPrint(task.snapshot.toString());
  debugPrint(e.toString());
});

Home screen displays progress spinner with percentage, but it only displays the initial % it reads and does not get updated percentages from the background task

Consumer(
  builder: (context, watch, child) {
    final uploadingPercent =
        watch(uploadingStateProvider).state;
    if (uploadingPercent != null) {
      return Stack(
        alignment: Alignment.center,

        /// Note: First child is the bottom of the stack...
        children: [
          SpinKitDualRing(
            color: Colors.white.withOpacity(0.5),
            size: titleFontSize(shrinkOffset),
            lineWidth: 2.0,
            duration: const Duration(
                milliseconds: 1500),
          ),
          Text(
            '$uploadingPercent%',
            style: TextStyle(
              color: Colors.white.withOpacity(0.5),
              fontSize: uploadFontSize(shrinkOffset),
              fontWeight: FontWeight.w200,
            ),
          ),
        ],
      );
    } else {
      return const SizedBox.shrink();
    }
  },
),

CodePudding user response:

I would use the 1.0.0 version. No context

final uploadingStateProvider =
    StateNotifierProvider.autoDispose<UploadingState, int?>((ref) {
  return UploadingState(read: ref.read);
});

I would use a StateNotifier. The reader can be useful if you want the entire logic in the myUploadTask methode.

class UploadingState extends StateNotifier<int?> {
  final Reader read;
  StreamSubscription? mySubscription;

  UploadingState({required this.read}) : super(null);

  Future<void> myUploadTask(firebase_storage.UploadTask task) async {
    mySubscription = task.snapshotEvents.listen((TaskSnapshot snapshot) {
      final int percent =
          ((snapshot.bytesTransferred / snapshot.totalBytes) * 100).round();
      state = percent;
    }, onDone: () async {
      state = null;
    }, one rror: (e) {
      state = null;
      debugPrint(task.snapshot.toString());
      debugPrint(e.toString());
    });
  }

  @override
  void dispose() {
    mySubscription?.cancel();
    super.dispose();
    
  }
}

And your Consumer

Consumer(
  builder: (context,  ref,_) {
    final uploadingPercent = ref.watch(uploadingStateProvider);
    if (uploadingPercent != null) {
      return Stack(
        alignment: Alignment.center,

        /// Note: First child is the bottom of the stack...
        children: [
          SpinKitDualRing(
            color: Colors.white.withOpacity(0.5),
            size: titleFontSize(shrinkOffset),
            lineWidth: 2.0,
            duration: const Duration(
                milliseconds: 1500),
          ),
          Text(
            '$uploadingPercent%',
            style: TextStyle(
              color: Colors.white.withOpacity(0.5),
              fontSize: uploadFontSize(shrinkOffset),
              fontWeight: FontWeight.w200,
            ),
          ),
        ],
      );
    } else {
      return const SizedBox.shrink();
    }
  },
),

Call that somewhere or put all the logic in UploadingState()

ref.read(uploadingStateProvider.notifier).myUploadTask(task);
  • Related