0

I have an app that displays information using FutureBuilder.

When I open the Textfield the soft keyboard appears and the state of that FutureBuilder gets recreated. Is there any way to avoid that unnecessary running of the build method.

Apparently, when i use init state to call the future it works but for other functions like deleting data, it doesn't work because the future gets called only once.

this is my code

         class FutureBuilderWidget extends StatefulWidget {
          @override
          _FutureBuilderWidgetState createState() => _FutureBuilderWidgetState();
        }

        class _FutureBuilderWidgetState extends State<FutureBuilderWidget> {
          final _appBar = AppBar();

          @override 
          Widget build(BuildContext context) {
            return FutureBuilder(
                      future: Provider.of<QuickNotesProvider>(context, listen: false)
                          .fetchAndSetNotes(),
                      builder: (ctx, snapshot) {
                        return snapshot.connectionState == ConnectionState.waiting
                            ? Center(
                                child: Text('loading...'),
                              )
                            : Consumer<QuickNotesProvider>(
                                child: Center(
                                  child: Container(
                                    margin: EdgeInsets.only(
                                        top: MediaQuery.of(context).size.height * 0.3),
                                    child: Column(
                                      children: <Widget>[
                                        Icon(Icons.calendar_today,
                                            size: MediaQuery.of(context).size.height *
                                                0.07),
                                        SizedBox(
                                          height: 6,
                                        ),
                                        Text('Added Notes will appear here',
                                            style:
                                                Theme.of(context).textTheme.headline),
                                        SizedBox(
                                          height: 10,
                                        ),
                                        Text(
                                          'Tap + to add a quick note',
                                          style: TextStyle(
                                              fontSize:
                                                  MediaQuery.of(context).size.height *
                                                      0.02,
                                              fontWeight: FontWeight.w400),
                                        )
                                      ],
                                    ),
                                  ),
                                ),
                                builder: (ctx, eventData, ch) {
                                  if (eventData.quicknotes.length == 0) {
                                    return ch;
                                  } else {
                                    return Container(
                                      height: (MediaQuery.of(context).size.height -
                                              _appBar.preferredSize.height -
                                              MediaQuery.of(context).padding.top -
                                              MediaQuery.of(context).padding.bottom) *
                                          0.869,
                                      child: ListView.builder(
                                        itemCount: eventData.quicknotes.length,
                                        itemBuilder: (context, index) {
                                          return Container(
                                              margin: const EdgeInsets.only(
                                                  left: 10, top: 7, right: 10),
                                              child: Card(
                                                elevation: 5,
                                                shape: RoundedRectangleBorder(
                                                    borderRadius:
                                                        BorderRadius.circular(5)),
                                                color: Color.fromRGBO(230, 230, 230, 1),
                                                child: Column(
                                                  crossAxisAlignment:
                                                      CrossAxisAlignment.start,
                                                  children: <Widget>[
                                                    Padding(
                                                      padding: EdgeInsets.only(
                                                          top: 10, left: 8),
                                                      child: Text(
                                                        eventData.quicknotes[index]
                                                            .quicknote,
                                                      ),
                                                    ),
                                                    Row(
                                                      mainAxisAlignment:
                                                          MainAxisAlignment.end,
                                                      children: <Widget>[
                                                        Padding(
                                                          padding:
                                                              const EdgeInsets.only(
                                                                  right: 10.0),
                                                          child: InkWell(
                                                            onTap: () {
                                                              setState(() {
                                                                eventData.deleteEvents(
                                                                    eventData
                                                                        .quicknotes[
                                                                            index]
                                                                        .id);
                                                              });
                                                            },
                                                            child: Icon(
                                                              Icons.more_horiz,
                                                              color: Colors.black54,
                                                            ),
                                                          ),
                                                        )
                                                      ],
                                                    )
                                                  ],
                                                ),
                                              ));
                                        },
                                      ),
                                    );
                                  }
                                });
                      },
                    );
          }
        }
Prajwal
  • 65
  • 1
  • 8
  • Seems to be the same problem https://stackoverflow.com/questions/55234179/opening-keyboard-causes-stateful-widgets-to-be-re-initialized – kuhnroyal Dec 02 '19 at 16:09

1 Answers1

0

That's normal. When the soft keyboard appears your layout gets resized, hence rebuilt.

You can avoid resizing by setting the resizeToAvoidBottomInsets in the Scaffold ancestor of your widget, but if any rebuild occurs the problem will represent itself.

A way to handle this could be caching your Future results. I believe you can prevent the re-execution by using a Completer.

In your State create a

var myCompleter = Completer<YourDataDype>()

Then launch your future function in initState, but instead of returning the result, do this:

myCompleter.complete(yourData)

You can then pass myCompleter.future to your FutureBuilder and see what happens.

Personally I've never done this since I separate logic and presentation using the BLoC pattern, but it should work for your case indeed.

You should start splitting your logics too, since it'll avoid a lot of pain and improve your codebase quality!

magicleon94
  • 4,887
  • 2
  • 24
  • 53