Сегодня я узнал о виджетах с отслеживанием состояния, базе данных Flutter, асинхронном программировании, поэтому пришло время поделиться своими знаниями с новичками, которые только начали изучать флаттер. Виджет, который мы узнали в предыдущей части, - это виджеты без состояния. Виджеты без сохранения состояния неизменяемы и не сохраняют состояние. Теперь, если вы работаете над проектом, который взаимодействует с пользователями, необходимо что-то изменить. Давайте разберемся с виджетами State и Stateful.

Что такое штат?

Состояние - это информация, которая может считываться синхронно при построении виджета и может быть изменена в течение жизненного цикла виджета. Давайте разберемся с определением.

Вышеупомянутое определение состоит из двух частей, которые приведены ниже.

  1. Процесс инициализации при создании виджета.
  2. Изменение состояния во время жизни виджета.

Фактически, виджет не меняется, его состояние будет изменено. Во Flutter классы, наследующие виджеты с отслеживанием состояния, неизменяемы, но само состояние может изменяться.

Как решить, какой виджет использовать?

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

Реализация виджета без сохранения состояния

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

/*
 * State less widget
 * Hello world will not be changed in the life cycle of widget
 */
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Center(
      child: Text(
        "Hello World",
        textDirection: TextDirection.ltr,
      ),
    );
  }
}

Реализация с отслеживанием состояния

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {

  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return _State();
  }



}

class _State extends State<MyApp> {

  String name = "";

  @override
  Widget build(BuildContext context) {
    // TODO: implement build

    return MaterialApp(
      title: "State Full Widget",
      home: Scaffold(
        appBar: AppBar(
          title: Text("State Full Widget"),

        ),
        body: Column(
          children: <Widget>[
            TextField(
              onChanged: (String s) {
                setState(() {
                  name = s;
                });
              },
            ),
            Text("Hello " + name)
          ],
        ),
      ),
    );
  }

}

Создать список задач

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

class Todo {
  // "_" show their access is private
  int _id;
  String _title;
  String _description;
  int _periority;
  String _date;

  /*
   * Constructor
   *
   * Note that you have only one constructor without name if you want
   * to add more constructor create a name constructor
   */
  Todo(this._title, this._description, this._periority, this._date);

  /*
   * Name Constructor
   */
  Todo.withId(this._id, this._title, this._description, this._periority,
      this._date);

  //getters

  String get date => _date;

  int get periority => _periority;

  String get description => _description;

  String get title => _title;

  int get id => _id;

  //setters

  set date(String value) {
    _date = value;
  }

  set periority(int value) {
    if(value > 0 && value <= 3)
      _periority = value;
  }

  set description(String value) {
    if(value.length <= 255)
      _description = value;
  }

  set title(String value) {
    if(value.length <= 255)
      _title = value;
  }

  /*
   * Convert the todos into map which is used to store in db
   */
  Map<String, dynamic> toMap() {
    var map = Map<String, dynamic>();
    map["title"] = _title;
    map["description"] = _description;
    map["periority"] = _periority;
    map["date"] = _date;
    if(_id != null) {
      map["id"] = _id;
    }

    return map;
  }

  /*
   * Convert the dynamic into todos
   */
  Todo.fromObject(dynamic o) {
    this._id = o["id"];
    this._title = o["title"];
    this._description = o["description"];
    this._periority = o["periority"];
    this._date = o["date"];
  }


}

База данных во Flutter

Для взаимодействия с базой данных мы можем использовать sqflite, который является плагином SQLite для флаттера, прежде чем мы сможем его использовать, мы должны предоставить зависимость в файле pubspec.yml.

Мы должны использовать другие зависимости для нашего приложения todo, то есть path_provider, который обычно используется для доступа к физическому местоположению для базы данных, потому что обе операционные системы имеют другое местоположение, поэтому может пользователь path_provider, поэтому нам не нужно беспокоиться о местоположении файловой системы другой операционной системы. Мы также используем intl-зависимость для форматирования даты, которая используется для интернационализации, которая используется в нашем приложении для форматирования даты.

Чтобы добавить зависимости sqflite, path_provider и intl, давайте обновим наш файл pubspec.yml. Мы используем любую версию sqflite и path_provider. Для intl мы используем версию больше или равную 0.15.7.

dependencies:
  flutter:
    sdk: flutter
  sqflite: any
  path_provider: any
  intl: ^0.15.7

Создать вспомогательный класс базы данных

Создайте переменную таблицы и столбцов и сделайте этот класс одноэлементным, чтобы его можно было создать один раз и поделиться экземпляром со всем приложением. Цель этого класса - читать и записывать данные в базу данных.

Как сделать синглтон класса в Dart?

  1. Сначала вам нужно создать частный экземпляр класса.
  2. Создайте частный конструктор.
  3. Используйте фабрику, чтобы каждый раз возвращать один и тот же экземпляр.

Создайте частный экземпляр класса и сделайте конструктор частным. В Dart есть одна интересная функция, например Factory Constructor, которая позволяет вам переопределить поведение по умолчанию вместо того, чтобы создавать новый экземпляр, он вернет один и тот же экземпляр каждый раз.

import 'package:sqflite/sqflite.dart';
import 'dart:async';
import 'dart:io';
import 'package:path_provider/path_provider.dart';
import 'package:todos_app/models/todo.dart';

class DbHelper {

    static final DbHelper _dbHelper = DbHelper._internal();
    static final DBVersion = 1;
    static Database _db;

    String tblTodo = "todo";
    String colId = "id";
    String colTitle = "title";
    String coldescription = "description";
    String colPeriority = "periority";
    String colDate = "date";

    /*
     * Named Constructor
     */
    DbHelper._internal();

    /*
     * Factory Constructor
     *
     * Use factory to always return the same instance
     */
    factory DbHelper() {
      return _dbHelper;
    }

    /*
     * Fetch the db instance. if it is null initialize it
     */
    Future<Database> get db async {
      if(_db == null) {
        _db = await initializeDB();
      }
      return _db;
    }

Асинхронное программирование во флаттере

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

Если ваше приложение не отвечает более 5 секунд, операционная система ответит, что ваше приложение не отвечает. Чтобы ваше приложение работало гладко, вы должны использовать отдельный поток для длительной задачи, чтобы ваш основной поток и вторичный поток работали параллельно. Это называется многопоточностью.

Во Flutter вы можете применять многопоточность, используя Future, async и await. давайте по очереди разберемся с Feature, async и await.

Будущее - это объект, который используется для получения ценности когда-нибудь в будущем. Если вы создаете метод, который возвращает future. Если вы вызовете этот метод, вы получите будущий объект немедленно, только когда оператор внутри будет успешно выполнен. Метод «then» будет вызван с результатом.

Другой способ справиться с асинхронным программированием во флаттере - использовать ключевое слово async-await.

Инициализируйте базу данных во вторичном потоке и выберите каталог приложения независимо от операционной системы. и создайте таблицу задач.

/*
 * initialize db in secondary thread (Worker thread) by using async
 * which will return Future of type DbHelper.
 *
 * await is used for long running operation
 */
Future<Database> initializeDB() async {
  Directory directory = await getApplicationDocumentsDirectory();
  String path = directory.path + 'todos.db';
  var dbTodos = await openDatabase(path, version: DBVersion, onCreate: _onCreate);
  return dbTodos;
}
/*
 * Create table todos
 */
void _onCreate(Database db, int version) async {
  await db.execute(
    "CREATE TABLE $tblTodo($colId INTEGER PRIMARY KEY, $colTitle TEXT, "
        "$coldescription TEXT, $colPeriority INTEGER, $colDate TEXT)"
  );
}

Создайте базу данных, которая будет доступна для всего класса, и создайте получатель для объекта базы данных. если он равен нулю, инициализируйте базу данных и в любом случае она вернет базу данных.

static Database _db;
Future<Database> get db async {
  if(_db == null) {
    _db = await initializeDB();
  }
  return _db;
}

Следующая часть:

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

📝 Прочтите этот рассказ позже в Журнале.

🗞 Просыпайтесь каждое воскресенье утром и слышите самые интересные истории, мнения и новости недели, ожидающие в вашем почтовом ящике: Получите заслуживающий внимания информационный бюллетень›