Home > Back-end >  Why Pull to Refresh does not stop?
Why Pull to Refresh does not stop?

Time:02-16

I am caching data online from API and then store it in Have DB. Everything works well until when it comes to refreshing the data by Pull to Refresh widget. When I pull the screen down to refresh the data, the CircularProgressIndicator widget starts circling endlessly, so the data does not update. Please look at the code provided below and let me know what the problem is. Thanks! Code:

class HomeScreen extends StatefulWidget {
  const HomeScreen({Key? key}) : super(key: key);

  @override
  _HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  List stories = [];
  late Box storyBox;
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
  }

  Future<void> openBox() async {
    final document = await getApplicationDocumentsDirectory();
    Hive.init(document.path);
    Hive.registerAdapter<Item>(ItemAdapter());
    storyBox = await Hive.openBox<Item>(storyBoxName);
    return;
  }

  Future<bool> getAllData() async {
    await openBox();
    const url = 'https://shaparak-732ff.firebaseio.com/items.json';
    try {
      final response = await http.get(Uri.parse(url));
      final extractedData = json.decode(response.body) as Map<String, dynamic>;
      await putData(extractedData);
    } catch (SocketException) {
      print('NO Internet');
    }
    var mymap = storyBox.toMap().values.toList().reversed.toList();
    if (mymap.isEmpty) {
      stories.add('Empty');
    } else {
      stories = mymap;
    }
    return Future.value(true);
  }

  Future putData(Map<String, dynamic> data) async {
    await storyBox.clear();
    Item newStory;
    data.forEach((key, value) {
      newStory = Item(
        title: value['title'],
        category: value['category'],
        content: value['content'],
        author: value['author'],
        id: key.toString(),
        date: DateTime.parse(value['id']),
      );
      storyBox.put(key, newStory);
    });
  }

  Future<void> updateData() async {
    const url = 'https://shaparak-732ff.firebaseio.com/items.json';
    try {
      final response = await http.get(Uri.parse(url));
      final extractedData = json.decode(response.body) as Map<String, dynamic>;

      await putData(extractedData);
      setState(() {});
    } catch (SocketException) {
      Fluttertoast.showToast(
          msg: "This is Center Short Toast",
          toastLength: Toast.LENGTH_SHORT,
          gravity: ToastGravity.CENTER,
          backgroundColor: Colors.red,
          textColor: Colors.white,
          fontSize: 16.0);
    }
  }

  @override
  void didChangeDependencies() {
    // TODO: implement didChangeDependencies
    super.didChangeDependencies();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.grey[300],
      appBar: AppBar(
        title: const Text('Shaparak'),
        backgroundColor: Theme.of(context).primaryColor,
        
      ),
      body: Center(
        child: FutureBuilder(
          future: getAllData(),
          builder: (context, snapshot) {
            if (snapshot.hasData) {
              if (stories.contains('empty')) {
                return const Text('No Data');
              } else {
                return RefreshIndicator(
                    child: ItemsGrid(stories as List<Item>),
                    onRefresh: updateData);
              }
            } else {
              return const CircularProgressIndicator();
            }
          },
        ),
      ),
    );
  }
}

CodePudding user response:

try seeing this video from flutter

https://www.youtube.com/watch?v=ORApMlzwMdM

CodePudding user response:

FutureBuilder's snapshot parameter also contains a snapshot.hasError that tells you if an exception was raised inside the future function. You can check if snapshot.hasError is true and display a Text(snapshot.error) to see what the error was.

Right now you are not making use of this error if it is happening. My guess is that you are getting and ignoring an error there.

I bet getAllData() is not completing correctly. Do you have any errors in your logs? You can try to add print('here'); kind of lines at the end of getAllData() and see if it actually executes till the end.

CodePudding user response:

When you call setState() in updateData() the build method is called. This causes your FutureBuilder to call getAllData() again.

Instead of calling getAllData() in your build method, call it in initState() at the beginning and save the data into the box.

Use a ValueListeneableBuilder to show the data directly from the box, and it will update when you update the box content

ValueListenableBuilder(
  valueListenable: storyBox.listenable(),
  builder: (context, box, widget) {
    // TODO get stories from box
  },
)
  • Related