Перейти к содержимому

Initstate flutter statefull как сделать

  • автор:

Initstate flutter statefull как сделать

Класс StatefulWidget предназначен для создания виджетов, которые хранят состояние. При этом несмотря на то, что объекты класса StatefulWidget являются неизменяемыми (immutable), их состояние является изменяемым (mutable).

Что представляет собой состояние? Состояние — это некоторая информация, которая может быть считана синхронно при создании виджета и которая в процессе жизненного цикла виджета может измениться. Состояние может храниться в виде отдельных объектов State, либо в других объектах, на которые объект State подписывается.

Объекты State создаются с помощью метода createState , который вызывается фреймворком и который связывает их с виджетом StatefulWidget.

Например, определим простейший виджет StatefulWidget:

import 'package:flutter/material.dart'; void main() < runApp(MaterialApp( home: Scaffold( body: Counter(), appBar: AppBar(title: Text("METANIT.COM")),) )); >class Counter extends StatefulWidget< Counter(< super.key>); @override _CounterState createState() => _CounterState(); > class _CounterState extends State < int value = 0; @override Widget build(BuildContext context) < return Text( "Value: $value", style: TextStyle(fontSize: 22), ); >>

Итак,здесь определен класс Counter, который наследуется от StatefulWidget.

Его конструктор содержит один параметр — key, хотя при необходимости мы можем определять какие-то другие параметры, исходя из наших потребностей.

Также класс виджета должен переопределить метод createState() , который должен возвращать состояние для этого виджета

@override _CounterState createState() => _CounterState();

В данном случае это объект класса _CounterState . (Классы или члены классов, которые предваряются знаком прочерка (_), являются приватными по отношению к классам из других библиотек.)

Сам класс состояния унаследован от класса State , который типизирован классом класса виджета.

class _CounterState extends State

В самом классе определена переменная value , которая условно представляет данные, которые хранит класс состояния.

int value = 0;

Также нам надо переопределить метод build() , который возвращает виджет:

Widget build(BuildContext context)

Здесь мы просто возвращаем виджет Text , который выводит значение переменной value . Но естественно возвращаемая иерархия виджетов может быть более сложной.

Затем виджет Counter встравивается в приложение в элемент Scaffold:

void main() < runApp(MaterialApp( home: Scaffold( body: Counter(),

В итоге при запуске приложения мы увидим текст со значением переменной value

StatefulWidget в Flutter

Но ключевая идея StatefulWidget состоит в том, что мы можем менять его состояние. Поэтому добавим изменение переменной value по нажатию на кнопку:

import 'package:flutter/material.dart'; void main() < runApp(MaterialApp( home: Scaffold( body: Counter(), appBar: AppBar(title: Text("METANIT.COM")),) )); >class Counter extends StatefulWidget< Counter(< super.key>); @override _CounterState createState() => _CounterState(); > class _CounterState extends State< int value = 0; @override Widget build(BuildContext context) < return ElevatedButton( child: Text("Value: $value", style: TextStyle(fontSize: 22)), onPressed:()< setState(() < value++; >);> ); > >

Теперь для простоты значение переменной value выводится в качестве текста на кнопку. При нажатии на кнопку будет вызываться функция, которая увеличит значение value на единицу. Чтобы указать, что состояние изменилось, виджет вызывает метод State.setState() . В этот метод передается функция, которая не принимает параметров и ничего не возвращает. И именно в ней мы можем изменить значение value.

В итоге по нажатию на кнопку увеличится значение переменной value:

StatefulWidget и изменение состояния State с помощью метода State.setState в Flutter

Передача данных в State

При необходимости в объект State можно передавать данные извне. В этом случае передача осуществляется через StatefulWidget. Например, изменим выше приведенный пример таким образом, чтобы State принимал начальные данные извне:

import 'package:flutter/material.dart'; void main() < runApp(MaterialApp( home: Scaffold( body: Column(children:[ Counter(value: 4, increment: 2), Counter(value:-1, increment: 1) ]), appBar: AppBar(title: Text("METANIT.COM")),) )); >class Counter extends StatefulWidget< int value = 0; int increment = 1; Counter(< super.key, required this.value, required this.increment>); @override _CounterState createState() => _CounterState(this.value, this.increment); > class _CounterState extends State< int value = 0; int increment = 1; _CounterState(this.value, this.increment); @override Widget build(BuildContext context) < return ElevatedButton( child: Text("Value: $value", style: TextStyle(fontSize: 22)), onPressed:()< setState(() < value = value + increment; >);> ); > >

В данном случае в State добавлена новая переменная increment , на которую увеличивается значение переменной value. Для получения извне значений для этих переменных определен конструктор _CounterState(this.value, this.increment)

При создании объекта State виджет Counter передает в конструктор соответствующие данные:

_CounterState createState() => _CounterState(this.value, this.increment);

При этом эти значения виджет Counter сам принимает извне с помощью своего конструктора:

Counter(< super.key, required this.value, required this.increment>);

В итоге при применении виджета мы можем передавать в него различные данные:

Column(children:[ Counter(value: 4, increment: 2), Counter(value:-1, increment: 1) ])

Передача данных в StatefulWidget и State и метод State.setState в Flutter

Получение виджета

С помощью свойства widget внутри State можно обращаться к виджету StatefulWidget, к которому привязан объект State:

import 'package:flutter/material.dart'; void main() < runApp(MaterialApp( home: Scaffold( body: Column(children:[ Counter(increment: 2), Counter(increment: 1), ]), appBar: AppBar(title: Text("METANIT.COM")),) )); >class Counter extends StatefulWidget< int increment = 1; Counter(< super.key, required this.increment>); @override _CounterState createState() => _CounterState(); > class _CounterState extends State< int value = 0; @override Widget build(BuildContext context) < return ElevatedButton( child: Text("Value: $value", style: TextStyle(fontSize: 22)), onPressed:()< setState(() < value = value + widget.increment; >);> ); > >

В данном случае переменная increment определена только внутри класса Counter, и чтобы к ней обратиться, применяется выражение widget.increment , где widget - это виджет Counter. Подобным образом можно обращаться к другим полям и методам из виджета при их наличии.

Вынос логики изменения состояния в метод

В примерах выше вся логика изменения состояния сосредоточена в функции из onPressed . Но все эти действия также можно вынести в отдельный метод:

import 'package:flutter/material.dart'; void main() < runApp(MaterialApp( home: Scaffold( body: Column(children:[ Counter(increment: 2), Counter(increment: 1), ]), appBar: AppBar(title: Text("METANIT.COM")),) )); >class Counter extends StatefulWidget< int increment = 1; Counter(< super.key, required this.increment>); @override _CounterState createState() => _CounterState(); > class _CounterState extends State< int value = 0; increaseValue()< setState(() < value = value + widget.increment; >); > @override Widget build(BuildContext context) < return ElevatedButton( child: Text("Value: $value", style: TextStyle(fontSize: 22)), onPressed:()< increaseValue();>); > >

Если метод, в который вынесены все действия, ничего не возвращает и не принимает никаких параметров, то есть соответствует определению onPressed (как в данном случае), то можно напрямую присвоить функцию параметру onPressed:

ElevatedButton( child: Text("Value: $value", style: TextStyle(fontSize: 22)), onPressed: increaseValue );

Жизненный цикл приложения во Flutter

Если вы здесь, это означает, что вам может быть интересно, что происходит за кулисами, когда запускается ваше приложение.

Жизненный цикл приложения Flutter относится к нескольким этапам, которые проходит приложение при запуске, запуске и завершении работы. Понимание жизненного цикла приложения имеет решающее значение, поскольку оно позволяет создавать код, который выполняется в определенные моменты жизненного цикла, например, при инициализации приложения или при его закрытии.

Во Flutter доступно несколько крючков жизненного цикла приложения. Эти перехватчики позволяют приложению выполнять код в определенные моменты жизненного цикла приложения, например, при инициализации приложения, когда приложение становится видимым или неактивным и когда приложение закрывается. Крючки жизненного цикла перечислены следующим образом:

  1. initState()
  2. didChangeDependencies()
  3. build()
  4. didUpdateWidget()
  5. dispose()

Вот краткий обзор каждого крючка:

initState()

Метод initState() - это перехватчик жизненного цикла, который вызывается при инициализации приложения. Этот метод является хорошим местом для инициализации любого состояния приложения, такого как загрузка данных с удаленного сервера или подключение к базе данных.

Вот пример того, как метод initState() может быть использован в приложении Flutter:

class InitExample extends StatefulWidget < @override _InitExampleState createState() =>_InitExampleState(); > class _InitExampleState extends State < String data; @override void initState() < super.initState(); fetchData().then((value) < setState(() < data = value; >); >); > @override Widget build(BuildContext context) < return Scaffold( body: data != null ? Text(data) : CircularProgressIndicator(), ); >>

Метод initState() используется в предыдущем примере для извлечения данных с сервера и сохранения их в переменной data. Затем данные отображаются на экране с помощью метода build() . Вместо этого отображается знак загрузки, если данные еще не доступны.

didChangeDependencies()

Каждый раз, когда изменяются зависимости виджета, вызывается метод didChangeDependencies() . Понимание этого метода важно, поскольку оно помогает вам обновлять состояние виджета в зависимости от изменений в его зависимостях.

Вот как вы могли бы использовать метод didChangeDependencies() в приложении Flutter:

 @override void didChangeDependencies()

Важно отметить, что хук didChangeDependencies() вызывается всякий раз, когда изменяются зависимости виджета, а не только при изменении значения унаследованного виджета. Это означает, что вы должны быть осторожны и обновлять состояние виджета только при необходимости, так как ненужное обновление состояния может привести к проблемам с производительностью.

build()

Метод build() используется для создания пользовательского интерфейса для вашего приложения.

Этот метод должен возвращать виджет, представляющий пользовательский интерфейс приложения. Он вызывается каждый раз, когда приложению необходимо обновить свой внешний вид, и отвечает за создание виджетов, составляющих пользовательский интерфейс приложения.

Вот простой пример того, как используется метод build() :

class InitExample extends StatefulWidget < @override _InitExampleState createState() =>_InitExampleState(); > class _InitExampleState extends State  < String data = "This is an example"; @override Widget build(BuildContext context) < return Scaffold( body: Text(data), ); >> 

Метод build() вызывается часто, поэтому важно убедиться, что он эффективен и выполняет только то, что необходимо для создания пользовательского интерфейса. Это помогает поддерживать бесперебойную и быструю работу приложения.

didUpdateWidget()

Метод didUpdateWidget() вызывается каждый раз, когда виджет перестраивается и его зависимости изменяются. Этот метод полезен для обновления состояния виджета на основе изменений его зависимостей.

Вот как вы могли бы использовать метод didUpdateWidget() в приложении Flutter:

@override void didUpdateWidget(MyApp oldWidget)

Метод didUpdateWidget() вызывается всякий раз, когда виджет перестраивается и его зависимости изменяются, поэтому важно убедиться, что он эффективен и делает только то, что необходимо для обновления состояния виджета.

dispose()

Метод dispose() используется для очистки любых ресурсов, удерживаемых состоянием при его закрытии.

 StreamSubscription _streamSubscription; @override void dispose()

В предыдущем примере метод dispose() используется для закрытия соединения StreamSubscription. Это высвобождает ресурсы и обеспечивает эффективную работу приложения.

Вывод

Чтобы создать плавный и бесшовный пользовательский интерфейс в вашем приложении Flutter, вы должны сначала понять жизненный цикл приложения.

Мы надеемся, вы нашли это краткое объяснение жизненного цикла приложения Flutter полезным! Если у вас есть какие-либо вопросы, не стесняйтесь обращаться к нам.

initState method

The framework will call this method exactly once for each State object it creates.

Override this method to perform initialization that depends on the location at which this object was inserted into the tree (i.e., context) or on the widget used to configure this object (i.e., widget).

If a State's build method depends on an object that can itself change state, for example a ChangeNotifier or Stream, or some other object to which one can subscribe to receive notifications, then be sure to subscribe and unsubscribe properly in initState, didUpdateWidget, and dispose:

  • In initState, subscribe to the object.
  • In didUpdateWidget unsubscribe from the old object and subscribe to the new one if the updated widget configuration requires replacing the object.
  • In dispose, unsubscribe from the object.

You should not use BuildContext.dependOnInheritedWidgetOfExactType from this method. However, didChangeDependencies will be called immediately following this method, and BuildContext.dependOnInheritedWidgetOfExactType can be used there.

Implementations of this method should start with a call to the inherited method, as in super.initState() .

Implementation

@protected @mustCallSuper void initState() < assert(_debugLifecycleState == _StateLifecycle.created); if (kFlutterMemoryAllocationsEnabled) < MemoryAllocations.instance.dispatchObjectCreated( library: _flutterWidgetsLibrary, className: '$State', object: this, ); >>

initState() not called when building stateful widget

I am trying to build a widget and do something in the initState() function. I have done it before in other cases, but this time the initState() is just not called. I have put breakpoints, the application goes into the constructor (assert line) and the object in the assert is not null, so it should go on and initialize the state. But it doesn't, and I don't understand why. Any help would be greatly appreciated. Thanks. Here's the code:

class MyWidget extends StatefulWidget < SomeOtherObject someOtherObject; MyWidget() : assert(someOtherObject != null) ; @override _MyWidgetState createState() => _MyWidgetState(); > class _MyWidgetState extends State  < @override void initState() < super.initState(); // widget.someOtherObject.addListener(update); >@override Widget build(BuildContext context) < // . >> 

asked Dec 8, 2019 at 19:55
2,229 4 4 gold badges 25 25 silver badges 32 32 bronze badges
So if you put a print() statement in initState, it won't print anything?
Dec 8, 2019 at 19:59
Nothing. I already tried it 🙂 Doesn't stop in a breakpoint on that line, doesn't print anything.
Dec 9, 2019 at 0:49
Where are you using this widget?
Dec 9, 2019 at 0:56
So you know, initState doesn't get called on hot reload, only on hot restart.
Dec 9, 2019 at 0:57

@BenjaminS. yes, I know. As I said, it doesn't stop on breakpoint and there's nothing printed to the console.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *