PagingController stuck with isFetching TRUE

I am encountering a problem with the PagingController logic when using it within a GetX controller. Specifically, after invoking pagingController.fetchNextPage() for the first time, the _isFetching flag in PagingController remains permanently set to TRUE.

Also when fetchNextPage is called for the first time the listener does listen but it reads controllers.loadedItems as empty

PS: We need to use GetX (get | Flutter package) and not Provider and Consumer

Here’s a detailed breakdown of the issue:

  • Problem Description: Upon calling pagingController.fetchNextPage(), the execution appears to hang at the following line without throwing an error or returning any data:
final data = await pageFuture(_nextPageToken);

The _isFetching variable does not revert to FALSE, which seems to indicate that the fetch process never completes.

  • Context: This issue only occurs when the logic is implemented in a GetX controller. The same logic functions correctly within a stateful widget class. Our application requires using a controller because the fetched data is utilized across multiple screens.
  • Request: Could you please advise on potential causes or solutions for this behavior? It appears that the asynchronous fetch operation does not conclude properly within the GetX controller context.

Attached below is the relevant section of my album_controller class for your review. Your insights on resolving this issue would be greatly appreciated, as it is crucial for the data to be shared across various parts of our application.

AlbumController Class BELOW

import 'package:app/logger.dart';
import 'package:app/objects/fam_image.dart';
import 'package:app/screens/home/album_screen.dart';
import 'package:app/services/amity/user_service.dart';
import 'package:app/services/lock_time_service.dart';
import 'package:get/get.dart';
import 'package:flutter/material.dart';
import 'package:amity_sdk/amity_sdk.dart';
import 'package:shared_preferences/shared_preferences.dart';

class AlbumController extends GetxController {
  final ScrollController scrollController = ScrollController();
  RxBool showSelectButton = false.obs;
  RxList<FamImage> lockedFamImages = <FamImage>[].obs;
  RxList<FamImage> unlockedFamImages = <FamImage>[].obs;
  RxList<AmityPost> lockedPosts = <AmityPost>[].obs;
  RxList<AmityPost> unlockedPosts = <AmityPost>[].obs;
  late PagingController<AmityPost> controller;
  final userService = Get.find<UserService>();
  final locktimeService = Get.find<LockTimeService>();
  RxBool unlockPhotoExists = false.obs;
  RxBool hasUnlockPhotoOnce = false.obs;

  @override
  void onInit() {
    super.onInit();
    //? Initialize the page controller to retrieve posts from Amity
    initializePageController().then((value) {
      controller.fetchNextPage();
    });
    checkUnlockPhotoOnce().then((hasUnlocked) {
      showSelectButton.value = hasUnlocked;
    });
    getUnlockPhotoExistsSharedPreference().then((value) {
      unlockPhotoExists.value = value;
    });

    //? Check if the user have unlocked photos atleast once
    checkUnlockPhotoOnce().then((value) {
      hasUnlockPhotoOnce.value = value;
    });
  }

  @override
  void onClose() {
    scrollController.dispose();
    controller.dispose();
    super.onClose();
  }

  Future<void> initializePageController({bool isForce = false}) async {
    if (isForce) {
      lockedFamImages.clear();
      unlockedFamImages.clear();
      lockedPosts.clear();
      unlockedPosts.clear();
      controller.dispose();
    }

    controller = PagingController(
      pageFuture: (token) => AmitySocialClient.newFeedRepository()
          .getGlobalFeed()
          .getPagingData(token: token, limit: 20),
      pageSize: 20,
    );

    controller.addListener(
      () {
        AppLogger.logInfo('Listener called: Album Controller');
//? Listener is called once after fetchNextPage and loadedItems is empty when there are actually datas in amity
 for (AmityPost amityPost in controller.loadedItems) {
//OUR APP LISTENER LOGIC
}

      },
    );

    if (isForce) {
      // After reinitializing the controller, fetch the next page immediately
      controller.fetchNextPage();
    }
  }

  Future<bool> loadMoreGlobalFeed({bool isForce = false}) async {
    if (controller.hasMoreItems || isForce) {
      lockedPosts.clear();
      unlockedPosts.clear();

      controller.fetchNextPage();

      return true;
    } else {
      return false;
    }
  }

  Future<bool> checkUnlockPhotoOnce() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    return prefs.getBool('checkUnlockPhotoOnce') ?? false;
  }
}

@danielkang98 Let me pass this to check with my team and I’ll get back to you.

@danielkang98 Regarding the issue you encountered, we need more information to investigate:

  1. The version you are using.
  2. Could you please check the logs further to see if there is anything unusual on your side, or if there are additional logs that could help us investigate your issue?"