0

My understanding is that in Flutter, the only time the screen will update is when a value it uses is changed with setState().

Here's my general situation: I have a main screen that dynamically generates tiles containing information pulled from SharedPreferences. The tiles can be edited by clicking a button on the tile which pulls up a dialog box where fields can be entered to update the values in sharedpreferences. After a lot of work, I have this part working. Unfortunately, the screen does not update after the change is made (I have to restart the app or whatever to see the change).

I'm not really sure what to do here, I recall reading something about InheritedWidgets in flutter, but not sure if that is applicable here. I tried just adding setState(() {}) at the end of the logic in onPressed() in the dialog box, to no avail.

Here is the onPressed logic within the dialog box Widget

                onPressed: () async {
                  SharedPreferences prefs = await SharedPreferences.getInstance();
                  var paoData = (json.decode(prefs.getString(paoKey)) as List).map((i) => PAOData.fromJson(i)).toList();
                  int currIndex = int.parse(widget.paoData.digits);
                  PAOData updatedPAOEntry = paoData[currIndex];
                  if (personTextController.text != '') {
                    print('saving person');
                    updatedPAOEntry.person = personTextController.text;
                    personTextController.text = '';
                  }
                  if (actionTextController.text != '') {
                    print('saving action');
                    updatedPAOEntry.action = actionTextController.text;
                    actionTextController.text = '';
                  }
                  if (objectTextController.text != '') {
                    print('saving object');
                    updatedPAOEntry.object = objectTextController.text;
                    objectTextController.text = '';
                  }
                  print('will update $currIndex to: ${updatedPAOEntry.person} | ${updatedPAOEntry.action} | ${updatedPAOEntry.object}');
                  paoData[currIndex] = updatedPAOEntry;
                  prefs.setString(paoKey, json.encode(paoData));
                  setState(() {
                    paoData = paoData;
                  });
                  Navigator.of(context).pop();
                },

Separately, in the main page:

  List<PAOView> getPAOViews () {
    List<PAOView> paoViews = [];
    if (paoData != null) {
      for (int i = 0; i < paoData.length; i++) {
        PAOView paoView = PAOView(paoData: PAOData(paoData[i].digits,
          paoData[i].person, paoData[i].action, paoData[i].object,
          paoData[i].familiarity));
        paoViews.add(paoView);
      }
    }
    return paoViews;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('MEM++ Homepage'),
      ),
      body: Center(
        child: ListView(
          children: getPAOViews(),
        )
      ),
    );
  }

Full PAOView:

class PAOView extends StatefulWidget {
  final PAOData paoData;

  PAOView({this.paoData});

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

class _PAOViewState extends State<PAOView> {
  final personTextController = TextEditingController();
  final actionTextController = TextEditingController();
  final objectTextController = TextEditingController();
  SharedPreferences sharedPreferences;
  String paoKey = 'pao';

  @override
  void dispose() {
    // Clean up the controller when the widget is disposed.
    personTextController.dispose();
    actionTextController.dispose();
    objectTextController.dispose();
    super.dispose();
  }

  Widget build(BuildContext context) {
    Dialog dialog = Dialog(
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12.0)),
      //this right here
      child: Container(
        height: 350.0,
        width: 300.0,
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: <Widget>[
            Padding(
              padding: const EdgeInsets.all(8.0),
              child: Text('Person'),
            ),
            Container(
              padding: EdgeInsets.fromLTRB(20, 0, 20, 0),
              child: TextField(
                textAlign: TextAlign.center,
                controller: personTextController,
                decoration: InputDecoration(
                  contentPadding: EdgeInsets.all(5),
                  border: OutlineInputBorder(),
                  hintText: '${widget.paoData.person}',
                ),
              ),
            ),
            Padding(
              padding: const EdgeInsets.all(8.0),
              child: Text('Action'),
            ),
            Container(
              padding: EdgeInsets.fromLTRB(20, 0, 20, 0),
              child: TextField(
                textAlign: TextAlign.center,
                decoration: InputDecoration(
                    contentPadding: EdgeInsets.all(5),
                    border: OutlineInputBorder(),
                    hintText: '${widget.paoData.action}'),
              ),
            ),
            Padding(
              padding: const EdgeInsets.all(8.0),
              child: Text('Object'),
            ),
            Container(
              padding: EdgeInsets.fromLTRB(20, 0, 20, 0),
              child: TextField(
                textAlign: TextAlign.center,
                decoration: InputDecoration(
                    contentPadding: EdgeInsets.all(5),
                    border: OutlineInputBorder(),
                    hintText: '${widget.paoData.object}'),
              ),
            ),
            Container(
              width: 5,
              height: 10,
            ),
            FlatButton(
                onPressed: () async {
                  SharedPreferences prefs = await SharedPreferences.getInstance();
                  var paoData = (json.decode(prefs.getString(paoKey)) as List).map((i) => PAOData.fromJson(i)).toList();
                  int currIndex = int.parse(widget.paoData.digits);
                  PAOData updatedPAOEntry = paoData[currIndex];
                  if (personTextController.text != '') {
                    print('saving person');
                    updatedPAOEntry.person = personTextController.text;
                    personTextController.text = '';
                  }
                  if (actionTextController.text != '') {
                    print('saving action');
                    updatedPAOEntry.action = actionTextController.text;
                    actionTextController.text = '';
                  }
                  if (objectTextController.text != '') {
                    print('saving object');
                    updatedPAOEntry.object = objectTextController.text;
                    objectTextController.text = '';
                  }
                  print('will update $currIndex to: ${updatedPAOEntry.person} | ${updatedPAOEntry.action} | ${updatedPAOEntry.object}');
                  paoData[currIndex] = updatedPAOEntry;
                  prefs.setString(paoKey, json.encode(paoData));
                  setState(() {
                    paoData = paoData;
                  });
                  Navigator.of(context).pop();
                },
                child: Container(
                  decoration: BoxDecoration(
                    border: Border.all(),
                    borderRadius: BorderRadius.all(Radius.circular(5)),
                  ),
                  padding: EdgeInsets.fromLTRB(20, 5, 20, 5),
                  child: Text(
                    'Save',
                    style: TextStyle(fontSize: 18.0),
                  ),
                ))
          ],
        ),
      ),
    );

    return Center(
      child: Card(
          child: Stack(
        children: <Widget>[
          // TODO add overlay of familiarity somewhere
          ListTile(
            leading: Text(
              '${widget.paoData.digits}',
              style: TextStyle(fontSize: 26),
            ),
            title: Text('${widget.paoData.person}',
            style: TextStyle(fontSize: 20)),
            subtitle:
                Text('${widget.paoData.action} • ${widget.paoData.object}',
                style: TextStyle(fontSize: 16),),
            trailing: FlatButton(
                child: Text('Edit', style: TextStyle(color: Colors.cyan)),
                onPressed: () {
                  showDialog(context: context, child: dialog);
                }),
          ),
        ],
      )),
    );
  }
}
Matt Takao
  • 2,406
  • 3
  • 16
  • 30

2 Answers2

0

I was able to resolve this with the help of this answer, using callbacks. Very straight forward and easy to implement!

Emit the data to parent Widget in Flutter

Matt Takao
  • 2,406
  • 3
  • 16
  • 30
-1

You understood right,the setState is the solution for refreshing page including changes.But your edits/functions must be inside setState method.

For example: in your code, after calling onPressed it should be look like this:

 onPressed: () async {
              setState(){
              SharedPreferences prefs = await SharedPreferences.getInstance();
              var paoData = (json.decode(prefs.getString(paoKey)) as List).map((i) => PAOData.fromJson(i)).toList();
              int currIndex = int.parse(widget.paoData.digits);
              PAOData updatedPAOEntry = paoData[currIndex];
              if (personTextController.text != '') {
                print('saving person');
                updatedPAOEntry.person = personTextController.text;
                personTextController.text = '';
              }
             }
Soli
  • 89
  • 5
  • the main page is using a function to generate 100 tiles. each tile has the capability to create a dialog box. the dialog separately checks sharedpreferences data, and updates it. – Matt Takao Jan 22 '20 at 21:53