Welcome to WuJiGu Developer Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
370 views
in Technique[技术] by (71.8m points)

dart - NoSuchMethodError: The method 'xxx' was called on null (flutter widget)

I know this question has been asked before but the previous questions and their answers have not helped me to figure out why I keep getting the exception:

NoSuchMethodError: The method 'showProgress' was called on null. Receiver: null Tried calling showProgress()

I created a widget class MyProgress

import 'package:flutter/material.dart';

class MyProgress extends StatefulWidget {
  Color backgroundColor;
  Color color;
  Color containerColor;
  double borderRadius;
  String text;
  MyProgressState progressState;

  MyProgress(
    {
      this.backgroundColor = Colors.black54,
      this.color = Colors.white,
      this.containerColor = Colors.transparent,
      this.borderRadius = 10,
      this.text
    }
  );

  @override
  createState() => progressState = new MyProgressState(
      backgroundColor: this.backgroundColor,
      color: this.color,
      containerColor: this.containerColor,
      borderRadius: this.borderRadius,
      text: this.text);

  void hideProgress() {
    progressState.hideProgress();
  }

  void showProgress() {
    progressState.showProgress();
  }

  void showProgressWithText(String title) {
    progressState.showProgressWithText(title);
  }

  static Widget getMyProgress(String title) {
    return MyProgress(
      backgroundColor: Colors.black12,
      color: Colors.black,
      containerColor: Colors.white,
      borderRadius: 5,
      text: title,
    );
  }
}

class MyProgressState extends State<MyProgress> {
  Color backgroundColor;
  Color color;
  Color containerColor;
  double borderRadius;
  String text;
  bool _opacity = false;

  MyProgressState(    
    {
      this.backgroundColor = Colors.black54,
      this.color = Colors.white,
      this.containerColor = Colors.transparent,
      this.borderRadius = 10,
      this.text
    }
  );

  @override
  Widget build(BuildContext context) {
    return Container(
      child: !_opacity ? null : new Opacity(opacity: _opacity ? 1 : 0,
        child: Stack(
          children: <Widget>[
            new Center(
              child: Container(
                width: 300,
                height: 120,
                decoration: new BoxDecoration(
                  color: containerColor,
                  border: Border.all(color: Colors.orange),
                  boxShadow: [BoxShadow(blurRadius: 5)],
                  borderRadius: new BorderRadius.all(
                     new Radius.circular(borderRadius)
                  )
                ),
              ),
            ),
            new Center(
              child: _getCenterContent(),
            )
          ],
        ),
      )
    );
  }

  Widget _getCenterContent() {
    if (text == null || text.isEmpty) {
      return _getCircularProgress();
    }

    return Center(
      child: Row(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          _getCircularProgress(),
          new Container(
            margin: const EdgeInsets.fromLTRB(20, 0, 0, 0),
            child: Text(
              text,
              style: new TextStyle(color: color, fontSize: 18),
            ),
          )
        ],
      ),
    );
  }

  Widget _getCircularProgress() {
    return CircularProgressIndicator(
        valueColor: new AlwaysStoppedAnimation(Colors.deepOrange));
  }

  void hideProgress() {
    setState(() {
      _opacity = false;
    });
  }

  void showProgress() {
    setState(() {
      _opacity = true;
    });
  }

  void showProgressWithText(String title) {
    setState(() {
      _opacity = true;
      text = title;
    });
  }
}

I use my progress in my screen class: ItemsLoad

class ItemsLoad extends StatefulWidget {

  @override
  State<StatefulWidget> createState() {
    return ItemsLoadState();
  }
}

class ItemsLoadState extends State<ItemsLoad> {
  var appBar = AppBar();
  final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();

  List<Item> items;

  MyProgress progress = MyProgress.getMyProgress("Fetching Data ...");

  ItemsLoadState();

  @override
  Widget build(BuildContext context) {
    if (items == null) {
      items = List<Item>();
      progress.showProgress();
      requestData();
    }

    return Scaffold(
      appBar: AppBar(
        title: Text("Items Loading"),
      ),
      body: SingleChildScrollView(
          child: Stack(
            children: <Widget>[
              Container(
                height: (MediaQuery.of(context).size.height - (appBar.preferredSize.height * 2)),
                padding: const EdgeInsets.symmetric(horizontal: 5),
                child: ListView.builder(
                  physics: BouncingScrollPhysics(),
                      itemCount: items.length,
                      itemBuilder: bookListView,
                ),
              ),
              Container(
                height: (MediaQuery.of(context).size.height - (appBar.preferredSize.height * 2)),
                padding: const EdgeInsets.symmetric(horizontal: 10),
                child: progress,
              ),
            ],
          ),
        ),
    );
  }
}

I would appreciate how to fix this exception since it occurs when the screen is loaded at first but an action button if tapped works well without any exception. Am still learning to use flutter and there could be some concepts I would missing here.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

The problem is that you are storing state in a widget. Widgets should be stateless, because new instances might be created when things are rebuild. When things are rebuild with a new instance of the widget and the type and key match those of the previous widget in the same place, then the element and the instance of the State subclass are reused. In that case createState isn’t invoked again.

In your case, when the widget gets rebuild for some reason, progressState will be empty.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to WuJiGu Developer Q&A Community for programmer and developer-Open, Learning and Share
...