2

I have class for images that are displayed in a listview. Sometimes the image fails and setstate does not reload the image nor any method that I have thought of works, even when assigning a unique key value.

The image class returns this code:

CachedNetworkImage(
        imageUrl: widget.url,
        fit: BoxFit.fitWidth,
        progressIndicatorBuilder: (context, url, downloadProgress) =>
            Container(
              alignment: Alignment.center,
              height: MediaQuery.of(context).size.height * 0.5,
              width: MediaQuery.of(context).size.width,
              child: CircularProgressIndicator(
                  value: downloadProgress.progress),
            ),
            errorWidget: (){
              return Container(
                alignment: Alignment.center,
                height: MediaQuery.of(context).size.height * 0.5,
                width: MediaQuery.of(context).size.width,
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: [
                    Icon(
                      Icons.perm_scan_wifi,
                      color: Colors.grey[600],
                      size: 50,
                    ),
                    Padding(
                      padding: const EdgeInsets.only(bottom: 20, top: 25),
                      child: Text(
                        'Failed To Load Image',
                        style: TextStyle(color: Colors.white, fontSize: 17),
                      ),
                    ),
                    Padding(
                      padding: const EdgeInsets.only(
                          bottom: 12.0, left: 10, right: 10),
                      child: Text(
                        'Check your internet connection and try again.',
                        textAlign: TextAlign.center,
                        style: TextStyle(color: Colors.grey),
                      ),
                    ),
                    FlatButton(
                      shape: RoundedRectangleBorder(
                          borderRadius: BorderRadius.circular(8)),
                      child: Text('Retry',
                          style: TextStyle(color: Colors.black)),
                      onPressed: () {
                        setState(() {});
                      },
                      color: Pigment.fromString('#FFCC00'),
                    )
                  ],
                ),
              );
            },
         
        )

Can you please propose a way to reload the image when it fails, I can only use cached network image, no other packages would be useful cuz I was the unique cache key feature.

anass naoushi
  • 859
  • 2
  • 10
  • 25
  • any error message? – John Joe Dec 09 '20 at 17:30
  • In regular error cases like connection timed out, the user got disconnected, etc.. The point is to simply reload when the user presses retry button, but in my case setstate does not work as you can see in the code – anass naoushi Dec 09 '20 at 20:18

2 Answers2

2

You can copy paste run full code below
You can use ValueNotifier to change cacheKey of CachedNetworkImage
In working demo
Step 1: image is not loaded in airplane mode
Step 2: turn off airplane mode
Step 3: and click Retry button then _networklHasErrorNotifier.value++
Step 4: ValueListenableBuilder rebuild CachedNetworkImage with new cacheKey

code snippet

ValueNotifier<int> _networklHasErrorNotifier = ValueNotifier(0);
...
ValueListenableBuilder(
                valueListenable: _networklHasErrorNotifier,
                builder: (BuildContext context, int count, Widget child) {
                  print("rebuild");
                  return CachedNetworkImage(
                    cacheKey: _networklHasErrorNotifier.value.toString(),
...                 
onPressed: () {
        print("clicked");
        _networklHasErrorNotifier.value++;      
      },                    

working demo

enter image description here

full code

import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  ValueNotifier<int> _networklHasErrorNotifier = ValueNotifier(0);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            ValueListenableBuilder(
                valueListenable: _networklHasErrorNotifier,
                builder: (BuildContext context, int count, Widget child) {
                  print("rebuild");
                  return CachedNetworkImage(
                    cacheKey: _networklHasErrorNotifier.value.toString(),
                    imageUrl: "https://via.placeholder.com/350x150",
                    fit: BoxFit.fitWidth,
                    progressIndicatorBuilder:
                        (context, url, downloadProgress) => Container(
                      alignment: Alignment.center,
                      height: MediaQuery.of(context).size.height * 0.5,
                      width: MediaQuery.of(context).size.width,
                      child: CircularProgressIndicator(
                          value: downloadProgress.progress),
                    ),
                    errorWidget: (context, url, error) {
                      return Container(
                        alignment: Alignment.center,
                        height: MediaQuery.of(context).size.height * 0.5,
                        width: MediaQuery.of(context).size.width,
                        child: Column(
                          mainAxisAlignment: MainAxisAlignment.center,
                          crossAxisAlignment: CrossAxisAlignment.center,
                          children: [
                            Icon(
                              Icons.perm_scan_wifi,
                              color: Colors.grey[600],
                              size: 50,
                            ),
                            Padding(
                              padding:
                                  const EdgeInsets.only(bottom: 20, top: 25),
                              child: Text(
                                'Failed To Load Image',
                                style: TextStyle(
                                    color: Colors.white, fontSize: 17),
                              ),
                            ),
                            Padding(
                              padding: const EdgeInsets.only(
                                  bottom: 12.0, left: 10, right: 10),
                              child: Text(
                                'Check your internet connection and try again.',
                                textAlign: TextAlign.center,
                                style: TextStyle(color: Colors.grey),
                              ),
                            ),
                            FlatButton(
                              shape: RoundedRectangleBorder(
                                  borderRadius: BorderRadius.circular(8)),
                              child: Text('Retry',
                                  style: TextStyle(color: Colors.black)),
                              onPressed: () {
                                print("clicked");
                                _networklHasErrorNotifier.value++;
                                //setState(() {});
                              },
                              //color: Pigment.fromString('#FFCC00'),
                            )
                          ],
                        ),
                      );
                    },
                  );
                })
          ],
        ),
      ),
    );
  }
}
chunhunghan
  • 51,087
  • 5
  • 102
  • 120
  • so I tried it as a standalone widget like you did, it works, but when I insert it inside a list view, the problems remains. what do you think I should do? – anass naoushi Dec 12 '20 at 23:33
  • need to reproduce your case, please post your reproduce code to a new question. thanks. – chunhunghan Dec 14 '20 at 00:40
1

I am also, Meet the same type of problem when my list view scrolls up or down that time inside the list item image reload again and again.

finally, I'm adding cacheExtent (int value) parameter in ListViewBuilder this problem is solved,

ListView.builder(
    cacheExtent: 9999,
    itemCount: snapshot.data.items.length,
    itemBuilder: (context, I) 
    {
       return getItemCard(
           child: CachedNetworkImage(
           imageUrl: snapshot.data.items[i],
           placeholder: (context, url) => CircularProgressIndicator(),
           errorWidget: (context, url, error) => Icon(Icons.error),
    ), 
  );
});
Karthikeyan M
  • 211
  • 2
  • 6