{"id":330882,"date":"2022-03-21T09:00:54","date_gmt":"2022-03-21T09:00:54","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=330882"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=330882","title":{"rendered":"<span>\u0410\u043a\u0442\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u0441\u043f\u0438\u0441\u043a\u0430\u0445 Flutter-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f<\/span>"},"content":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/672\/360\/c92\/672360c92ec0848a01ae020f5adba27b.png\" width=\"1804\" height=\"1019\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/672\/360\/c92\/672360c92ec0848a01ae020f5adba27b.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u0418\u043d\u043e\u0433\u0434\u0430 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u0442\u043e\u0431\u0440\u0430\u0437\u0438\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a c \u0434\u0430\u043d\u043d\u044b\u043c\u0438. \u0415\u0441\u043b\u0438 \u044d\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0441\u043f\u0438\u0441\u043e\u043a, \u043e\u043d \u0440\u0435\u0434\u043a\u043e \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u0438. \u041e\u0434\u043d\u0430\u043a\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0441\u043f\u0438\u0441\u043a\u043e\u0432, \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0434\u043e\u043b\u0436\u043d\u043e \u043c\u0435\u043d\u044f\u0442\u044c\u0441\u044f, \u0447\u0430\u0441\u0442\u043e \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442 \u043a \u043e\u0448\u0438\u0431\u043a\u0430\u043c, \u0441\u043b\u043e\u0436\u043d\u044b\u043c \u0434\u043b\u044f \u0432\u044b\u044f\u0432\u043b\u0435\u043d\u0438\u044f \u0438 \u043e\u0442\u043b\u0430\u0434\u043a\u0438.<\/p>\n<p>\u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0445\u043e\u0447\u0443 \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u0442\u044c \u043e \u0441\u0432\u043e\u0451\u043c \u043e\u043f\u044b\u0442\u0435 \u0440\u0430\u0431\u043e\u0442\u044b \u0441\u043e \u0441\u043f\u0438\u0441\u043a\u0430\u043c\u0438 \u0438 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u044e \u0432 \u043d\u0438\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0439 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438, \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u0438, \u0430\u043a\u0442\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u0434\u0440\u0443\u0433\u0438\u0435.<\/p>\n<p>\u0421\u0442\u0430\u0442\u044c\u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0430 \u0432 \u0432\u0438\u0434\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0438 \u0438 \u043e\u0440\u0438\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0430 \u043d\u0430 Flutter-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u0441 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u043c \u043e\u043f\u044b\u0442\u043e\u043c, \u0445\u043e\u0442\u044f, \u043d\u0430\u0434\u0435\u044e\u0441\u044c, \u0438 \u043e\u043f\u044b\u0442\u043d\u044b\u043c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c \u043e\u043d\u0430 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u0435\u0437\u043d\u0430. \u0414\u043b\u044f \u043b\u0443\u0447\u0448\u0435\u0433\u043e \u0443\u0441\u0432\u043e\u0435\u043d\u0438\u044f \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0430 \u0436\u0435\u043b\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0437\u043d\u0430\u0442\u044c \u043e\u0441\u043d\u043e\u0432\u044b \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u0438\u043c\u0435\u0442\u044c \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0439 \u043e\u043f\u044b\u0442 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u043e\u0439 rxdart, \u043f\u043e\u043d\u0438\u043c\u0430\u0442\u044c, \u043a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 ChangeNotifier.<\/p>\n<p>\u0412\u0437\u044f\u0432 \u0437\u0430 \u043e\u0441\u043d\u043e\u0432\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441 \u043f\u0440\u0438\u043c\u0438\u0442\u0438\u0432\u043d\u044b\u043c \u0441\u043f\u0438\u0441\u043a\u043e\u043c, \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u043d\u0430\u0440\u0430\u0449\u0438\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c, \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u044f \u043e\u0442 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0441\u0442\u044b\u0445 \u0438 \u0447\u0430\u0441\u0442\u044b\u0445 \u0437\u0430\u0434\u0430\u0447 \u043a \u0431\u043e\u043b\u0435\u0435 \u0441\u043b\u043e\u0436\u043d\u044b\u043c \u0438 \u0440\u0435\u0434\u043a\u0438\u043c. \u0427\u0442\u043e\u0431\u044b \u0443\u043c\u0435\u043d\u044c\u0448\u0438\u0442\u044c \u043e\u0431\u044a\u0451\u043c \u043a\u043e\u0434\u0430 \u0438 \u0443\u043f\u0440\u043e\u0441\u0442\u0438\u0442\u044c \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u0442\u0435\u043c\u044b, \u044f \u043d\u0435 \u0431\u0443\u0434\u0443 \u0431\u0440\u0430\u0442\u044c \u043a\u0430\u043a\u043e\u0439-\u0442\u043e \u043f\u0440\u0438\u043c\u0435\u0440 \u0438\u0437 \u0436\u0438\u0437\u043d\u0438, \u0430 \u0441\u043a\u043e\u043d\u0446\u0435\u043d\u0442\u0440\u0438\u0440\u0443\u044e\u0441\u044c \u043d\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0438 \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0421\u0442\u0430\u0442\u044c\u044f \u0440\u0430\u0437\u0431\u0438\u0442\u0430 \u043d\u0430 \u0447\u0430\u0441\u0442\u0438 \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0447\u0442\u043e \u043f\u043e \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0438 \u043f\u0440\u043e\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u043e\u0447\u0435\u0440\u0435\u0434\u043d\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u0432\u044b \u0431\u0443\u0434\u0435\u0442\u0435 \u0438\u043c\u0435\u0442\u044c \u0440\u0430\u0431\u043e\u0447\u0435\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435. \u0418\u0437-\u0437\u0430 \u0442\u0430\u043a\u043e\u0433\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0430 \u0447\u0438\u0442\u0430\u0442\u044c \u0441\u0442\u0430\u0442\u044c\u044e \u043c\u043e\u0436\u043d\u043e \u043d\u0435 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e, \u0430 \u043b\u0438\u0448\u044c \u0434\u043e \u043c\u043e\u043c\u0435\u043d\u0442\u0430 \u0441 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435\u043c \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b, \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u0439 \u0432\u0430\u043c. \u0412 \u043d\u0430\u0447\u0430\u043b\u0435 \u043a\u0430\u0436\u0434\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u0441\u0442\u0430\u0442\u044c\u0438 \u044f \u0431\u0443\u0434\u0443 \u0440\u0430\u0437\u043c\u0435\u0449\u0430\u0442\u044c \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 \u043a\u043e\u0434 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u0434\u0430\u043d\u043d\u043e\u0439 \u0447\u0430\u0441\u0442\u0438.<\/p>\n<h2>\u0421\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435<\/h2>\n<ol>\n<li>\n<p><a href=\"#terms\" rel=\"noopener noreferrer nofollow\">\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0430\u044f \u0442\u0435\u0440\u043c\u0438\u043d\u043e\u043b\u043e\u0433\u0438\u044f \u0438 \u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#struct\" rel=\"noopener noreferrer nofollow\">\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#prepare\" rel=\"noopener noreferrer nofollow\">\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#async\" rel=\"noopener noreferrer nofollow\">\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#filters\" rel=\"noopener noreferrer nofollow\">\u0424\u0438\u043b\u044c\u0442\u0440 \u0438 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0430<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#load_data\" rel=\"noopener noreferrer nofollow\">\u041f\u043e\u0440\u0446\u0438\u043e\u043d\u043d\u0430\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#actual\" rel=\"noopener noreferrer nofollow\">\u0410\u043a\u0442\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#work_list\" rel=\"noopener noreferrer nofollow\">\u0420\u0430\u0431\u043e\u0442\u0430 \u0441\u043e \u0441\u043f\u0438\u0441\u043a\u043e\u043c \u0437\u0430\u043f\u0438\u0441\u0435\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u0441\u044b\u043b\u0430\u044e\u0442\u0441\u044f \u043d\u0430 \u0434\u0440\u0443\u0433\u0438\u0435 \u0437\u0430\u043f\u0438\u0441\u0438<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#list_update_records\" rel=\"noopener noreferrer nofollow\">\u0421\u043f\u0438\u0441\u043e\u043a \u0438\u0437 \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c\u044b\u0445 \u0437\u0430\u043f\u0438\u0441\u0435\u0439<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#conclusion\" rel=\"noopener noreferrer nofollow\">\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/a><\/p>\n<\/li>\n<\/ol>\n<p><a class=\"anchor\" name=\"terms\" id=\"terms\"><\/a><\/p>\n<h2>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0430\u044f \u0442\u0435\u0440\u043c\u0438\u043d\u043e\u043b\u043e\u0433\u0438\u044f \u0438 \u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f<\/h2>\n<ul>\n<li>\n<p>\u0417\u0430\u043f\u0438\u0441\u044c \u2014 \u043e\u0431\u044a\u0435\u043a\u0442, \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0431\u0443\u0434\u0435\u0442 \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043e\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0438 \u0441\u043f\u0438\u0441\u043a\u0430;<\/p>\n<\/li>\n<li>\n<p>\u0422\u0438\u0437\u0435\u0440 \u2014 \u0433\u0440\u0430\u0444\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0437\u0430\u043f\u0438\u0441\u0438 \u0441\u043f\u0438\u0441\u043a\u0430;<\/p>\n<\/li>\n<li>\n<p>\u041a\u0443\u0431\u0438\u0442 \u2014 \u043e\u0431\u044a\u0435\u043a\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u0441\u0435\u0433\u0434\u0430 \u0445\u0440\u0430\u043d\u0438\u0442 \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0437\u0430\u043f\u0438\u0441\u0438 \u0441\u043f\u0438\u0441\u043a\u0430;<\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0441\u043f\u0438\u0441\u043a\u0430 \u2014 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u044b\u043c \u0441\u043f\u0438\u0441\u043a\u0430 \u0438 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435\u043c, \u043d\u0430 \u043a\u0430\u043a\u043e\u0439 \u0441\u0442\u0430\u0434\u0438\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u043e\u043d \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f;<\/p>\n<\/li>\n<li>\n<p>\u0418\u0441\u0442\u043e\u0447\u043d\u0438\u043a \u0434\u0430\u043d\u043d\u044b\u0445 \u2014 \u043b\u044e\u0431\u043e\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435, \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435. \u041c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043a\u0430\u043a \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u0430\u044f \u0432 \u044f\u0437\u044b\u043a \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u0430\u043d\u043d\u044b\u0445, \u0442\u0430\u043a \u0438 \u043b\u044e\u0431\u043e\u0439 \u0441\u0435\u0440\u0432\u0438\u0441, \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u0439 \u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0430 \u0437\u0430\u043f\u0440\u043e\u0441 \u043e\u0442 \u043a\u043b\u0438\u0435\u043d\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0411\u0430\u0437\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u2014 \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u0441\u0442\u0430\u0442\u044c\u0438 \u044d\u0442\u043e \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0445\u0440\u0430\u043d\u0438\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u0441 \u0437\u0430\u043f\u0438\u0441\u044f\u043c\u0438;<\/p>\n<\/li>\n<li>\n<p>\/\/ + \u2014 \u0441\u0442\u0440\u043e\u043a\u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0430;<\/p>\n<\/li>\n<li>\n<p>\/\/ &#8212; \u2014 \u0441\u0442\u0440\u043e\u043a\u0430 \u0443\u0434\u0430\u043b\u0435\u043d\u0430;<\/p>\n<\/li>\n<li>\n<p>\/\/ * \u2014 \u0441\u0442\u0440\u043e\u043a\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0430.<\/p>\n<\/li>\n<\/ul>\n<p><a class=\"anchor\" name=\"struct\" id=\"struct\"><\/a><\/p>\n<h2>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/h2>\n<ul>\n<li>\n<p>models.dart \u2014 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440 \u0434\u0430\u043d\u043d\u044b\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438;<\/p>\n<\/li>\n<li>\n<p>repository.dart \u2014 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u043d\u0438\u043c\u0438;<\/p>\n<\/li>\n<li>\n<p>list_state.dart \u2014 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u0430;<\/p>\n<\/li>\n<li>\n<p>list_controller.dart \u2014 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u043e\u043c;<\/p>\n<\/li>\n<li>\n<p>widgets\\record_teaser.dart \u2014 \u0432\u0438\u0434\u0436\u0435\u0442 \u0434\u043b\u044f \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0438\u0441\u0438 \u0441\u043f\u0438\u0441\u043a\u0430 (\u0442\u0438\u0437\u0435\u0440\u0430);<\/p>\n<\/li>\n<li>\n<p>widgets\\list_status_indicator.dart \u2014 \u0432\u0438\u0434\u0436\u0435\u0442 \u0434\u043b\u044f \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u0430;<\/p>\n<\/li>\n<li>\n<p>main.dart \u2014 \u0442\u043e\u0447\u043a\u0430 \u0432\u0445\u043e\u0434\u0430 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435.<\/p>\n<\/li>\n<\/ul>\n<p>\u0421\u043f\u0438\u0441\u043e\u043a \u0444\u0430\u0439\u043b\u043e\u0432 \u043e\u0442\u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d \u0432 \u043f\u043e\u0440\u044f\u0434\u043a\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u043e\u0434\u043d\u0438\u0445 \u0444\u0430\u0439\u043b\u043e\u0432 \u043e\u0442 \u0434\u0440\u0443\u0433\u0438\u0445. \u0414\u0440\u0443\u0433\u0438\u043c\u0438 \u0441\u043b\u043e\u0432\u0430\u043c\u0438, \u0447\u0435\u043c \u0432\u044b\u0448\u0435 \u0444\u0430\u0439\u043b, \u0442\u0435\u043c \u043c\u0435\u043d\u044c\u0448\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u043e\u043d \u0438\u043c\u0435\u0435\u0442 \u043e\u0442 \u0434\u0440\u0443\u0433\u0438\u0445 \u0444\u0430\u0439\u043b\u043e\u0432. \u0422\u0430\u043a \u0436\u0435 \u0434\u0430\u043d\u043d\u044b\u0439 \u0441\u043f\u0438\u0441\u043e\u043a \u0438\u043b\u043b\u044e\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u0442 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0437\u043c\u0435\u043d\u044f\u0442\u044c \u0444\u0430\u0439\u043b\u044b \u0432 \u043a\u0430\u0436\u0434\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u0441\u0442\u0430\u0442\u044c\u0438.<\/p>\n<p><a class=\"anchor\" name=\"prepare\" id=\"prepare\"><\/a><\/p>\n<h2>\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f<\/h2>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/b8f\/031\/8ee\/b8f0318eebca1855b502a9d96e7bff61.gif\" alt=\"\" title=\"\" width=\"320\" height=\"569\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/b8f\/031\/8ee\/b8f0318eebca1855b502a9d96e7bff61.gif\"\/><figcaption><\/figcaption><\/figure>\n<p><a href=\"https:\/\/github.com\/astoniocom\/fl_list_example\/tree\/init\" rel=\"noopener noreferrer nofollow\">\u041e\u0442\u043a\u0440\u044b\u0442\u044c \u043a\u043e\u0434 \u043d\u0430 GitHub<\/a><\/p>\n<p>\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u043c \u043a\u0430\u0440\u043a\u0430\u0441 \u0434\u043b\u044f \u0431\u0443\u0434\u0443\u0449\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0412 \u043d\u0451\u043c \u0431\u0443\u0434\u0435\u0442 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d \u0431\u0435\u0441\u043a\u043e\u043d\u0435\u0447\u043d\u044b\u0439 \u0441\u043f\u0438\u0441\u043e\u043a \u0431\u0435\u0437 \u043a\u0430\u043a\u0438\u0445-\u043b\u0438\u0431\u043e \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<p>\u0412\u044b\u043f\u043e\u043b\u043d\u0438\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043d\u043e\u0432\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<pre><code class=\"bash\">> flutter create fl_list_example<\/code><\/pre>\n<h4>main.dart<\/h4>\n<p>\u0418\u0437\u043c\u0435\u043d\u0438\u043c \u0444\u0430\u0439\u043b <em>main.dart<\/em> \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<pre><code class=\"dart\">\/* file: main.dart *\/  import 'package:flutter\/material.dart';  void main() {   runApp(const MyApp()); }  class MyApp extends StatelessWidget {   const MyApp({Key? key}) : super(key: key);    @override   Widget build(BuildContext context) {     return const MaterialApp(home: HomePage());   } }  class HomePage extends StatefulWidget {   const HomePage({Key? key}) : super(key: key);    @override   State&lt;HomePage> createState() => _HomePageState(); }  class _HomePageState extends State&lt;HomePage> {   @override   Widget build(BuildContext context) {     return Scaffold(       appBar: AppBar(title: const Text(\"List Demo\")),       body: ListView.builder(         itemBuilder: (context, index) {           return ListTile(title: Text(\"Item $index\"));         },       ),     );   } } <\/code><\/pre>\n<p>\u0421\u043e\u0437\u0434\u0430\u043d\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0438\u043c\u0435\u0435\u0442 \u043b\u0438\u0448\u044c \u043e\u0434\u0438\u043d \u044d\u043a\u0440\u0430\u043d \u0441\u043e \u0441\u043f\u0438\u0441\u043a\u043e\u043c. \u0412\u0438\u0434\u0436\u0435\u0442 <em>HomePage<\/em>, \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0431\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u0431\u0430\u0437\u0435 <em>StatelessWidget<\/em>, \u043e\u0434\u043d\u0430\u043a\u043e \u0432 \u0431\u0443\u0434\u0443\u0449\u0435\u043c \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0438\u043c\u0435\u043d\u043d\u043e <em>StatefullWidget<\/em>, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043e\u0441\u0442\u0430\u0432\u0438\u043c \u043a\u0430\u043a \u0435\u0441\u0442\u044c.<\/p>\n<p><a class=\"anchor\" name=\"async\" id=\"async\"><\/a><\/p>\n<h2>\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445<\/h2>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/05b\/e52\/de3\/05be52de3e5a9d5665e91c3f732102ca.gif\" width=\"320\" height=\"569\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/05b\/e52\/de3\/05be52de3e5a9d5665e91c3f732102ca.gif\"\/><figcaption><\/figcaption><\/figure>\n<p><a href=\"https:\/\/github.com\/astoniocom\/fl_list_example\/tree\/async\" rel=\"noopener noreferrer nofollow\">\u041e\u0442\u043a\u0440\u044b\u0442\u044c \u043a\u043e\u0434 \u043d\u0430 GitHub<\/a><\/p>\n<p>\u0412 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u043d\u0435\u0447\u0430\u0441\u0442\u043e \u0438\u043c\u0435\u044e\u0442\u0441\u044f \u0434\u0430\u043d\u043d\u044b\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0436\u043d\u043e \u0441\u0440\u0430\u0437\u0443 \u043e\u0442\u043e\u0431\u0440\u0430\u0437\u0438\u0442\u044c \u0432 \u0441\u043f\u0438\u0441\u043a\u0435. \u041e\u0431\u044b\u0447\u043d\u043e \u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0443\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0438\u0437 \u043d\u0435\u043a\u043e\u0433\u043e \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430 \u0438 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u0442\u044c.  \u041e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u0441 \u044d\u0442\u0438\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0446\u0435\u043b\u0435\u0441\u043e\u043e\u0431\u0440\u0430\u0437\u043d\u043e \u0438\u043d\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0438 \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u044e\u0449\u0438\u0445 \u043e\u0448\u0438\u0431\u043a\u0430\u0445. \u0412 \u044d\u0442\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u043c\u044b \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0443\u0435\u043c \u044d\u0442\u0438 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u044b.<\/p>\n<h4>pubspec.yaml<\/h4>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u043f\u0430\u043a\u0435\u0442\u044b \u0432 \u0444\u0430\u0439\u043b <em>pubspec.yaml<\/em> \u0438 \u0432 \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u043c <em>flutter pub get<\/em>.<\/p>\n<pre><code class=\"yaml\">dependencies:   english_words: ^4.0.0 # 1   provider: ^6.0.0 # 2   ... <\/code><\/pre>\n<p>\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043a\u043e\u0434\u0430:<\/p>\n<ol>\n<li>\n<p>\u041f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u0430\u043d\u0433\u043b\u0438\u0439\u0441\u043a\u0438\u0445 \u0441\u043b\u043e\u0432 \u0434\u043b\u044f \u043d\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445, \u0441 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c.<\/p>\n<\/li>\n<li>\n<p>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0443 \u0441\u043f\u0438\u0441\u043a\u0430.<\/p>\n<\/li>\n<\/ol>\n<h4>models.dart<\/h4>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u043c \u043a\u043b\u0430\u0441\u0441 \u0434\u043b\u044f \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u0441\u043f\u0438\u0441\u043a\u0430. \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0444\u0430\u0439\u043b <em>models.dart<\/em> \u0441 \u0442\u0430\u043a\u0438\u043c \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u044b\u043c:<\/p>\n<pre><code class=\"dart\">\/* file: models.dart *\/  class ExampleRecord {   final String title;    const ExampleRecord({required this.title}); } <\/code><\/pre>\n<p>\u041f\u043e\u043a\u0430 \u0447\u0442\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u044d\u0442\u043e\u0442 \u043a\u043b\u0430\u0441\u0441\u0430 \u0431\u0443\u0434\u0443\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u043b\u043e\u0432\u043e \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0432 \u0441\u0442\u0440\u043e\u043a\u0430\u0445 \u0432\u0438\u0434\u0436\u0435\u0442\u0430 <em>ListView<\/em>.<\/p>\n<h4>repository.dart<\/h4>\n<p>\u0412\u0441\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u043d\u0430\u0434 \u0437\u0430\u043f\u0438\u0441\u044f\u043c\u0438 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0431\u0443\u0434\u0443\u0442 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u0447\u0435\u0440\u0435\u0437 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439. \u0415\u0433\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0440\u0430\u0437\u043c\u0435\u0441\u0442\u0438\u043c \u0432 \u0444\u0430\u0439\u043b\u0435 <em>repository.dart<\/em>.<\/p>\n<pre><code class=\"dart\">\/* file: repository.dart *\/  import 'dart:math'; import 'package:english_words\/english_words.dart'; import 'package:fl_list_example\/models.dart';  const kRecordsToGenerate = 100;  class MockRepository {   \/\/ 1   final List&lt;ExampleRecord> _store = List&lt;ExampleRecord>.generate(             kRecordsToGenerate,             (i) => ExampleRecord(                 title: nouns[Random().nextInt(nouns.length)],               ));    \/\/ 2   static final MockRepository _instance = MockRepository._internal();   factory MockRepository() => _instance;   MockRepository._internal() : super();    \/\/ 3   Future&lt;List&lt;ExampleRecord>> queryRecords() async {     await Future.delayed(const Duration(seconds: 2)); \/\/ 4     return _store;   } } <\/code><\/pre>\n<p>\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043a\u043e\u0434\u0430:<\/p>\n<ol>\n<li>\n<p>\u041f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f \u0437\u0430\u043f\u043e\u043b\u043d\u0438\u043c private-\u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e <em>_store<\/em> (\u0443\u0441\u043b\u043e\u0432\u043d\u0443\u044e \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445) \u0437\u0430\u043f\u0438\u0441\u044f\u043c\u0438 \u0441\u043e \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u044b\u043c\u0438 \u0441\u043b\u043e\u0432\u0430\u043c\u0438.<\/p>\n<\/li>\n<li>\n<p>\u0427\u0442\u043e\u0431\u044b \u0432\u0441\u0435\u0433\u0434\u0430 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u043e\u0434\u043d\u0438\u043c \u0438 \u0442\u0435\u043c \u0436\u0435 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u043c \u0434\u0430\u043d\u043d\u044b\u0445, \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u043a\u043b\u0430\u0441\u0441 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f \u0431\u044b\u043b \u0441\u0438\u043d\u0433\u043b\u0442\u043e\u043d\u043e\u043c, \u0442\u043e \u0435\u0441\u0442\u044c \u043c\u043e\u0433 \u0438\u043c\u0435\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u0438\u043d \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440.<\/p>\n<\/li>\n<li>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f, \u043a \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0431\u0443\u0434\u0435\u043c \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u0438\u0437 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445. \u0412 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0432 \u043a\u043e\u0434\u0435 \u044d\u0442\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0434\u043e\u043b\u0436\u043d\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u044c \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0435 \u043a \u00ab\u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0435\u0439\u00bb \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u043b\u0438 http-\u0437\u0430\u043f\u0440\u043e\u0441.<\/p>\n<\/li>\n<li>\n<p>\u0421\u0442\u0440\u043e\u043a\u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u043c\u0438\u0442\u0430\u0446\u0438\u044e \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0438 \u043f\u0440\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<\/li>\n<\/ol>\n<h4>list_state.dart<\/h4>\n<p>\u0414\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043a\u043b\u0430\u0441\u0441\u0430, \u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e \u0437\u0430 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u0430, \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0444\u0430\u0439\u043b <em>list_state.dart<\/em> \u0441\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u044b\u043c:<\/p>\n<pre><code class=\"dart\">\/* file: list_state.dart *\/  import 'package:fl_list_example\/models.dart';  class ListState {   ListState({     List&lt;ExampleRecord>? records,     this.isLoading = false,     this.error = '', \/\/ 1   }) : recordsStore = records; \/\/ 2    final List&lt;ExampleRecord>? recordsStore; \/\/ 3    bool get isInitialized => recordsStore != null; \/\/ 3    List&lt;ExampleRecord> get records => recordsStore ?? List&lt;ExampleRecord>.empty(); \/\/ 4    final String error;    bool get hasError => error.isNotEmpty; \/\/ 5    final bool isLoading; \/\/ 6      \/\/ 7   ListState copyWith({     List&lt;ExampleRecord>? records,     bool? isLoading,     String? error,   }) {     return ListState(       records: records ?? recordsStore,       isLoading: isLoading ?? this.isLoading,       error: error ?? this.error,     );   } }  <\/code><\/pre>\n<p>\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043a\u043e\u0434\u0430:<\/p>\n<ol>\n<li>\n<p>\u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u043e\u0432\u0435\u043d\u0438\u044f \u043e\u0448\u0438\u0431\u043a\u0438 \u043f\u0440\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u0437 <em>MockRepository<\/em>, \u0432 \u044d\u0442\u0443 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u0434\u043b\u044f \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u0433\u043e \u0435\u0451 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f. \u042d\u0442\u0430 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c <em>null<\/em> \u0438 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0445\u0440\u0430\u043d\u0438\u0442 \u043f\u0443\u0441\u0442\u0443\u044e \u0441\u0442\u0440\u043e\u043a\u0443. \u0422\u0430\u043a\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u043d\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u043e\u0433\u043e \u0442\u043e\u043b\u043a\u043e\u0432\u0430\u043d\u0438\u044f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u044d\u0442\u043e\u0439 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439. \u041f\u043e\u044f\u0441\u043d\u044e. \u0415\u0441\u043b\u0438 \u0431\u044b \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u0431\u044b\u043b\u0430 <em>null<\/em> \u2014 \u044d\u0442\u043e \u0431\u044b, \u0441\u043a\u043e\u0440\u0435\u0435 \u0432\u0441\u0435\u0433\u043e, \u043e\u0437\u043d\u0430\u0447\u0430\u043b\u043e \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435 \u043e\u0448\u0438\u0431\u043a\u0438. \u041d\u043e \u0435\u0441\u043b\u0438 \u0431\u044b \u044d\u0442\u0430 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u0445\u0440\u0430\u043d\u0438\u043b\u0430 \u043f\u0443\u0441\u0442\u0443\u044e \u0441\u0442\u0440\u043e\u043a\u0443 \u0438, \u0432 \u0442\u043e \u0436\u0435 \u0432\u0440\u0435\u043c\u044f, \u0438\u043c\u0435\u043b\u0430 \u0431\u044b \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0438\u043c\u0435\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 <em>null<\/em>, \u0442\u043e \u0438\u043d\u0442\u0435\u0440\u043f\u0440\u0435\u0442\u0430\u0446\u0438\u044f \u0442\u0430\u043a\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0431\u044b\u043b\u0430 \u0431\u044b \u043d\u0435 \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0421\u0442\u0440\u043e\u043a\u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0430 \u043b\u0438\u0448\u044c \u0434\u043b\u044f \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u043d\u044f\u0442\u043d\u043e\u0433\u043e \u0438 \u044d\u0441\u0442\u0435\u0442\u0438\u0447\u043d\u043e\u0433\u043e \u043d\u0430\u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0430 \u043a\u043b\u0430\u0441\u0441\u0430.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f <em>recordsStore<\/em> \u0445\u0440\u0430\u043d\u0438\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043d\u0430 \u044d\u043a\u0440\u0430\u043d\u0435. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f <em>null<\/em> \u0441\u0434\u0435\u043b\u0430\u043d\u043e \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0440\u0430\u0437\u043b\u0438\u0447\u0430\u0442\u044c \u043f\u0440\u0438\u0447\u0438\u043d\u044b, \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u0441\u043f\u0438\u0441\u043e\u043a \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u043f\u0443\u0441\u0442. \u0415\u0441\u043b\u0438 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u0438\u043c\u0435\u0435\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 <em>null<\/em>, \u0437\u043d\u0430\u0447\u0438\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u043f\u0443\u0441\u0442, \u0442\u0430\u043a \u043a\u0430\u043a \u0435\u0449\u0451 \u043d\u0435 \u0431\u044b\u043b\u043e \u0443\u0441\u043f\u0435\u0448\u043d\u044b\u0445 \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0439 \u043a <em>MockRepository<\/em> \u043d\u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0437\u0430\u043f\u0438\u0441\u0435\u0439. \u0415\u0441\u043b\u0438 \u0436\u0435 \u0432 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 \u0441\u043e\u0445\u0440\u0430\u043d\u0451\u043d \u043f\u0443\u0441\u0442\u043e\u0439 \u0441\u043f\u0438\u0441\u043e\u043a, \u0437\u043d\u0430\u0447\u0438\u0442 \u0442\u0430\u043a\u043e\u0435 \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0435 \u0431\u044b\u043b\u043e, \u043e\u0434\u043d\u0430\u043a\u043e <em>MockRepository<\/em> \u043d\u0435 \u0432\u0435\u0440\u043d\u0443\u043b \u043d\u0438 \u043e\u0434\u043d\u043e\u0439 \u0437\u0430\u043f\u0438\u0441\u0438. \u0414\u043b\u044f \u0431\u043e\u043b\u0435\u0435 \u0443\u0434\u043e\u0431\u043d\u043e\u0433\u043e \u0440\u0430\u0437\u043b\u0438\u0447\u0438\u044f \u044d\u0442\u0438\u0445 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f <em>isInitialized<\/em>.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 <em>records<\/em> \u0432\u0441\u0435\u0433\u0434\u0430 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0441\u043f\u0438\u0441\u043e\u043a, \u0432\u043d\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0442\u043e\u0433\u043e, \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u043e \u043b\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 <em>null<\/em> \u0432 <em>recordsStore<\/em>. \u042d\u0442\u043e\u0442 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0443\u0434\u043e\u0431\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c, \u0447\u0442\u043e\u0431\u044b \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f <em>recordsStore<\/em> \u043d\u0430 <em>null<\/em>, \u043f\u0440\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0438 \u0441\u043f\u0438\u0441\u043a\u0430 \u0437\u0430\u043f\u0438\u0441\u0435\u0439.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 <em>hasError<\/em> \u0443\u0434\u043e\u0431\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c, \u043a\u043e\u0433\u0434\u0430 \u043d\u0430\u0434\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c, \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430 \u043b\u0438 \u043e\u0448\u0438\u0431\u043a\u0430 \u0432 \u0445\u043e\u0434\u0435 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u0438\u0437 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f. \u0414\u043b\u044f \u044d\u0442\u0438\u0445 \u0446\u0435\u043b\u0435\u0439 \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0431\u044b \u0430\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e <em>error<\/em>, \u043e\u0434\u043d\u0430\u043a\u043e \u0432 \u0445\u043e\u0434\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0441\u043f\u043e\u0441\u043e\u0431 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u043e\u0448\u0438\u0431\u043a\u0438 \u0432 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438 \u0441\u043f\u0438\u0441\u043a\u0430 \u043c\u043e\u0436\u0435\u0442 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c\u0441\u044f \u0438 \u0442\u043e\u0433\u0434\u0430 \u043f\u0440\u0438\u0434\u0451\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u043a\u043e\u0434\u0430. \u0414\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u044d\u0442\u043e\u0433\u043e \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430 \u0442\u0430\u043a\u0436\u0435 \u043f\u0440\u0438\u0432\u0435\u0434\u0451\u0442 \u043a \u0431\u043e\u043b\u0435\u0435 \u043a\u0440\u0430\u0442\u043a\u043e\u043c\u0443 \u0438 \u043f\u043e\u043d\u044f\u0442\u043d\u043e\u043c\u0443 \u043a\u043e\u0434\u0443.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 <em>isLoading<\/em> \u0441\u0438\u0433\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u0442 \u043e \u0442\u043e\u043c, \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043b\u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0441\u043f\u0438\u0441\u043a\u0430 \u0432 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442. \u042d\u0442\u043e\u0442 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0438\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440\u0430 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0441\u043f\u0438\u0441\u043a\u0430, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0441\u043f\u0438\u0441\u043a\u0430 \u0438\u0437 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0437.<\/p>\n<\/li>\n<li>\n<p>\u0422\u0430\u043a \u043a\u0430\u043a \u043e\u0431\u044a\u0435\u043a\u0442 \u043a\u043b\u0430\u0441\u0441\u0430 <em>ListState<\/em> \u043d\u0435\u0438\u0437\u043c\u0435\u043d\u044f\u0435\u043c\u044b\u0439, \u0444\u0443\u043d\u043a\u0446\u0438\u044f copyWith \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u044d\u0442\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0441 \u043d\u0443\u0436\u043d\u044b\u043c\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f\u043c\u0438.<\/p>\n<\/li>\n<\/ol>\n<h4>list_controller.dart<\/h4>\n<p>\u041d\u0430 \u0431\u0430\u0437\u0435 <em>ValueNotifier<\/em> \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u043e\u043c. \u041e\u043d \u0431\u0443\u0434\u0435\u0442 \u0438\u0437\u043c\u0435\u043d\u044f\u0442\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0441\u043f\u0438\u0441\u043a\u0430 <em>ListState<\/em>, \u0441\u043e\u0445\u0440\u0430\u043d\u0451\u043d\u043d\u043e\u0435 \u0432 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 <em>value<\/em>. \u0412\u043c\u0435\u0441\u0442\u043e <em>ValueNotifier<\/em> \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438 \u043b\u044e\u0431\u043e\u0439 \u0434\u0440\u0443\u0433\u043e\u0439 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, Bloc.<\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0444\u0430\u0439\u043b <em>list_controller.dart<\/em> \u0441 \u0442\u0430\u043a\u0438\u043c \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u044b\u043c:<\/p>\n<pre><code class=\"dart\">\/* file: list_controller.dart *\/  import 'package:fl_list_example\/list_state.dart'; import 'package:fl_list_example\/models.dart'; import 'package:fl_list_example\/repository.dart'; import 'package:flutter\/foundation.dart';  class ListController extends ValueNotifier&lt;ListState> {   ListController() : super(ListState()) { \/\/ 1     loadRecords(); \/\/ 2   }    \/\/ 3   Future&lt;List&lt;ExampleRecord>> fetchRecords() async {     final loadedRecords = await MockRepository().queryRecords();     return loadedRecords;   }    \/\/ 4   Future&lt;void> loadRecords() async {     if (value.isLoading) return; \/\/ 5      value = value.copyWith(isLoading: true, error: \"\"); \/\/ 6      try {       final fetchResult = await fetchRecords();        value = value.copyWith(isLoading: false, records: fetchResult); \/\/ 7     } catch (e) {       value = value.copyWith(isLoading: false, error: e.toString()); \/\/ 8       rethrow;     }   }    \/\/ 9   repeatQuery() {     return loadRecords();   } } <\/code><\/pre>\n<p>\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043a\u043e\u0434\u0430:<\/p>\n<ol>\n<li>\n<p>\u0412\u044b\u0437\u043e\u0432 <em>super<\/em> \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0441\u043f\u0438\u0441\u043a\u0430.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430 \u0438\u043d\u0438\u0446\u0438\u0438\u0440\u0443\u0435\u043c \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0433\u043e \u0441\u043f\u0438\u0441\u043a\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u0441\u043f\u0438\u0441\u043e\u043a. \u041d\u0435 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u0438\u0437 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f, \u0442\u0430\u043a \u043a\u0430\u043a \u043a\u0440\u043e\u043c\u0435 \u0441\u0430\u043c\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u043d\u043e\u0433\u0434\u0430 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0442\u044c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0445\u0430\u0440\u0430\u043a\u0442\u0435\u0440\u0438\u0441\u0442\u0438\u043a\u0438 \u044d\u0442\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043b\u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u044b\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u0435\u043c \u0441\u043f\u0438\u0441\u043a\u0430 (\u0432 \u0441\u043b\u0443\u0447\u0430\u0435, \u0435\u0441\u043b\u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0441\u043f\u0438\u0441\u043e\u043a \u0447\u0430\u0441\u0442\u044f\u043c\u0438).<\/p>\n<\/li>\n<li>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f, \u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u0430\u044f \u0437\u0430 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0443 \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u0441\u043f\u0438\u0441\u043a\u0430 \u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u0430 \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438.<\/p>\n<\/li>\n<li>\n<p>\u0418\u0433\u043d\u043e\u0440\u0438\u0440\u0443\u0435\u043c \u043d\u043e\u0432\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043d\u0430 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0443 \u0441\u043f\u0438\u0441\u043a\u0430, \u043f\u043e\u043a\u0430 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0451\u043d.<\/p>\n<\/li>\n<li>\n<p>\u0412 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438 \u0441\u043f\u0438\u0441\u043a\u0430 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c, \u0447\u0442\u043e \u0441\u043f\u0438\u0441\u043e\u043a \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438. \u0421\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u0435\u043c \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043e\u0448\u0438\u0431\u043a\u0438, \u0435\u0441\u043b\u0438 \u0442\u0430\u043a\u0430\u044f \u0438\u043c\u0435\u043b\u0430\u0441\u044c \u043f\u043e\u0441\u043b\u0435 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0439 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438.<\/p>\n<\/li>\n<li>\n<p>\u0415\u0441\u043b\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u043f\u0440\u043e\u0448\u043b\u043e \u0443\u0441\u043f\u0435\u0448\u043d\u043e, \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0438\u0445 \u0432 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0441\u043f\u0438\u0441\u043a\u0430. \u0422\u0430\u043a\u0436\u0435 \u0432 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438 \u0441\u043f\u0438\u0441\u043a\u0430 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c, \u0447\u0442\u043e \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0441\u043f\u0438\u0441\u043a\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0415\u0441\u043b\u0438 \u0447\u0442\u043e-\u0442\u043e \u043f\u043e\u0448\u043b\u043e \u043d\u0435 \u0442\u0430\u043a, \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0432 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0441\u043f\u0438\u0441\u043a\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0435.<\/p>\n<\/li>\n<li>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u0439 \u043f\u043e\u043f\u044b\u0442\u043a\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u0430 \u0437\u0430\u043f\u0438\u0441\u0435\u0439, \u0435\u0441\u043b\u0438 \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0439 \u043f\u043e\u043f\u044b\u0442\u043a\u0438 \u0432\u043e\u0437\u043d\u0438\u043a\u043b\u0430 \u043e\u0448\u0438\u0431\u043a\u0430. \u041d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e <em>loadRecords<\/em>, \u0442\u0430\u043a \u043a\u0430\u043a \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u0447\u0430\u0441\u0442\u044f\u0445 \u0441\u0442\u0430\u0442\u044c\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u044f <em>repeatQuery<\/em> \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c\u0441\u044f.<\/p>\n<\/li>\n<\/ol>\n<h4>widgets\/list_status_indicator.dart<\/h4>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0432\u0438\u0434\u0436\u0435\u0442 \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u0430 <em>ListState<\/em>. \u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u044d\u0442\u043e\u0442 \u0432\u0438\u0434\u0436\u0435\u0442 \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c \u043d\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044e <em>onRepeat<\/em>. \u0415\u0441\u043b\u0438 \u044d\u0442\u043e\u0442 \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d, \u0442\u043e \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0441\u043f\u0438\u0441\u043a\u0430, \u0432\u0438\u0434\u0436\u0435\u0442 \u043e\u0442\u043e\u0431\u0440\u0430\u0437\u0438\u0442 \u043a\u043d\u043e\u043f\u043a\u0443 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u0439 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438.<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/781\/db1\/dcf\/781db1dcfa220eb1d5474d61494c114d.png\" width=\"400\" height=\"327\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/781\/db1\/dcf\/781db1dcfa220eb1d5474d61494c114d.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0444\u0430\u0439\u043b <em>widgets\/list_status_indicator.dart<\/em> \u0441 \u0442\u0430\u043a\u0438\u043c \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u044b\u043c:<\/p>\n<pre><code class=\"dart\">\/* file: widgets\/list_status_indicator.dart *\/  import 'package:fl_list_example\/list_state.dart'; import 'package:flutter\/material.dart';  class ListStatusIndicator extends StatelessWidget {   final ListState listState;   final Function()? onRepeat;    const ListStatusIndicator(this.listState, {this.onRepeat, Key? key}) : super(key: key);    static bool hasStatus(ListState listState) => listState.hasError || listState.isLoading || (listState.isInitialized &amp;&amp; listState.records.isEmpty); \/\/ 1    @override   Widget build(BuildContext context) {     Widget? stateIndicator;     if (listState.hasError) {       stateIndicator = const Text(\"Loading Error\", textAlign: TextAlign.center);       if (onRepeat != null) {         stateIndicator = Row(           mainAxisSize: MainAxisSize.min,           children: [stateIndicator, const SizedBox(width: 8), IconButton(onPressed: onRepeat, icon: const Icon(Icons.refresh))],         );       }     } else if (listState.isLoading) {       stateIndicator = const CircularProgressIndicator();     } else if (listState.isInitialized &amp;&amp; listState.records.isEmpty) {       stateIndicator = const Text(\"No results\", textAlign: TextAlign.center);     }      if (stateIndicator == null) return Container();      return Container(alignment: Alignment.center, child: stateIndicator);   } } <\/code><\/pre>\n<p>\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043a\u043e\u0434\u0430:<\/p>\n<ol>\n<li>\n<p>\u0422\u0430\u043a \u043a\u0430\u043a \u044d\u0442\u043e\u0442 \u0432\u0438\u0434\u0436\u0435\u0442 \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c\u0441\u044f \u0432 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0435 \u0441\u043f\u0438\u0441\u043a\u0430 <em>ListView<\/em>, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0442\u044c, \u0435\u0441\u0442\u044c \u043b\u0438 \u0432 \u043d\u0435\u0439 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u0438 \u0431\u0443\u0434\u0435\u0442 \u043b\u0438 \u0434\u0430\u043d\u043d\u044b\u0439 \u0432\u0438\u0434\u0436\u0435\u0442 \u0447\u0442\u043e-\u0442\u043e \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c. \u042d\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <em>hasStatus<\/em>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0441\u043e\u043e\u0431\u0449\u0430\u0435\u0442 \u043e \u0446\u0435\u043b\u0435\u0441\u043e\u043e\u0431\u0440\u0430\u0437\u043d\u043e\u0441\u0442\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u044d\u0442\u043e\u0433\u043e \u0432\u0438\u0434\u0436\u0435\u0442\u0430.<\/p>\n<\/li>\n<\/ol>\n<h4>main.dart<\/h4>\n<p>\u0412\u043d\u0435\u0441\u0451\u043c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u0444\u0430\u0439\u043b <em>main.dart<\/em>. \u0422\u0430\u043a \u043a\u0430\u043a \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u043c\u043d\u043e\u0433\u043e, \u043f\u0440\u0438\u0432\u043e\u0436\u0443 \u0435\u0433\u043e \u043f\u043e\u043b\u043d\u043e\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435:<\/p>\n<pre><code class=\"dart\">\/* file: main.dart *\/  import 'package:fl_list_example\/list_controller.dart'; \/\/ + import 'package:fl_list_example\/widgets\/list_status_indicator.dart'; \/\/ + import 'package:flutter\/material.dart'; import 'package:provider\/provider.dart'; \/\/ +  void main() {   runApp(const MyApp()); }  class MyApp extends StatelessWidget {   const MyApp({Key? key}) : super(key: key);    @override   Widget build(BuildContext context) {     return MaterialApp( \/\/ +       home: ChangeNotifierProvider( \/\/ + 1         create: (_) => ListController(), \/\/ +         child: const HomePage(), \/\/ +       ), \/\/+     ); \/\/ +   } }  class HomePage extends StatefulWidget {   const HomePage({Key? key}) : super(key: key);    @override   State&lt;HomePage> createState() => _HomePageState(); }  class _HomePageState extends State&lt;HomePage> {   @override   Widget build(BuildContext context) {     final listController = context.watch&lt;ListController>(); \/\/ + 2     final listState = listController.value; \/\/ + 3     final itemCount = listState.records.length + (ListStatusIndicator.hasStatus(listState) ? 1 : 0); \/\/ + 4     return Scaffold(       appBar: AppBar(title: const Text(\"List Demo\")),       body: ListView.builder( \/\/ +         itemBuilder: (context, index) {           if (index == listState.records.length &amp;&amp; ListStatusIndicator.hasStatus(listState)) { \/\/ + 5             return ListStatusIndicator(listState, onRepeat: listController.repeatQuery); \/\/ + 6           } \/\/ +            final record = listState.records[index]; \/\/ + 7           return ListTile(title: Text(record.title)); \/\/ +         }, \/\/ +         itemCount: itemCount,       ),     );   } }  <\/code><\/pre>\n<p>\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043a\u043e\u0434\u0430:<\/p>\n<ol>\n<li>\n<p>\u0412\u0438\u0434\u0436\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u043a\u043b\u0430\u0441\u0441\u0430 <em>ListController<\/em> \u0438 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043d\u0435\u043c\u0443 \u0432 \u0434\u0440\u0443\u0433\u0438\u0445 \u0432\u0438\u0434\u0436\u0435\u0442\u0430\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u043d\u0438\u0436\u0435 \u043f\u043e \u0438\u0435\u0440\u0430\u0440\u0445\u0438\u0438.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u0431\u043b\u044e\u0434\u0430\u0435\u043c \u0437\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430 <em>ListController<\/em>. \u0415\u0441\u043b\u0438 \u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0438\u0437\u043c\u0435\u043d\u0438\u043b\u043e\u0441\u044c (\u0431\u044b\u043b\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043e \u043d\u043e\u0432\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 <em>value<\/em> \u0438, \u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e, \u0432\u044b\u0437\u0432\u0430\u043d\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044f <em>notifyListeners()<\/em>), \u0442\u043e \u043f\u0440\u043e\u0438\u0437\u043e\u0439\u0434\u0451\u0442 \u043d\u043e\u0432\u044b\u0439 \u0432\u044b\u0437\u043e\u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <em>build<\/em>. \u0427\u0435\u0440\u0435\u0437 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e <em>listController<\/em> \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u044d\u0442\u043e\u043c\u0443 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0443.<\/p>\n<\/li>\n<li>\n<p>\u0412 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e <em>listState<\/em> \u043f\u043e\u043c\u0435\u0449\u0430\u0435\u043c \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430 \u0434\u043b\u044f \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0431\u043e\u043b\u0435\u0435 \u0447\u0438\u0442\u0430\u0435\u043c\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u0434\u0430\u043b\u0435\u0435.<\/p>\n<\/li>\n<li>\n<p>\u0412\u0438\u0434\u0436\u0435\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u0430 <em>ListStatusIndicator<\/em> \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u0442\u0441\u044f \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u043e\u0439 \u0432 \u0432\u0438\u0434\u0436\u0435\u0442\u0435 \u0441\u043f\u0438\u0441\u043a\u0430 <em>ListView<\/em>. \u041e\u0434\u043d\u0430\u043a\u043e \u043d\u0435\u0442 \u0441\u043c\u044b\u0441\u043b\u0430 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0441\u043f\u0438\u0441\u043a\u0430 \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e. \u0412 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f <em>hasStatus<\/em> \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c, \u043d\u0443\u0436\u043d\u043e \u043b\u0438 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c \u0432\u0438\u0434\u0436\u0435\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0441\u043f\u0438\u0441\u043a\u0430 \u0438, \u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e, \u043d\u0443\u0436\u043d\u043e \u043b\u0438 \u0440\u0435\u0437\u0435\u0440\u0432\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u043d\u0435\u0433\u043e \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u0443\u044e \u0441\u0442\u0440\u043e\u043a\u0443. \u041a\u043e\u043d\u0435\u0447\u043d\u043e, \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0431\u044b \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c \u0432\u0438\u0434\u0436\u0435\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0438 \u043f\u043e\u0432\u0435\u0440\u0445 \u0432\u0438\u0434\u0436\u0435\u0442\u0430 <em>ListView<\/em>, \u043d\u043e \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u0431\u043e\u043b\u0435\u0435 \u0443\u0434\u043e\u0431\u0435\u043d, \u043a\u043e\u0433\u0434\u0430 \u043c\u044b \u0447\u0443\u0442\u044c \u043f\u043e\u0437\u0436\u0435 \u0431\u0443\u0434\u0435\u043c \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u0442\u044c \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0443 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441\u043f\u0438\u0441\u043a\u0430 \u0447\u0430\u0441\u0442\u044f\u043c\u0438.<\/p>\n<\/li>\n<li>\n<p>\u0415\u0441\u043b\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e, \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u043c \u0432\u0438\u0434\u0436\u0435\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u0430 \u0432 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0439 \u0441\u0442\u0440\u043e\u043a\u0435 \u0432\u0438\u0434\u0436\u0435\u0442\u0430 <em>ListView<\/em>.<\/p>\n<\/li>\n<li>\n<p>\u0415\u0441\u043b\u0438 \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0441\u043f\u0438\u0441\u043a\u0430 \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430 \u043e\u0448\u0438\u0431\u043a\u0430, \u043e\u0442\u043e\u0431\u0440\u0430\u0437\u0438\u0442\u0441\u044f \u0432\u0438\u0434\u0436\u0435\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u0430 \u0441 \u043a\u043d\u043e\u043f\u043a\u043e\u0439 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f. \u041f\u043e\u0441\u043b\u0435 \u043d\u0430\u0436\u0430\u0442\u0438\u044f \u043d\u0430 \u044d\u0442\u0443 \u043a\u043d\u043e\u043f\u043a\u0443 \u0432\u044b\u0437\u043e\u0432\u0435\u0442\u0441\u044f \u043c\u0435\u0442\u043e\u0434 <em>repeatQuery<\/em> \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0432\u0442\u043e\u0440\u0438\u0442 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u0437\u0430\u043f\u0440\u043e\u0441.<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0439 \u0441\u0442\u0440\u043e\u043a\u0438 \u0441\u043f\u0438\u0441\u043a\u0430, \u0438 \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u044d\u0442\u0443 \u0441\u0442\u0440\u043e\u043a\u0443.<\/p>\n<\/li>\n<\/ol>\n<p><a class=\"anchor\" name=\"filters\" id=\"filters\"><\/a><\/p>\n<h2>\u0424\u0438\u043b\u044c\u0442\u0440 \u0438 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0430<\/h2>\n<figure class=\"bordered\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/3ac\/fa9\/1ba\/3acfa91bac206acd35147c661deeabd7.png\" alt=\"\" title=\"\" width=\"320\" height=\"569\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/3ac\/fa9\/1ba\/3acfa91bac206acd35147c661deeabd7.png\"\/><figcaption><\/figcaption><\/figure>\n<p><a href=\"https:\/\/github.com\/astoniocom\/fl_list_example\/tree\/filter\" rel=\"noopener noreferrer nofollow\">\u041e\u0442\u043a\u0440\u044b\u0442\u044c \u043a\u043e\u0434 \u043d\u0430 GitHub<\/a><\/p>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u0438 \u0438 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u0441\u043f\u0438\u0441\u043a\u0435. \u0424\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u044e \u0431\u0443\u0434\u0435\u043c \u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0438 \u043d\u0430\u043b\u0438\u0447\u0438\u044f \u043f\u043e\u0434\u0441\u0442\u0440\u043e\u043a\u0438 \u043f\u043e\u0438\u0441\u043a\u0430 \u0432 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0435 \u0437\u0430\u043f\u0438\u0441\u0438, \u0430 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0443 \u2014 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0432\u0435\u0441\u0430 \u0437\u0430\u043f\u0438\u0441\u0438.<\/p>\n<h4>models.dart<\/h4>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0432 \u043c\u043e\u0434\u0435\u043b\u044c \u0437\u0430\u043f\u0438\u0441\u0438 \u0441\u043f\u0438\u0441\u043a\u0430 <em>ExampleRecord<\/em> \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e <em>weight<\/em>. \u042d\u0442\u0430 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0430\u0442\u044c \u043f\u043e\u0440\u044f\u0434\u043e\u043a \u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u044f \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u0441\u043f\u0438\u0441\u043a\u0430.<\/p>\n<p>\u0422\u0430\u043a\u0436\u0435 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043a\u043b\u0430\u0441\u0441 <em>ExampleRecordQuery<\/em>, \u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0437\u0430 \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u044e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0441\u043f\u0438\u0441\u043a\u0430 \u043f\u043e \u043f\u043e\u0434\u0441\u0442\u0440\u043e\u043a\u0435 \u0432 <em>title<\/em> \u0438 \u0435\u0433\u043e \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0443 \u043f\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044e \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 <em>weight<\/em>.<\/p>\n<pre><code class=\"dart\">\/* file: models.dart *\/  class ExampleRecord {   final String title;   final int weight; \/\/ +    const ExampleRecord({     required this.title,     required this.weight, \/\/ +   }); }  class ExampleRecordQuery {   final String? contains; \/\/ 1    const ExampleRecordQuery({     this.contains,   });    \/\/ 2   bool suits(ExampleRecord obj) {     if (contains != null &amp;&amp; contains!.isNotEmpty &amp;&amp; !obj.title.contains(contains!)) return false;     return true;   }    \/\/ 3   int compareRecords(ExampleRecord record1, ExampleRecord record2) {     return record1.weight.compareTo(record2.weight);   } }  <\/code><\/pre>\n<p>\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043a\u043e\u0434\u0430:<\/p>\n<ol>\n<li>\n<p>\u041f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0441\u0442\u0440\u043e\u043a\u0438 \u043f\u043e\u0438\u0441\u043a\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u044f \u043e\u0431\u044a\u0435\u043a\u0442\u0430 obj \u0443\u0441\u043b\u043e\u0432\u0438\u044f\u043c\u0438 \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u0438.<\/p>\n<\/li>\n<li>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f \u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043f\u043e\u0440\u044f\u0434\u043a\u0430 \u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u044f \u0437\u0430\u043f\u0438\u0441\u0435\u0439 <em>record1<\/em> \u0438 <em>record2<\/em>.<\/p>\n<\/li>\n<\/ol>\n<h4>repository.dart<\/h4>\n<p>\u0412 \u043a\u043b\u0430\u0441\u0441 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f <em>MockRepository<\/em> \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u0438 \u0438 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438 \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u0438\u0437 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<pre><code class=\"dart\">\/* file: repository.dart *\/  import 'dart:math'; import 'package:english_words\/english_words.dart'; import 'package:fl_list_example\/models.dart';  const kRecordsToGenerate = 100;  class MockRepository {   final List&lt;ExampleRecord> _store = List&lt;ExampleRecord>.generate(       kRecordsToGenerate,       (i) => ExampleRecord(             weight: i * 10, \/\/ + 1             title: nouns[Random().nextInt(nouns.length)],           ))     ..shuffle(); \/\/ + 2    static final MockRepository _instance = MockRepository._internal();   factory MockRepository() => _instance;   MockRepository._internal() : super();    Future&lt;List&lt;ExampleRecord>> queryRecords(ExampleRecordQuery? query) async { \/\/ *     await Future.delayed(const Duration(seconds: 2));       final sortedList = List.of(_store); \/\/ + 3     if (query != null) sortedList.sort(query.compareRecords);  \/\/ + 4      return sortedList.where((record) => query == null || query.suits(record)).toList();  \/\/ * 5   } } <\/code><\/pre>\n<p>\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043a\u043e\u0434\u0430:<\/p>\n<ol>\n<li>\n<p>\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c \u0432\u0435\u0441 \u0437\u0430\u043f\u0438\u0441\u0438, \u043a\u0440\u0430\u0442\u043d\u044b\u0439 10, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u0437\u0430\u043f\u0438\u0441\u0435\u0439, \u0431\u044b\u043b\u0430 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0438\u0445 \u0432\u0441\u0442\u0430\u0432\u043a\u0438 \u043c\u0435\u0436\u0434\u0443 \u0434\u0440\u0443\u0433\u0438\u043c\u0438 \u0437\u0430\u043f\u0438\u0441\u044f\u043c\u0438.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0435\u0440\u0435\u043c\u0435\u0448\u0430\u0435\u043c \u0441\u043f\u0438\u0441\u043e\u043a, \u0447\u0442\u043e\u0431\u044b \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f \u0432 \u0440\u0430\u0431\u043e\u0442\u043e\u0441\u043f\u043e\u0441\u043e\u0431\u043d\u043e\u0441\u0442\u0438 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438.<\/p>\n<\/li>\n<li>\n<p>\u0427\u0442\u043e\u0431\u044b \u043d\u0435 \u043c\u043e\u0434\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0431\u0430\u0437\u0443 \u0437\u0430\u043f\u0438\u0441\u0435\u0439, \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0435\u0451 \u043a\u043e\u043f\u0438\u044e.<\/p>\n<\/li>\n<li>\n<p>\u0415\u0441\u043b\u0438 \u0435\u0441\u0442\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c, \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0443 \u0441\u043f\u0438\u0441\u043a\u0430. \u0412 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0432\u043c\u0435\u0441\u0442\u043e \u0432\u044b\u0437\u043e\u0432\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <em>sortedList.sort<\/em> \u0434\u043e\u043b\u0436\u043d\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u044c \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 <em>ExampleRecordQuery<\/em> \u0432 \u0444\u043e\u0440\u043c\u0430\u0442, \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u043c\u044b\u0439 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u043c \u0434\u0430\u043d\u043d\u044b\u0445, \u0431\u0443\u0434\u044c \u0442\u043e SQL ORDER BY \u0438\u043b\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 GET-\u0437\u0430\u043f\u0440\u043e\u0441\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0415\u0441\u043b\u0438 \u0435\u0441\u0442\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c, \u0444\u0438\u043b\u044c\u0442\u0440\u0443\u0435\u043c \u0441\u043f\u0438\u0441\u043e\u043a, \u0447\u0442\u043e\u0431\u044b \u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u0435 \u0437\u0430\u043f\u0438\u0441\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0443\u0434\u043e\u0432\u043b\u0435\u0442\u0432\u043e\u0440\u044f\u044e\u0442 \u0437\u0430\u043f\u0440\u043e\u0441\u0443. \u0412 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0432\u043c\u0435\u0441\u0442\u043e \u0432\u044b\u0437\u043e\u0432\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <em>query.suits<\/em>  \u0434\u043e\u043b\u0436\u043d\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u044c \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 <em>ExampleRecordQuery<\/em> \u0432 \u0444\u043e\u0440\u043c\u0430\u0442, \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u043c\u044b\u0439 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u043c \u0434\u0430\u043d\u043d\u044b\u0445, \u0431\u0443\u0434\u044c \u0442\u043e SQL WHERE-\u0443\u0441\u043b\u043e\u0432\u0438\u0435 \u0438\u043b\u0438 HTTP GET-\u0437\u0430\u043f\u0440\u043e\u0441.<\/p>\n<\/li>\n<\/ol>\n<h4>list_controller.dart<\/h4>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043c\u043e\u0434\u0438\u0444\u0438\u0446\u0438\u0440\u0443\u0435\u043c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u0441\u043f\u0438\u0441\u043a\u0430 \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u043e\u043d \u043c\u043e\u0433 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u0430 <em>ExampleRecordQuery<\/em>.<\/p>\n<pre><code class=\"dart\">\/* file: list_controller.dart *\/  import 'package:fl_list_example\/list_state.dart'; import 'package:fl_list_example\/models.dart'; import 'package:fl_list_example\/repository.dart'; import 'package:flutter\/foundation.dart';  class ListController extends ValueNotifier&lt;ListState> {   final ExampleRecordQuery query; \/\/ +    ListController({required this.query}) : super(ListState()) {     loadRecords(query: query); \/\/ *   }    Future&lt;List&lt;ExampleRecord>> fetchRecords(ExampleRecordQuery? query) async { \/\/ *     final loadedRecords = await MockRepository().queryRecords(query); \/\/ *     return loadedRecords;   }    Future&lt;void> loadRecords({ExampleRecordQuery? query}) async { \/\/ *     if (value.isLoading) return;      value = value.copyWith(isLoading: true, error: \"\");      try {       final fetchResult = await fetchRecords(query); \/\/ *        value = value.copyWith(isLoading: false, records: fetchResult);     } catch (e) {       value = value.copyWith(isLoading: false, error: e.toString());       rethrow;     }   }    repeatQuery() {     return loadRecords(query: query); \/\/ *   } } <\/code><\/pre>\n<h4>widgets\/record_teaser.dart<\/h4>\n<p>\u0414\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u0432\u044b\u043d\u0435\u0441\u0435\u043c \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u0441\u043f\u0438\u0441\u043a\u0430 \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u0432\u0438\u0434\u0436\u0435\u0442. \u0427\u0442\u043e\u0431\u044b \u0432\u0438\u0437\u0443\u0430\u043b\u044c\u043d\u043e \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438, \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0432 \u0432\u0438\u0434\u0436\u0435\u0442\u0435 \u0432\u0435\u0441\u0430 \u0437\u0430\u043f\u0438\u0441\u0438.<\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0444\u0430\u0439\u043b <em>widgets\/record_teaser.dart<\/em> \u0441 \u0442\u0430\u043a\u0438\u043c \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u044b\u043c:<\/p>\n<pre><code class=\"dart\">\/* file: widgets\/record_teaser.dart *\/  import 'package:fl_list_example\/models.dart'; import 'package:flutter\/material.dart';  class RecordTeaser extends StatelessWidget {   final ExampleRecord record;    const RecordTeaser({required this.record, Key? key}) : super(key: key);    @override   Widget build(BuildContext context) {     return ListTile(       title: Text(record.title),       subtitle: Text(\"weight: ${record.weight}\"),     );   } }  <\/code><\/pre>\n<h4>main.dart<\/h4>\n<p>\u0412 \u0441\u0442\u0440\u043e\u043a\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430 \u0444\u0430\u0439\u043b\u0430 <em>main.dart<\/em> \u0443\u043a\u0430\u0436\u0435\u043c \u0443\u0441\u043b\u043e\u0432\u0438\u044f \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u0438 \u0437\u0430\u043f\u0438\u0441\u0435\u0439. \u0414\u043e\u0431\u0430\u0432\u0438\u043c, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0447\u0442\u043e \u0432 \u0441\u043f\u0438\u0441\u043a\u0435 \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0437\u0430\u043f\u0438\u0441\u0438, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u0435 \u043f\u043e\u0434\u0441\u0442\u0440\u043e\u043a\u0443 &#171;ea&#187;.<\/p>\n<pre><code class=\"dart\">\/* file: main.dart *\/ import 'package:fl_list_example\/models.dart'; \/\/ +    ...   home: ChangeNotifierProvider(     create: (_) => ListController(query: const ExampleRecordQuery(contains: \"ea\")), \/\/ *     child: const HomePage(),   ),   ...  <\/code><\/pre>\n<p>\u0418\u0437\u043c\u0435\u043d\u0438\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e <em>build<\/em> \u0444\u0430\u0439\u043b\u0430 <em>main.dart<\/em> \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u0434\u043b\u044f \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u0441\u043f\u0438\u0441\u043a\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0447\u0442\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0439 \u043d\u0430\u043c\u0438 \u0432\u0438\u0434\u0436\u0435\u0442 <em>RecordTeaser<\/em>.<\/p>\n<pre><code class=\"dart\">\/* file: main.dart *\/ import 'package:fl_list_example\/widgets\/record_teaser.dart'; \/\/ +    ...   final record = listState.records[index];   return RecordTeaser(record: record); \/\/ *   ... <\/code><\/pre>\n<p><a class=\"anchor\" name=\"load_data\" id=\"load_data\"><\/a><\/p>\n<h2>\u041f\u043e\u0440\u0446\u0438\u043e\u043d\u043d\u0430\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445<\/h2>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/821\/b19\/efb\/821b19efbce381c583394c1255be3ee8.gif\" alt=\"\" title=\"\" width=\"320\" height=\"569\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/821\/b19\/efb\/821b19efbce381c583394c1255be3ee8.gif\"\/><figcaption><\/figcaption><\/figure>\n<p><a href=\"https:\/\/github.com\/astoniocom\/fl_list_example\/tree\/partial\" rel=\"noopener noreferrer nofollow\">\u041e\u0442\u043a\u0440\u044b\u0442\u044c \u043a\u043e\u0434 \u043d\u0430 GitHub<\/a><\/p>\n<p>\u041a\u043e\u0433\u0434\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043c\u043d\u043e\u0433\u043e, \u043d\u0435\u0442 \u0441\u043c\u044b\u0441\u043b\u0430 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044c \u0438\u0445 \u0432\u0441\u0435 \u0441\u0440\u0430\u0437\u0443. \u0412 \u044d\u0442\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u043d\u043e\u0432\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e \u043c\u0435\u0440\u0435 \u043f\u0440\u043e\u043a\u0440\u0443\u0442\u043a\u0438 \u0441\u043f\u0438\u0441\u043a\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u043c.<\/p>\n<h4>models.dart<\/h4>\n<p>\u0422\u0430\u043a \u043a\u0430\u043a \u043f\u0440\u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0435 \u0441\u043f\u0438\u0441\u043a\u0430 \u0447\u0430\u0441\u0442\u044f\u043c\u0438 \u0432 \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u043d\u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u043d\u0443\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c, \u043a\u0430\u043a\u043e\u0439 \u0432\u0435\u0441 \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0443 \u043e\u0447\u0435\u0440\u0435\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u0434\u0430\u043d\u043d\u044b\u0445, \u0432 \u043a\u043b\u0430\u0441\u0441 <em>ExampleRecordQuery<\/em> \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e weightGt (\u0432 \u0434\u0440\u0443\u0433\u043e\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u044d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0441 \u043d\u043e\u043c\u0435\u0440\u043e\u043c \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b <em>page<\/em>).<\/p>\n<p>\u0422\u0430\u043a \u0436\u0435 \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u0430, \u043d\u043e \u0441 \u0438\u0437\u043c\u0435\u043d\u0451\u043d\u043d\u044b\u043c\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c\u0438.<\/p>\n<pre><code class=\"dart\">\/* file: models.dart *\/ class ExampleRecordQuery {   final String? contains;   final int? weightGt; \/\/ +    const ExampleRecordQuery({     this.contains,     this.weightGt, \/\/ +   });   ...   ExampleRecordQuery copyWith({int? weightGt}) { \/\/ +     return ExampleRecordQuery( \/\/ +       weightGt: weightGt ?? this.weightGt, \/\/ +     ); \/\/ +   }\/\/ + } <\/code><\/pre>\n<h4>repository.dart<\/h4>\n<p>\u0412 \u043d\u0430\u0447\u0430\u043b\u0435 \u0444\u0430\u0439\u043b\u0430 <em>repository.dart<\/em> \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u0443, \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044e\u0449\u0443\u044e \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0437\u0430\u043f\u0438\u0441\u0435\u0439, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0435\u0439 <em>queryRecords<\/em> \u0437\u0430 \u0440\u0430\u0437.<\/p>\n<pre><code class=\"dart\">\/* file: repository.dart *\/ ... const kBatchSize = 15; ... <\/code><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u044e\u044e \u0441\u0442\u0440\u043e\u043a\u0443 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <em>queryRecords<\/em> \u043d\u0430\u0434\u043e \u0437\u0430\u043c\u0435\u043d\u0438\u0442\u044c \u043d\u0430:<\/p>\n<pre><code class=\"dart\">\/* file: repository.dart *\/    ...    \/\/ if ((query?.weightGt ?? 0) > 400) throw \"Test Exception\"; \/\/ 1    return sortedList.where((record) => query == null || query.suits(record)).take(kBatchSize).toList();    ... <\/code><\/pre>\n<p>\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043a\u043e\u0434\u0430:<\/p>\n<ol>\n<li>\n<p>\u0420\u0430\u0441\u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443 \u043c\u043e\u0436\u043d\u043e \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u0440\u0435\u0430\u0433\u0438\u0440\u0443\u0435\u0442 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b, \u0435\u0441\u043b\u0438 \u0432\u043e\u0437\u043d\u0438\u043a\u043b\u0430 \u043e\u0448\u0438\u0431\u043a\u0430 \u043d\u0430 \u0441\u0442\u0430\u0434\u0438\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445. \u0412 \u044d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u043a\u043e\u0433\u0434\u0430 \u043c\u044b \u043f\u0440\u043e\u043b\u0438\u0441\u0442\u0430\u0435\u043c \u0441\u043f\u0438\u0441\u043e\u043a \u0434\u043e \u0437\u0430\u043f\u0438\u0441\u0438 \u0441 \u0432\u0435\u0441\u043e\u043c 400, \u0434\u043e\u043b\u0436\u043d\u043e \u043f\u043e\u044f\u0432\u0438\u0442\u044c\u0441\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0435 \u0441 \u043a\u043d\u043e\u043f\u043a\u043e\u0439 \u043f\u043e\u0432\u0442\u043e\u0440\u0435\u043d\u0438\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432.<\/p>\n<\/li>\n<\/ol>\n<h4>list_state.dart<\/h4>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u043a \u043c\u043e\u0434\u0435\u0440\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u043a\u043b\u0430\u0441\u0441\u0430 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u0430 <em>ListState<\/em>.<\/p>\n<pre><code class=\"dart\">\/* file: list_state.dart *\/  import 'package:fl_list_example\/models.dart';  enum LoadingFor { idle, replace, add } \/\/ + 1  class ListState {   ListState({     List&lt;ExampleRecord>? records,     this.loadingFor = LoadingFor.idle,     this.hasLoadedAllRecords = false, \/\/ + 2     this.error = '',   }) : recordsStore = records {     \/\/ 3     if (isInitialized &amp;&amp; !hasLoadedAllRecords &amp;&amp; this.records.isEmpty) { \/\/ +        throw Exception(\"Wrong list state: list is empty but has no loadedAllRecords marker\"); \/\/ +     } \/\/ +      if (hasLoadedAllRecords &amp;&amp; hasError) { \/\/ +        throw Exception(\"Wrong list state: state with hasLoadedAllRecords marker must not contain error ($error)\"); \/\/ +     } \/\/ +    }    final LoadingFor loadingFor; \/\/ *   final bool hasLoadedAllRecords; \/\/ +    final List&lt;ExampleRecord>? recordsStore;    bool get isInitialized => recordsStore != null;    List&lt;ExampleRecord> get records => recordsStore ?? List&lt;ExampleRecord>.empty();    final String error;    bool get hasError => error.isNotEmpty;    bool get isLoading => loadingFor != LoadingFor.idle; \/\/ +    bool canLoadMore() => !hasLoadedAllRecords &amp;&amp; !isLoading &amp;&amp; !hasError; \/\/ +    ListState copyWith({     List&lt;ExampleRecord>? records,     LoadingFor? loadingFor, \/\/ *     bool? hasLoadedAllRecords, \/\/ +     String? error,   }) {     return ListState(       records: records ?? recordsStore,       loadingFor: loadingFor ?? this.loadingFor, \/\/ +       hasLoadedAllRecords: hasLoadedAllRecords ?? this.hasLoadedAllRecords, \/\/ +       error: error ?? this.error,     );   } }  <\/code><\/pre>\n<p>\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043a\u043e\u0434\u0430:<\/p>\n<ol>\n<li>\n<p>\u0418\u043d\u043e\u0433\u0434\u0430 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u043e-\u0440\u0430\u0437\u043d\u043e\u043c\u0443 \u0438\u043d\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043e \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u0441\u043b\u0443\u0447\u0430\u044f\u0445, \u0435\u0441\u043b\u0438 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0432\u0441\u0435\u0433\u043e \u0441\u043f\u0438\u0441\u043a\u0430, \u043b\u0438\u0431\u043e \u043f\u043e\u0434\u0433\u0440\u0443\u0436\u0430\u0435\u0442\u0441\u044f \u0435\u0433\u043e \u0447\u0430\u0441\u0442\u044c. \u0414\u0430\u043d\u043d\u043e\u0435 \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0435 \u0446\u0435\u043b\u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u0441\u043f\u0438\u0441\u043a\u0430.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043d \u043b\u0438 \u0441\u043f\u0438\u0441\u043e\u043a \u0446\u0435\u043b\u0438\u043a\u043e\u043c. \u041e\u043d\u0430 \u0434\u043e\u043b\u0436\u043d\u0430 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 <em>true<\/em>, \u043a\u043e\u0433\u0434\u0430 \u0432 \u0441\u043f\u0438\u0441\u043e\u043a \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u044f\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043d\u0430 \u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u0430. \u0427\u0442\u043e\u0431\u044b \u043e\u0442\u043b\u0430\u0434\u043a\u0430 \u043a\u043e\u0434\u0430 \u0431\u044b\u043b \u043f\u0440\u043e\u0449\u0435, \u043b\u0443\u0447\u0448\u0435 \u0442\u0430\u043a\u0438\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043e\u0442\u043b\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0440\u0430\u043d\u044c\u0448\u0435.<\/p>\n<\/li>\n<\/ol>\n<h4>list_controller.dart<\/h4>\n<p>\u041f\u0440\u0438\u0441\u0442\u0443\u043f\u0430\u0435\u043c \u043a \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430 \u0441\u043f\u0438\u0441\u043a\u0430 <em>ListController<\/em> \u0438\u0437 \u0444\u0430\u0439\u043b\u0430 <em>list_controller.dart<\/em>. \u0418\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u043c\u043d\u043e\u0433\u043e, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0441\u043d\u043e\u0432\u0430 \u043f\u0440\u0438\u0432\u0435\u0434\u0443 \u0432\u0441\u0451 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u0444\u0430\u0439\u043b\u0430.<\/p>\n<pre><code class=\"dart\">\/* file: list_controller.dart *\/  import 'package:fl_list_example\/list_state.dart'; import 'package:fl_list_example\/models.dart'; import 'package:fl_list_example\/repository.dart'; import 'package:flutter\/foundation.dart';  \/\/ 1 class _FetchRecordsResult&lt;T> { \/\/ +   final List&lt;ExampleRecord> records; \/\/ +   final bool loadedAllRecords; \/\/ +    _FetchRecordsResult({required this.records, required this.loadedAllRecords}); \/\/ + } \/\/ +  class ListController extends ValueNotifier&lt;ListState> {   final ExampleRecordQuery query;    ListController({required this.query}) : super(ListState()) {     loadRecords(query: query);   }    Future&lt;_FetchRecordsResult> fetchRecords(ExampleRecordQuery? query) async { \/\/ * 1     final loadedRecords = await MockRepository().queryRecords(query);     return _FetchRecordsResult(records: loadedRecords, loadedAllRecords: loadedRecords.length &lt; kBatchSize); \/\/ *   }    Future&lt;void> loadRecords({ExampleRecordQuery? query, bool replace = true}) async { \/\/ * 2     if (value.isLoading) return;      value = value.copyWith(loadingFor: replace ? LoadingFor.replace : LoadingFor.add, error: \"\"); \/\/ * 3      try {       final fetchResult = await fetchRecords(query);        final records = [ \/\/ +         if (!replace) ...value.records, \/\/ +         ...fetchResult.records, \/\/ +       ]; \/\/ +        value = value.copyWith(loadingFor: LoadingFor.idle, records: records, hasLoadedAllRecords: fetchResult.loadedAllRecords); \/\/ *     } catch (e) {       value = value.copyWith(loadingFor: LoadingFor.idle, error: e.toString()); \/\/ *       rethrow;     }   }    directionalLoad() async { \/\/ + 4     final query = getNextRecordsQuery(); \/\/ +     await loadRecords(query: query, replace: false); \/\/ +   } \/\/ +    ExampleRecordQuery getNextRecordsQuery() { \/\/ + 5     if (value.records.isEmpty) throw Exception(\"Impossible to create query\"); \/\/ + 6     return query.copyWith(weightGt: value.records.last.weight); \/\/ + 7   } \/\/ +    repeatQuery() {     return value.records.isEmpty ? loadRecords(query: query) : directionalLoad(); \/\/ * 8   } } <\/code><\/pre>\n<p>\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043a\u043e\u0434\u0430:<\/p>\n<ol>\n<li>\n<p>\u0414\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0444\u0443\u043d\u043a\u0446\u0438\u044f <em>fetchRecords<\/em> \u043c\u043e\u0433\u043b\u0430 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u043f\u0438\u0441\u043e\u043a \u0437\u0430\u043f\u0438\u0441\u0435\u0439, \u043d\u043e \u0435\u0449\u0451 \u0438 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0442\u043e\u043c, \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043b\u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u044b\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u0435\u043c \u0441\u043f\u0438\u0441\u043a\u0430, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u043e\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u044d\u0442\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043e\u0431\u044a\u0435\u043a\u0442 \u043a\u043b\u0430\u0441\u0441\u0430 <em>_FetchRecordsResult<\/em>.<\/p>\n<\/li>\n<li>\n<p>\u0422\u0430\u043a \u043a\u0430\u043a \u0442\u0435\u043f\u0435\u0440\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u043c\u043e\u0436\u0435\u0442 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044c\u0441\u044f \u0438 \u0446\u0435\u043b\u0438\u043a\u043e\u043c, \u0438 \u0447\u0430\u0441\u0442\u044f\u043c\u0438, \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u044d\u0442\u043e \u0447\u0435\u0440\u0435\u0437 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 <em>replace<\/em> \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <em>loadRecords<\/em>.<\/p>\n<\/li>\n<li>\n<p>\u041e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u043c \u0446\u0435\u043b\u044c \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0441\u043f\u0438\u0441\u043a\u0430 (\u0446\u0435\u043b\u0438\u043a\u043e\u043c \u0438\u043b\u0438 \u0447\u0430\u0441\u0442\u044f\u043c\u0438) \u0432 \u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438.<\/p>\n<\/li>\n<li>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f, \u043a\u043e\u0433\u0434\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u0441\u043f\u0438\u0441\u043a\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u0442 \u043e\u0431\u044a\u0435\u043a\u0442 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u0441\u043f\u0438\u0441\u043a\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043d\u0430 \u0443\u043c\u0435\u0441\u0442\u043d\u043e\u0441\u0442\u044c \u0432\u044b\u0437\u043e\u0432\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <em>getNextRecordsQuery<\/em>. \u041d\u0435\u0442 \u0441\u043c\u044b\u0441\u043b\u0430 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u0441\u043f\u0438\u0441\u043a\u0430, \u0435\u0441\u043b\u0438 \u043e\u043d \u043f\u0443\u0441\u0442.<\/p>\n<\/li>\n<li>\n<p>\u041c\u043e\u0434\u0438\u0444\u0438\u0446\u0438\u0440\u0443\u0435\u043c \u0437\u0430\u043f\u0440\u043e\u0441 \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u0444\u0443\u043d\u043a\u0446\u0438\u044f <em>queryRecords<\/em> \u0432\u0435\u0440\u043d\u0443\u043b\u0430 \u0434\u0430\u043d\u043d\u044b\u0435, \u0443 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430, \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u0438\u0434\u0451\u0442 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0430, \u0431\u044b\u043b\u043e \u0431\u043e\u043b\u044c\u0448\u0435, \u0447\u0435\u043c \u0443 \u0442\u0430\u043a\u043e\u0433\u043e \u0436\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0439 \u0437\u0430\u043f\u0438\u0441\u0438 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0441\u043f\u0438\u0441\u043a\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0412\u043e \u0432\u0440\u0435\u043c\u044f \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u0439 \u043f\u043e\u043f\u044b\u0442\u043a\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u0441\u043f\u043e\u0441\u043e\u0431, \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u043e\u043d\u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u043b\u0438\u0441\u044c \u0432 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0439 \u0440\u0430\u0437. \u0414\u0435\u043b\u0430\u0435\u0442\u0441\u044f \u044d\u0442\u043e \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0438 \u0442\u043e\u0433\u043e, \u0435\u0441\u0442\u044c \u043b\u0438 \u0437\u0430\u043f\u0438\u0441\u0438 \u0432 \u0442\u0435\u043a\u0443\u0449\u0435\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438 \u0441\u043f\u0438\u0441\u043a\u0430. \u0410\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u2014 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 <em>ExampleRecordQuery<\/em> \u0432 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438 \u0441\u043f\u0438\u0441\u043a\u0430 <em>ListState<\/em>.<\/p>\n<\/li>\n<\/ol>\n<h4>main.dart<\/h4>\n<p>\u041f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u043a \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0444\u0430\u0439\u043b\u0430 <em>main.dart<\/em>. \u0422\u0430\u043a \u043a\u0430\u043a \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0431\u043e\u043b\u044c\u0448\u0435\u0433\u043e \u0438\u0437 \u0434\u0432\u0443\u0445 \u0447\u0438\u0441\u0435\u043b, \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u043c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 <em>import &#8216;dart:math&#8217;<\/em>.<\/p>\n<p>\u0427\u0442\u043e\u0431\u044b \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0442\u044c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0441\u0442\u0440\u043e\u043a \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0432 \u0441\u043f\u0438\u0441\u043a\u0435, \u0443\u0431\u0435\u0440\u0451\u043c \u0444\u0438\u043b\u044c\u0442\u0440 \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u043f\u043e \u043f\u043e\u0434\u0441\u0442\u0440\u043e\u043a\u0435:<\/p>\n<pre><code class=\"dart\">\/* file: main.dart *\/    ...   create: (_) => ListController(query: const ExampleRecordQuery(\/*contains: \"ea\"*\/)),   ... <\/code><\/pre>\n<p>\u041c\u043e\u0434\u0438\u0444\u0438\u0446\u0438\u0440\u0443\u0435\u043c \u043a\u043b\u0430\u0441\u0441 _HomePageState \u0434\u043e \u0432\u0438\u0434\u0430:<\/p>\n<pre><code class=\"dart\">\/* file: main.dart *\/  class _HomePageState extends State&lt;HomePage> {   final ScrollController _scrollController = ScrollController(); \/\/ 1 +    static const double loadExtent = 80.0; \/\/ 2 +    double _oldScrollOffset = 0.0; \/\/ 3 +    @override \/\/ +   initState() { \/\/ +     _scrollController.addListener(_scrollControllerListener); \/\/ + 4     super.initState(); \/\/ +   } \/\/ +    _scrollControllerListener() { \/\/ 4 +     if (!_scrollController.hasClients) return; \/\/ +     final offset = _scrollController.position.pixels; \/\/ +     final bool scrollingDown = _oldScrollOffset &lt; offset; \/\/ +     _oldScrollOffset = _scrollController.position.pixels; \/\/ +     final maxExtent = _scrollController.position.maxScrollExtent; \/\/ +     final double positiveReloadBorder = max(maxExtent - loadExtent, 0); \/\/ +      final listController = context.read&lt;ListController>(); \/\/ +     if (((scrollingDown &amp;&amp; offset > positiveReloadBorder) || positiveReloadBorder == 0) &amp;&amp; listController.value.canLoadMore()) { \/\/ +       listController.directionalLoad(); \/\/ +     } \/\/ +   } \/\/ +    @override \/\/ +   void dispose() { \/\/ +     if (_scrollController.hasClients == true) _scrollController.removeListener(_scrollControllerListener); \/\/ +     super.dispose(); \/\/ +   } \/\/ +    @override   Widget build(BuildContext context) {     final listController = context.watch&lt;ListController>();     final listState = listController.value;     final itemCount = listState.records.length + (ListStatusIndicator.hasStatus(listState) ? 1 : 0);     return Scaffold(       appBar: AppBar(title: const Text(\"List Demo\")),       body: ListView.builder(         controller: _scrollController, \/\/ + 1         itemBuilder: (context, index) {           if (index == listState.records.length &amp;&amp; ListStatusIndicator.hasStatus(listState)) {             return ListStatusIndicator(listState, onRepeat: listController.directionalLoad);           }            final record = listState.records[index];           return RecordTeaser(record: record);         },         itemCount: itemCount,       ),     );   } } <\/code><\/pre>\n<p>\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043a\u043e\u0434\u0430:<\/p>\n<ol>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u0451\u043c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440, \u0447\u0442\u043e\u0431\u044b \u0431\u044b\u043b\u0430 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u043a\u0440\u0443\u0442\u043a\u0443 \u0441\u043f\u0438\u0441\u043a\u0430.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u043e\u0442\u0441\u0442\u0443\u043f \u043e\u0442 \u043a\u043e\u043d\u0446\u0430 \u0441\u043f\u0438\u0441\u043a\u0430. \u041a\u043e\u0433\u0434\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043f\u0440\u043e\u043a\u0440\u0443\u0447\u0438\u0432\u0430\u0435\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u0434\u043e \u044d\u0442\u043e\u0439 \u043f\u043e\u0437\u0438\u0446\u0438\u0438, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443.<\/p>\n<\/li>\n<li>\n<p>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043b\u0438\u0448\u044c \u0434\u043b\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u043a\u0440\u0443\u0442\u043a\u0438 \u0441\u043f\u0438\u0441\u043a\u0430: \u0432\u0432\u0435\u0440\u0445 \u0438\u043b\u0438 \u0432\u043d\u0438\u0437.<\/p>\n<\/li>\n<li>\n<p>\u042d\u0442\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437, \u043a\u043e\u0433\u0434\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0434\u0435\u043b\u0430\u0435\u0442 \u043f\u0440\u043e\u043a\u0440\u0443\u0442\u043a\u0443 \u0441\u043f\u0438\u0441\u043a\u0430. \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0438\u043d\u0438\u0446\u0438\u0438\u0440\u0443\u0435\u0442 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0443 \u043e\u0447\u0435\u0440\u0435\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u0434\u0430\u043d\u043d\u044b\u0445, \u043a\u043e\u0433\u0434\u0430 \u0441\u043f\u0438\u0441\u043e\u043a \u0434\u043e\u043a\u0440\u0443\u0442\u0438\u043b\u0438 \u0434\u043e \u043f\u043e\u0437\u0438\u0446\u0438\u0438 <em>loadExtent<\/em> \u0441 \u043a\u043e\u043d\u0446\u0430.<\/p>\n<\/li>\n<\/ol>\n<p><a class=\"anchor\" name=\"actual\" id=\"actual\"><\/a><\/p>\n<h2>\u0410\u043a\u0442\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445<\/h2>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/c27\/b9a\/02e\/c27b9a02ef3df3915ebf96dc5803c91f.gif\" alt=\"\" title=\"\" width=\"320\" height=\"569\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/c27\/b9a\/02e\/c27b9a02ef3df3915ebf96dc5803c91f.gif\"\/><figcaption><\/figcaption><\/figure>\n<p><a href=\"https:\/\/github.com\/astoniocom\/fl_list_example\/tree\/actualizing\" rel=\"noopener noreferrer nofollow\">\u041e\u0442\u043a\u0440\u044b\u0442\u044c \u043a\u043e\u0434 \u043d\u0430 GitHub<\/a><\/p>\n<p>\u0422\u0430\u043a \u043a\u0430\u043a \u0434\u0430\u043d\u043d\u044b\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u044e\u0442\u0441\u044f \u0432 \u0441\u043f\u0438\u0441\u043a\u0435, \u0441\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0435\u043c \u043c\u043e\u0433\u0443\u0442 \u0443\u0441\u0442\u0430\u0440\u0435\u0432\u0430\u0442\u044c, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u044d\u0442\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445. \u041f\u0440\u0438 \u044d\u0442\u043e\u043c \u043d\u0435 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437 \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0442\u044c \u0443 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432\u0441\u0435 \u0437\u0430\u043f\u0438\u0441\u0438 \u0434\u043b\u044f \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u0430. \u0412 \u044d\u0442\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u0435\u0445 \u0441\u0442\u0440\u043e\u043a \u0441\u043f\u0438\u0441\u043a\u0430, \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0438\u0437\u043c\u0435\u043d\u0438\u043b\u0438\u0441\u044c.<\/p>\n<h4>pubspec.yaml<\/h4>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u043f\u0430\u043a\u0435\u0442\u044b \u0432 \u0444\u0430\u0439\u043b <em>pubspec.yaml<\/em> \u0438 \u0432 \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u043c <em>flutter pub get<\/em>.<\/p>\n<pre><code class=\"yaml\">dependencies:   rxdart: ^0.27.3 # 1   collection: ^1.15.0 # 2   ... <\/code><\/pre>\n<p>\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043a\u043e\u0434\u0430:<\/p>\n<ol>\n<li>\n<p>\u0411\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043f\u043e\u0442\u043e\u043a\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u043d\u0430\u0434 \u043e\u0431\u044a\u0435\u043a\u0442\u0430\u043c\u0438 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<\/li>\n<li>\n<p>\u0414\u043b\u044f \u0443\u043c\u0435\u043d\u044c\u0448\u0435\u043d\u0438\u044f \u043e\u0431\u044a\u0435\u043c\u0430 \u043a\u043e\u0434\u0430, \u0438\u0437 \u044d\u0442\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u043f\u043e\u0438\u0441\u043a\u0430 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u0432 \u0441\u043f\u0438\u0441\u043a\u0435 <em>firstWhereOrNull<\/em>.<\/p>\n<\/li>\n<\/ol>\n<h4>models.dart<\/h4>\n<p>\u0417\u0430\u043c\u0435\u043d\u0438\u043c \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u0444\u0430\u0439\u043b\u0430 <em>models.dart<\/em>.<\/p>\n<pre><code class=\"dart\">\/* file: models.dart *\/  typedef ID = int; \/\/ + 1  class ExampleRecord {   final ID id; \/\/ + 2   final String title;   final int weight;    const ExampleRecord({     required this.id, \/\/ + 2     required this.title,     required this.weight,   }); }  class ExampleRecordQuery {   final String? contains;   final int? weightGt;   final int? weightLte; \/\/ + 3    const ExampleRecordQuery({     this.contains,     this.weightGt,     this.weightLte, \/\/ + 3   });    bool suits(ExampleRecord obj) {     if (contains != null &amp;&amp; contains!.isNotEmpty &amp;&amp; !obj.title.contains(contains!)) return false;     if (weightGt != null &amp;&amp; obj.weight &lt;= weightGt!) return false;     if (weightLte != null &amp;&amp; obj.weight > weightLte!) return false; \/\/ + 3     return true;   }    int compareRecords(ExampleRecord record1, ExampleRecord record2) {     return record1.weight.compareTo(record2.weight);   }    ExampleRecordQuery copyWith({int? weightGt, int? weightLte}) { \/\/ *     return ExampleRecordQuery(       weightGt: weightGt ?? this.weightGt,       weightLte: weightLte ?? this.weightLte, \/\/ + 3     );   } }  \/\/ 4: abstract class RecordEvent { \/\/ +   final ID id; \/\/ +    RecordEvent(this.id); \/\/ + } \/\/ +  class RecordCreatedEvent extends RecordEvent { \/\/ +   RecordCreatedEvent(ID id) : super(id); \/\/ + } \/\/ +  class RecordUpdatedEvent extends RecordEvent { \/\/ +   RecordUpdatedEvent(ID id) : super(id); \/\/ + } \/\/ +  class RecordDeletedEvent extends RecordEvent { \/\/ +   RecordDeletedEvent(ID id) : super(id); \/\/ + } \/\/ +  \/\/ 5: class WeightDuplicate {} \/\/ +  class RecordDoesNotExist {} \/\/ + <\/code><\/pre>\n<p>\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043a\u043e\u0434\u0430:<\/p>\n<ol>\n<li>\n<p>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u0442\u0438\u043f \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0430 \u0437\u0430\u043f\u0438\u0441\u0438. \u042d\u0442\u043e \u0441\u0434\u0435\u043b\u0430\u043d\u043e \u0447\u0435\u0440\u0435\u0437 typedef, \u0447\u0442\u043e\u0431\u044b:<\/p>\n<\/li>\n<\/ol>\n<ul>\n<li>\n<p>\u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u043e\u043c\u0435\u043d\u044f\u0442\u044c \u0442\u0438\u043f \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0430 \u043d\u0430 \u0434\u0440\u0443\u0433\u043e\u0439, \u0431\u0435\u0437 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u043a\u0438 \u0442\u0438\u043f\u0430 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 \u0432\u043e \u0432\u0441\u0435\u0445 \u043c\u0435\u0441\u0442\u0430\u0445 \u043a\u043e\u0434\u0430, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440;<\/p>\n<\/li>\n<li>\n<p>\u0443\u043f\u0440\u043e\u0441\u0442\u0438\u0442\u044c \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u0446\u0435\u043b\u0435\u0439, \u0434\u043b\u044f \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0431\u0443\u0434\u0443\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u044d\u0442\u043e\u0433\u043e \u0442\u0438\u043f\u0430.<\/p>\n<\/li>\n<\/ul>\n<ol start=\"2\">\n<li>\n<p>\u041f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0430 \u0437\u0430\u043f\u0438\u0441\u0438. \u0421 \u0435\u0451 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0431\u0443\u0434\u0443\u0442 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u043e\u0434\u043d\u0438 \u0438 \u0442\u0435 \u0436\u0435 \u0437\u0430\u043f\u0438\u0441\u0438 \u0432 \u0441\u043f\u0438\u0441\u043a\u0435.<\/p>\n<\/li>\n<li>\n<p>\u0411\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u0438 \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u0441\u043f\u0438\u0441\u043a\u0430, \u0435\u0441\u043b\u0438 \u0438\u0445 \u0432\u0435\u0441 \u043c\u0435\u043d\u044c\u0448\u0435 \u0438\u043b\u0438 \u0440\u0430\u0432\u0435\u043d \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u043e\u043c\u0443 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044e <em>weightLte<\/em>.<\/p>\n<\/li>\n<li>\n<p>\u041a\u043b\u0430\u0441\u0441\u044b \u0434\u043b\u044f \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439, \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u043c\u044b\u0445 \u043d\u0430\u0434 \u0437\u0430\u043f\u0438\u0441\u044f\u043c\u0438 \u0432 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0435 \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<\/li>\n<li>\n<p>\u041a\u043b\u0430\u0441\u0441\u044b \u0434\u043b\u044f \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0439, \u0432\u043e\u0437\u043d\u0438\u043a\u0448\u0438\u0445 \u043f\u0440\u0438 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0438 \u0441 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u043c \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<\/li>\n<\/ol>\n<h4>repository.dart<\/h4>\n<p>\u0412 \u0444\u0430\u0439\u043b\u0435 <em>repository.dart<\/em> \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u043c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 <em>collection<\/em>. \u0418\u0437 \u043d\u0435\u0451 \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u0438 \u0441\u043f\u0438\u0441\u043a\u0430 <em>firstWhereOrNull<\/em>.<\/p>\n<p>\u0414\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439 \u043e \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f\u0445 \u043d\u0430\u0434 \u0437\u0430\u043f\u0438\u0441\u044f\u043c\u0438 \u0438\u0437 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 <em>_store<\/em> \u0432 \u0434\u0440\u0443\u0433\u0438\u0435 \u0447\u0430\u0441\u0442\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f <em>StreamController<\/em>, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u043c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 <em>dart:async<\/em> \u0438 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u0438 \u043f\u043e\u0442\u043e\u043a \u043f\u043e\u0442\u043e\u043a \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439 \u043e \u0441\u043e\u0431\u044b\u0442\u0438\u044f\u0445 \u0432 \u043a\u043b\u0430\u0441\u0441\u0435 <em>MockRepository<\/em>. <\/p>\n<pre><code class=\"dart\">\/* file: repository.dart *\/  import 'package:collection\/collection.dart'; \/\/ + import 'dart:async'; \/\/ +  ...  class MockRepository {   final StreamController&lt;RecordEvent> eventController = StreamController&lt;RecordEvent>(); \/\/ +   late Stream&lt;RecordEvent> rawEvents = eventController.stream.asBroadcastStream(); \/\/ +   ... <\/code><\/pre>\n<p>\u0412 \u043a\u043e\u0434, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0430\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u0431\u0430\u0437\u0443 \u0437\u0430\u043f\u0438\u0441\u0435\u0439, \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0441\u0442\u0440\u043e\u043a\u0443 \u043f\u0440\u0438\u0441\u0432\u043e\u0435\u043d\u0438\u044f \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0430 \u0434\u043b\u044f \u0437\u0430\u043f\u0438\u0441\u0438.<\/p>\n<pre><code class=\"dart\">      ...       (i) => ExampleRecord(           id: i, \/\/ +           weight: i * 10,           title: nouns[Random().nextInt(nouns.length)],         ))       ... <\/code><\/pre>\n<p>\u0412 \u044d\u0442\u043e\u0442 \u0436\u0435 \u043a\u043b\u0430\u0441\u0441 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u043f\u043e \u0438\u0445 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0430\u043c. \u0422\u0430\u043a \u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f, \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u0438\u0437 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<pre><code class=\"dart\">\/* file: repository.dart *\/   ...   Future&lt;List&lt;ExampleRecord>> getByIds(Iterable&lt;ID> ids) async {     return _store.where((record) => ids.contains(record.id)).toList();   }    Future&lt;ID> createRecord({required String title, required int weight}) async {     if (_store.where((element) => element.weight == weight).isNotEmpty) throw WeightDuplicate(); \/\/ 1     final maxId = _store.isNotEmpty ? _store.map((e) => e.id).reduce(max) : 0; \/\/ 2     final newId = maxId + 1;     _store.add(ExampleRecord( \/\/ 3       id: newId,       title: title,       weight: weight,     ));     eventController.add(RecordCreatedEvent(newId)); \/\/ 5     return newId;   }    Future&lt;void> updateRecord(ID id, {String? title, int? weight}) async {     final ExampleRecord? record = _store.firstWhereOrNull((element) => element.id == id); \/\/ 4     if (record == null) throw RecordDoesNotExist();      if (_store.where((element) => element != record &amp;&amp; element.weight == weight).isNotEmpty) throw WeightDuplicate(); \/\/ 1     final _storeIndex = _store.indexOf(record);     _store[_storeIndex] = ExampleRecord( \/\/ 3       id: id,       title: title ?? record.title,       weight: weight ?? record.weight,     );     eventController.add(RecordUpdatedEvent(id)); \/\/ 5   }    Future&lt;void> deleteRecord(ID id) async {     final ExampleRecord? record = _store.firstWhereOrNull((element) => element.id == id); \/\/ 4     if (record == null) throw RecordDoesNotExist();     _store.remove(record);     eventController.add(RecordDeletedEvent(id)); \/\/ 5   }   ... <\/code><\/pre>\n<p>\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043a\u043e\u0434\u0430:<\/p>\n<ol>\n<li>\n<p>\u0412\u0435\u0441 \u0437\u0430\u043f\u0438\u0441\u0438 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u043c, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0431\u044b\u043b\u043e \u043d\u0435\u043e\u0434\u043d\u043e\u0437\u043d\u0430\u0447\u043d\u044b\u0445 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u0439 \u0441 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u043e\u0439 \u0441\u043f\u0438\u0441\u043a\u0430. \u0412 \u043f\u0440\u043e\u0442\u0438\u0432\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0432\u044b\u0437\u043e\u0432\u0435\u0442 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 <em>WeightDuplicate<\/em>.<\/p>\n<\/li>\n<li>\n<p>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0430 \u0437\u0430\u043f\u0438\u0441\u0438 \u0432 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445. \u0415\u0441\u043b\u0438 \u0436\u0435 \u0432\u0441\u0435 \u0437\u0430\u043f\u0438\u0441\u0438 \u0438\u0437 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0431\u044b\u043b\u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u044b, \u0441\u0447\u0438\u0442\u0430\u0435\u043c, \u0447\u0442\u043e \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0439 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0440\u0430\u0432\u043d\u044f\u0435\u0442\u0441\u044f 0. \u041d\u043e\u0432\u043e\u0439 \u0437\u0430\u043f\u0438\u0441\u0438 \u043f\u0440\u0438\u0441\u0432\u0430\u0438\u0432\u0430\u0435\u043c \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u043d\u0430 \u0435\u0434\u0438\u043d\u0438\u0446\u0443 \u0431\u043e\u043b\u044c\u0448\u0435 \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0433\u043e.<\/p>\n<\/li>\n<li>\n<p>\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0437\u0430\u043f\u0438\u0441\u0438 \u0432 \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u0445\u043e\u0434\u0438\u043c \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0443\u044e \u0437\u0430\u043f\u0438\u0441\u044c \u0432 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445. \u0415\u0441\u043b\u0438 \u0436\u0435 \u0437\u0430\u043f\u0438\u0441\u0438 \u043d\u0435\u0442, \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 <em>RecordDoesNotExist<\/em>.<\/p>\n<\/li>\n<li>\n<p>\u0418\u043d\u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u043f\u043e\u0434\u043f\u0438\u0441\u0447\u0438\u043a\u043e\u0432 \u043f\u043e\u0442\u043e\u043a\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u043e \u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u043d\u043e\u043c \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0438 \u043d\u0430\u0434 \u0437\u0430\u043f\u0438\u0441\u044c\u044e \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<\/li>\n<\/ol>\n<h4>list_controller.dart<\/h4>\n<p>\u0412 \u0444\u0430\u0439\u043b <em>list_controller.dart<\/em> \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438.<\/p>\n<pre><code class=\"dart\">\/* file: list_contoller.dart *\/  import 'dart:async'; import 'package:rxdart\/rxdart.dart'; import 'package:collection\/collection.dart'; <\/code><\/pre>\n<p>\u0412 \u044d\u0442\u043e\u0442 \u0436\u0435 \u0444\u0430\u0439\u043b \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043a\u043b\u0430\u0441\u0441\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u043c\u0435\u0436\u0434\u0443 \u0440\u0430\u0437\u043d\u044b\u043c\u0438 \u0447\u0430\u0441\u0442\u044f\u043c\u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430. \u041a\u043b\u0430\u0441\u0441 <em>RecordsUpdates<\/em> \u043d\u0443\u0436\u0435\u043d \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u0437\u0430\u043f\u0438\u0441\u0435\u0439, \u043d\u0430\u0434 \u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u0431\u044b\u043b\u0438 \u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u044b \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f. \u041a\u043b\u0430\u0441\u0441 <em>_ListChange<\/em> \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0437\u0430\u043f\u0438\u0441\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u0438\u0437 \u0441\u043f\u0438\u0441\u043a\u0430, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0443\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 \u043d\u0435\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0441\u043f\u0438\u0441\u043e\u043a \u0441\u0442\u0430\u043b \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u043c.<\/p>\n<pre><code class=\"dart\">\/* file: list_contoller.dart *\/ ... class RecordsUpdates {   final Set&lt;ID> deletedKeys;   final Set&lt;ExampleRecord> insertedRecords;   final Set&lt;ExampleRecord> updatedRecords;    RecordsUpdates({this.deletedKeys = const {}, this.insertedRecords = const {}, this.updatedRecords = const {}}); }  class _ListChange {   final Iterable&lt;ExampleRecord> recordsToInsert;   final Iterable&lt;ExampleRecord> recordsToRemove;    _ListChange({this.recordsToInsert = const {}, this.recordsToRemove = const {}}); } ... <\/code><\/pre>\n<p>\u0422\u0430\u043a \u043a\u0430\u043a \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u0441\u043f\u0438\u0441\u043a\u0430 \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0438\u0441\u0435\u0439, \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0432 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u043e\u0442\u043c\u0435\u043d\u044b \u044d\u0442\u043e\u0439 \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0438, \u0435\u0441\u043b\u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f.<\/p>\n<pre><code class=\"dart\">\/* file: list_contoller.dart *\/  ... class ListController extends ValueNotifier&lt;ListState> {   late StreamSubscription _changesSubscription; \/\/ +   ...    @override \/\/ +   void dispose() { \/\/ +     _changesSubscription.cancel(); \/\/ +     super.dispose(); \/\/ +   } \/\/ +   ... <\/code><\/pre>\n<p>\u0412 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u043a\u043b\u0430\u0441\u0441\u0430 <em>ListController<\/em> \u043f\u043e\u0441\u043b\u0435 \u0441\u0442\u0440\u043e\u043a\u0438 <em>loadRecords(query: query)<\/em> \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0443 \u043d\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u044f:<\/p>\n<pre><code class=\"dart\">\/* file: list_contoller.dart *\/     ...      _changesSubscription = MockRepository()       .rawEvents       .where((event) => value.isInitialized) \/\/ 1       .bufferTime(const Duration(milliseconds: 300)) \/\/ 2       .where((event) => event.isNotEmpty) \/\/ 3       .asyncMap((event) async {         \/\/ 4:         final createdIds = event.whereType&lt;RecordCreatedEvent>().map((e) => e.id);         final updatedIds = event.whereType&lt;RecordUpdatedEvent>().map((e) => e.id);         final idsToResolve = {...createdIds, ...updatedIds};         final resolvedRecords = (await MockRepository().getByIds(idsToResolve)).toSet();                  return RecordsUpdates(           insertedRecords: resolvedRecords.where((r) => createdIds.contains(r.id)).toSet(),           updatedRecords: resolvedRecords.where((r) => updatedIds.contains(r.id)).toSet(),           deletedKeys: event.whereType&lt;RecordDeletedEvent>().map((e) => e.id).toSet(), \/\/ 5         );       })       .map(_filterRecords) \/\/ 6       .where((event) => event.recordsToInsert.isNotEmpty || event.recordsToRemove.isNotEmpty) \/\/ 7       .map((change) { \/\/ 8         final result = List.of(value.records)..removeWhere((r) => change.recordsToRemove.contains(r));         return result..insertAll(0, change.recordsToInsert);       })       .map((updatedList) {         return updatedList..sort(query.compareRecords); \/\/ 9       })       .listen((updatedList) { \/\/ 10         value = value.copyWith(records: updatedList);       });     ... <\/code><\/pre>\n<p>\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043a\u043e\u0434\u0430:<\/p>\n<ol>\n<li>\n<p>\u0418\u0433\u043d\u043e\u0440\u0438\u0440\u0443\u0435\u043c \u0432\u0441\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0434\u043e \u043c\u043e\u043c\u0435\u043d\u0442\u0430 \u043f\u043e\u043a\u0430 \u043d\u0435 \u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0430 \u043f\u0435\u0440\u0432\u043e\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u0430\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0441\u043f\u0438\u0441\u043a\u0430.<\/p>\n<\/li>\n<li>\n<p>\u041e\u0442 \u043f\u043e\u0442\u043e\u043a\u0430 <em>rawEvents<\/em> \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f \u043e \u0441\u043e\u0431\u044b\u0442\u0438\u044f\u0445 \u043f\u0440\u0438\u0445\u043e\u0434\u044f\u0442 \u043e\u0434\u043d\u043e \u0437\u0430 \u0434\u0440\u0443\u0433\u0438\u043c. \u0415\u0441\u043b\u0438 \u043a\u0430\u0436\u0434\u043e\u0435 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0435 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u0438\u043d\u0434\u0438\u0432\u0438\u0434\u0443\u0430\u043b\u044c\u043d\u043e, \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043d\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044c \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u0442 \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0438 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u0430. \u041e\u0442 \u044d\u0442\u043e\u0433\u043e \u043e\u043d \u043c\u043e\u0436\u0435\u0442 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u043f\u043e\u0441\u0442\u0440\u043e\u0447\u043d\u043e. \u0412 \u043e\u0441\u043e\u0431\u043e\u0439 \u0441\u0442\u0435\u043f\u0435\u043d\u0438 \u044d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u043e\u044f\u0432\u0438\u0442\u044c\u0441\u044f \u043f\u0440\u0438 \u0443\u0434\u0430\u043b\u0451\u043d\u043d\u043e\u043c \u043d\u0430\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u0438 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445. \u041f\u0440\u043e\u0441\u0442\u044b\u043c \u0440\u0435\u0448\u0435\u043d\u0438\u0435\u043c \u044d\u0442\u043e\u0439 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0431\u0443\u0444\u0435\u0440\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c \u0432\u0441\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0432 \u0442\u0435\u0447\u0435\u043d\u0438\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u0447\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u0438\u0437\u043c\u0435\u043d\u0451\u043d\u043d\u044b\u0435 \u0437\u0430\u043f\u0438\u0441\u0438 \u043d\u0435 \u043f\u043e \u043e\u0434\u043d\u043e\u0439, \u0430 \u0433\u0440\u0443\u043f\u043f\u0430\u043c\u0438. \u0418\u0437-\u0437\u0430 \u043d\u0435\u0441\u043e\u0432\u043f\u0430\u0434\u0435\u043d\u0438\u0438 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0431\u0443\u0444\u0435\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0441 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u0435\u043c \u043f\u043e\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0431\u044b\u0442\u0438\u0439, \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0430 \u0441 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435\u043c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430 \u0432\u0441\u0451 \u0440\u0430\u0432\u043d\u043e \u043e\u0441\u0442\u0430\u043d\u0435\u0442\u0441\u044f. \u0414\u043b\u044f \u0435\u0451 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043f\u0435\u0440\u0438\u043e\u0434 \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u043a\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u043c\u043e\u0436\u043d\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0442\u044c \u043d\u0435 \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u043c \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b\u043e\u043c, \u0430, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c\u0438 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f\u043c\u0438 \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435, \u0432\u043b\u0438\u044f\u044e\u0449\u0435\u0435 \u043d\u0430 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u0441\u043f\u0438\u0441\u043a\u0430, \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u043e.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u0435\u043a\u0440\u0430\u0449\u0430\u0435\u043c \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0443\u044e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0434\u0430\u043d\u043d\u044b\u0445, \u0435\u0441\u043b\u0438 \u0437\u0430 \u0432\u0440\u0435\u043c\u044f \u0441\u0431\u043e\u0440\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0431\u0443\u0444\u0435\u0440\u0430 \u043d\u0435 \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u043e \u043d\u0438 \u043e\u0434\u043d\u043e\u0433\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u044f.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0438 \u043f\u0440\u0438\u0448\u0435\u0434\u0448\u0438\u0445 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f\u0445 \u043e \u0441\u043e\u0431\u044b\u0442\u0438\u044f\u0445 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0437\u0430\u043f\u0438\u0441\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u044b\u043b\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u044b \u0438\u043b\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u044b. \u0414\u043b\u044f \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438, \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u043c \u0432\u0441\u0435 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u044b \u0437\u0430\u043f\u0438\u0441\u0435\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0438\u0437 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f. \u0417\u0430\u0442\u0435\u043c \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u044d\u0442\u0438 \u0437\u0430\u043f\u0438\u0441\u0438 \u043e\u0434\u043d\u0438\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u043c.<\/p>\n<\/li>\n<li>\n<p>\u0414\u043b\u044f \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u0438\u0437 \u0441\u043f\u0438\u0441\u043a\u0430 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043b\u0438\u0448\u044c \u0438\u0445 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u0432. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0440\u043e\u0441\u0442\u043e \u0441\u043e\u0437\u0434\u0430\u0451\u043c \u0441\u043f\u0438\u0441\u043e\u043a \u0441 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0430\u043c\u0438 \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0438 \u043f\u0440\u0438\u0448\u0435\u0434\u0448\u0438\u0445 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f\u0445 \u043e \u0441\u043e\u0431\u044b\u0442\u0438\u044f\u0445.<\/p>\n<\/li>\n<li>\n<p>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u0441 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0435\u0439 \u043e \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0445, \u0438\u0437\u043c\u0435\u043d\u0451\u043d\u043d\u044b\u0445 \u0438 \u0443\u0434\u0430\u043b\u0451\u043d\u043d\u044b\u0445 \u0437\u0430\u043f\u0438\u0441\u044f\u0445, \u0441\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0443\u044e \u0432 \u043f\u0440\u043e\u0448\u043b\u043e\u043c \u0448\u0430\u0433\u0435, \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u0435\u043c \u0432 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0441\u043f\u0438\u0441\u043a\u0438 \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u0434\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u0438\u0437 \u0441\u043f\u0438\u0441\u043a\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0415\u0441\u043b\u0438 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u0440\u043e\u0448\u043b\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043d\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u0434\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0438\u043b\u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f, \u043f\u0440\u0435\u043a\u0440\u0430\u0449\u0430\u0435\u043c \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043f\u0440\u0438\u0448\u0435\u0434\u0448\u0438\u0445 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f\u0445 \u043e \u0441\u043e\u0431\u044b\u0442\u0438\u044f\u0445.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0438 \u0441\u043f\u0438\u0441\u043a\u043e\u0432 \u0437\u0430\u043f\u0438\u0441\u0435\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0430\u0434\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0438 \u0443\u0431\u0440\u0430\u0442\u044c, \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u043d\u043e\u0432\u044b\u0439 \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u0439 \u0441\u043f\u0438\u0441\u043e\u043a \u0437\u0430\u043f\u0438\u0441\u0435\u0439.<\/p>\n<\/li>\n<li>\n<p>\u0412\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0443 \u043d\u043e\u0432\u043e\u0433\u043e \u0441\u043f\u0438\u0441\u043a\u0430. \u0421\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0430 \u043d\u0435 \u0431\u044b\u043b\u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0430 \u0432 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0439 \u0448\u0430\u0433, \u0442\u0430\u043a \u043a\u0430\u043a \u0438\u043d\u043e\u0433\u0434\u0430 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438 \u0441\u043f\u0438\u0441\u043a\u0430 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c. \u0412 \u0442\u0430\u043a\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a <em>*asyncMap*<\/em> \u0432\u043c\u0435\u0441\u0442\u043e <em>*map*<\/em>.<\/p>\n<\/li>\n<li>\n<p>\u041e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0441\u043f\u0438\u0441\u043a\u0430 \u043d\u043e\u0432\u044b\u043c\u0438 \u0437\u0430\u043f\u0438\u0441\u044f\u043c\u0438.<\/p>\n<\/li>\n<\/ol>\n<p>\u0423 \u043d\u0430\u0441 \u043e\u0441\u0442\u0430\u043b\u0430\u0441\u044c \u043d\u0435\u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f <em>_filterRecords<\/em>. \u0414\u043b\u044f \u0435\u0451 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0434\u0440\u0443\u0433\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u0432\u0435\u0447\u0430\u0442\u044c \u0437\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443, \u043c\u043e\u0436\u0435\u0442 \u043b\u0438 \u0437\u0430\u043f\u0438\u0441\u044c \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u0432 \u0441\u043f\u0438\u0441\u043a\u0435. \u0415\u0441\u043b\u0438 \u0441\u043f\u0438\u0441\u043e\u043a \u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043d \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e, \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442\u0441\u044f \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u043c <em>query<\/em>. \u0415\u0441\u043b\u0438 \u0436\u0435 \u0441\u043f\u0438\u0441\u043e\u043a \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u043d\u0435 \u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043d, \u0442\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043d\u043e\u0432\u044b\u0439 query \u0441 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435\u043c \u043d\u0430 \u0432\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u0435 \u0437\u0430\u043f\u0438\u0441\u0438 \u0432 \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b \u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043d\u043d\u044b\u0445 \u0437\u0430\u043f\u0438\u0441\u0435\u0439.<\/p>\n<pre><code class=\"dart\">\/* file: list_contoller.dart *\/   ...   bool _recordSuits(ExampleRecord record) {     if (value.hasLoadedAllRecords) return query.suits(record);     return query.copyWith(weightLte: value.records.last.weight).suits(record);   }   ... <\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e  <em>_filterRecords<\/em>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439, \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u0435\u0434\u0448\u0438\u0445 \u0441 \u0437\u0430\u043f\u0438\u0441\u044f\u043c\u0438, \u0431\u0443\u0434\u0435\u0442 \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0431\u044a\u0435\u043a\u0442 <em>_ListChange<\/em> \u0441\u043e \u0441\u043f\u0438\u0441\u043a\u0430\u043c\u0438 \u0437\u0430\u043f\u0438\u0441\u0435\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0443\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0438\u043b\u0438 \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u0438\u0437 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0438\u0440\u0443\u044e\u0449\u0435\u0433\u043e \u0441\u043f\u0438\u0441\u043a\u0430.<\/p>\n<pre><code class=\"dart\">\/* file: list_controller.dart *\/   ...    _ListChange _filterRecords(RecordsUpdates change) {     final recordsToRemove = value.records.where((r) => change.deletedKeys.contains(r.id)).toSet();      final Set&lt;ExampleRecord> rawRecordsToInsert = change.insertedRecords.where((r) => _recordSuits(r)).toSet();      for (final r in change.updatedRecords) {       final recordInList = value.records.firstWhereOrNull((recFromList) => recFromList.id == r.id);        if (recordInList != null &amp;&amp; !_recordSuits(r)) {         recordsToRemove.add(recordInList);       } else if (recordInList == null &amp;&amp; _recordSuits(r)) {         final ExampleRecord? inR = rawRecordsToInsert.firstWhereOrNull((recFromList) => recFromList.id == r.id); \/\/ 1         if (inR != null) rawRecordsToInsert.remove(inR);          rawRecordsToInsert.add(r);       } else if (recordInList != null &amp;&amp; _recordSuits(r)) { \/\/ 2         \/\/ Can we remove repetition of the line         final ExampleRecord? inR = rawRecordsToInsert.firstWhereOrNull((recFromList) => recFromList.id == r.id);         if (inR != null) rawRecordsToInsert.remove(inR);          recordsToRemove.add(recordInList);         rawRecordsToInsert.add(r);       }     }     return _ListChange(       recordsToInsert: rawRecordsToInsert,       recordsToRemove: recordsToRemove,     );   }    ...  <\/code><\/pre>\n<p>\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043a\u043e\u0434\u0430:<\/p>\n<ol>\n<li>\n<p>\u0415\u0441\u043b\u0438 \u0437\u0430\u043f\u0438\u0441\u044c, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u044b\u043b\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0430, \u0442\u0430\u043a \u0436\u0435 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0438 \u0432 \u0441\u043f\u0438\u0441\u043a\u0435 \u0437\u0430\u043f\u0438\u0441\u0435\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u044b\u043b\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u044b, \u0434\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0432 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0438\u0440\u0443\u044e\u0449\u0438\u0439 \u0441\u043f\u0438\u0441\u043e\u043a \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0437\u0430\u043f\u0438\u0441\u044c \u0438\u0437 \u0441\u043f\u0438\u0441\u043a\u0430 \u0438\u0437\u043c\u0435\u043d\u0451\u043d\u043d\u044b\u0445 \u0437\u0430\u043f\u0438\u0441\u0435\u0439. \u0412 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430 \u0441\u043f\u0438\u0441\u043a\u0430, \u044d\u0442\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0439. \u0422\u0430\u043a \u043a\u0430\u043a \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0435 \u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u043d\u044b\u0435 \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u0435 \u0437\u0430\u043f\u0438\u0441\u0438 \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e, \u0442\u043e \u044d\u0442\u0438 \u0437\u0430\u043f\u0438\u0441\u0438 \u043d\u0435 \u0431\u0443\u0434\u0443\u0442 \u043e\u0442\u043b\u0438\u0447\u0430\u0442\u044c\u0441\u044f. \u041e\u0434\u043d\u0430\u043a\u043e \u043f\u0440\u0438 \u0434\u0440\u0443\u0433\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u0438\u0437 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f, \u044d\u0442\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u0430.<\/p>\n<\/li>\n<li>\n<p>\u041e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044f, \u043a\u043e\u0433\u0434\u0430 \u0437\u0430\u043f\u0438\u0441\u044c \u0431\u044b\u043b\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0430, \u043d\u043e \u043e\u043d\u0430 \u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0435\u0449\u0451 \u0438 \u0432 \u0442\u0435\u043a\u0443\u0449\u0435\u043c \u0441\u043f\u0438\u0441\u043a\u0435 \u0438\u0437 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u0430. \u0412 \u044d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0438\u0437 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0438\u0440\u0443\u044e\u0449\u0435\u0433\u043e \u0441\u043f\u0438\u0441\u043a\u0430 \u0443\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u0441\u0442\u0430\u0440\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044c \u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u043e\u0432\u0430\u044f.<\/p>\n<\/li>\n<\/ol>\n<p>\u0414\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u0441\u043f\u0438\u0441\u043a\u0430 \u043d\u0443\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f, \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0438\u0441\u0435\u0439. \u0414\u043b\u044f \u0443\u043f\u0440\u043e\u0449\u0435\u043d\u0438\u044f \u043f\u043e\u0434\u043d\u0438\u043c\u0430\u043d\u0438\u044f \u0438 \u0443\u043c\u0435\u043d\u044c\u0448\u0435\u043d\u0438\u044f \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u043a\u043e\u0434\u0430 \u044f \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u043d\u0430 \u0442\u0438\u0437\u0435\u0440\u0430\u0445 \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u0440\u0438 \u043a\u043d\u043e\u043f\u043a\u0438:<\/p>\n<ol>\n<li>\n<p>\u041a\u043d\u043e\u043f\u043a\u0430 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0437\u0430\u043f\u0438\u0441\u0438 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0437\u0430\u043f\u0438\u0441\u044c \u0441 \u043d\u043e\u0432\u044b\u043c \u0441\u043b\u043e\u0432\u043e\u043c \u0438 \u0432\u0435\u0441\u043e\u043c \u043d\u0430 1 \u0431\u043e\u043b\u044c\u0448\u0435, \u0447\u0435\u043c \u0432\u0435\u0441 \u0437\u0430\u043f\u0438\u0441\u0438, \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0443 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0431\u044b\u043b\u043e \u043d\u0430\u0436\u0430\u0442\u0438\u0435.<\/p>\n<\/li>\n<li>\n<p>\u041a\u043d\u043e\u043f\u043a\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0438\u0441\u0438 \u0431\u0443\u0434\u0435\u0442 \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430\u0442\u044c \u0432\u0435\u0441 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0439 \u0437\u0430\u043f\u0438\u0441\u0438 \u043d\u0430 1.<\/p>\n<\/li>\n<li>\n<p>\u041a\u043d\u043e\u043f\u043a\u0430 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u0431\u0443\u0434\u0435\u0442 \u0443\u0434\u0430\u043b\u044f\u0442\u044c \u0442\u0435\u043a\u0443\u0449\u0443\u044e \u0437\u0430\u043f\u0438\u0441\u044c.<\/p>\n<\/li>\n<\/ol>\n<h4>record_teaser.dart<\/h4>\n<p>\u0412 \u0444\u0430\u0439\u043b <em>record_teaser.dart<\/em> \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438:<\/p>\n<pre><code class=\"dart\">\/* file: record_teaser.dart *\/  import 'dart:math'; import 'package:english_words\/english_words.dart'; import 'package:fl_list_example\/repository.dart'; ...  <\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0432 \u043a\u043b\u0430\u0441\u0441 <em>RecordTeaser<\/em> \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439 \u043d\u0430\u0434 \u0437\u0430\u043f\u0438\u0441\u044f\u043c\u0438:<\/p>\n<pre><code class=\"dart\">\/* file: record_teaser.dart *\/    ...    _createRecord(BuildContext context) async {     try {       await MockRepository().createRecord(title: nouns[Random().nextInt(nouns.length)].toUpperCase(), weight: record.weight + 1);     } on WeightDuplicate {       ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('Weight duplicate')));     } on RecordDoesNotExist {       ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('RecordDoesNotExist exception')));     }   }    _updateRecord(BuildContext context) async {     int newWeight = record.weight + 1;     try {       while (true) {         try {           await MockRepository().updateRecord(record.id, weight: newWeight);           break;         } on WeightDuplicate {           newWeight++;         }       }     } on RecordDoesNotExist {       ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('RecordDoesNotExist exception')));     }   }    _deleteRecord(BuildContext context) async {     try {       await MockRepository().deleteRecord(record.id);     } on RecordDoesNotExist {       ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('RecordDoesNotExist exception')));     }   }    ...  <\/code><\/pre>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u043c \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043a\u043d\u043e\u043f\u043e\u043a \u0432 \u0442\u0438\u0437\u0435\u0440\u0435 \u0437\u0430\u043f\u0438\u0441\u0438:<\/p>\n<pre><code class=\"dart\">\/* file: record_teaser.dart *\/   ...    @override   Widget build(BuildContext context) {     return ListTile(       title: Text(record.title),       subtitle: Text(\"weight: ${record.weight}\"),       trailing: Row(         mainAxisSize: MainAxisSize.min,         children: [ \/\/ +           IconButton(onPressed: () => _createRecord(context), icon: const Icon(Icons.new_label)), \/\/ +\/\/ +           IconButton(onPressed: () => _updateRecord(context), icon: const Icon(Icons.edit)), \/\/ +           IconButton(onPressed: () => _deleteRecord(context), icon: const Icon(Icons.delete)), \/\/ +         ], \/\/ +       ),     );   }    ... <\/code><\/pre>\n<p><a class=\"anchor\" name=\"work_list\" id=\"work_list\"><\/a><\/p>\n<h2>\u0420\u0430\u0431\u043e\u0442\u0430 \u0441\u043e \u0441\u043f\u0438\u0441\u043a\u043e\u043c \u0437\u0430\u043f\u0438\u0441\u0435\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u0441\u044b\u043b\u0430\u044e\u0442\u0441\u044f \u043d\u0430 \u0434\u0440\u0443\u0433\u0438\u0435 \u0437\u0430\u043f\u0438\u0441\u0438<\/h2>\n<p>\u0418\u043d\u043e\u0433\u0434\u0430 \u0437\u0430\u043f\u0438\u0441\u0438 \u0441\u043f\u0438\u0441\u043a\u0430 \u043c\u043e\u0433\u0443\u0442 \u0438\u043c\u0435\u0442\u044c \u043f\u043e\u043b\u044f, \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b. \u0415\u0441\u043b\u0438 \u044d\u0442\u0438 \u043f\u043e\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0434\u043b\u044f \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0438\u0441\u0438 \u0432 \u0441\u043f\u0438\u0441\u043e\u043a, \u0442\u043e \u0438\u0445 \u043d\u0443\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u043d\u0430 \u044d\u0442\u0430\u043f\u0435 \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043e\u0431\u044a\u0435\u043a\u0442\u0430 <em>RecordsUpdates<\/em>. \u041e\u0434\u043d\u0430\u043a\u043e \u0435\u0441\u043b\u0438 \u044d\u0442\u0438 \u043f\u043e\u043b\u044f \u043d\u0435 \u0443\u0447\u0430\u0441\u0442\u0432\u0443\u044e\u0442 \u0432 \u043f\u0440\u0438\u043d\u044f\u0442\u0438\u0438 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043d\u0430 \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0437\u0430\u043f\u0438\u0441\u0438 \u0432 \u0441\u043f\u0438\u0441\u043e\u043a \u0438 \u043c\u044b \u043d\u0435 \u0445\u043e\u0442\u0438\u043c \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0442\u044c \u0443 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u0437\u0431\u044b\u0442\u043e\u0447\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e, \u0442\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u044d\u0442\u0438\u0445 \u043f\u043e\u043b\u0435\u0439 \u0434\u043e\u043b\u0436\u043d\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u044d\u0442\u0430\u043f\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u0443\u0436\u0435 \u043f\u043e\u0441\u043b\u0435 \u0432\u044b\u0437\u043e\u0432\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <em>_filterRecords<\/em>. \u041d\u043e \u0432 \u0442\u0430\u043a\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0437\u0430 \u0432\u0440\u0435\u043c\u044f, \u043f\u043e\u043a\u0430 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u0441\u0432\u044f\u0437\u043d\u044b\u0445 \u043f\u043e\u043b\u0435\u0439, \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u0441\u043f\u0438\u0441\u043a\u0430 \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c\u0441\u044f \u0438 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0430\u043a\u0442\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441\u043f\u0438\u0441\u043a\u0430 \u0431\u0443\u0434\u0435\u0442 \u043d\u0435 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u043d\u043e\u0432\u043e\u043c\u0443 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u043c\u0443 \u0441\u043f\u0438\u0441\u043a\u0430. \u042d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u0432\u0435\u0441\u0442\u0438 \u043a \u0434\u0443\u0431\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e \u0437\u0430\u043f\u0438\u0441\u0435\u0439. \u0427\u0442\u043e\u0431\u044b \u044d\u0442\u043e\u0433\u043e \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u0440\u0435\u0434\u043e\u0442\u0432\u0440\u0430\u0442\u0438\u0442\u044c \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e\u0435 \u0438\u0441\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0441\u043f\u0438\u0441\u043a\u0430 \u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u0432\u044f\u0437\u043d\u044b\u0445 \u043f\u043e\u043b\u0435\u0439. \u042d\u0442\u043e \u0431\u0443\u0434\u0435\u043c \u0434\u0435\u043b\u0430\u0442\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 <em>synchronized<\/em>.<\/p>\n<p>\u0412 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u0437\u0430\u043f\u0438\u0441\u044f\u043c\u0438 \u0441\u043f\u0438\u0441\u043a\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 <em>isFavourite<\/em>. \u0414\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u044d\u0442\u043e\u0433\u043e \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 \u043a \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0443 \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<figure class=\"bordered\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/959\/c86\/417\/959c86417dd6cd4cc8fc665b973cd5bc.png\" alt=\"\" title=\"\" width=\"320\" height=\"569\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/959\/c86\/417\/959c86417dd6cd4cc8fc665b973cd5bc.png\"\/><figcaption><\/figcaption><\/figure>\n<p><a href=\"https:\/\/github.com\/astoniocom\/fl_list_example\/tree\/related\" rel=\"noopener noreferrer nofollow\">\u041e\u0442\u043a\u0440\u044b\u0442\u044c \u043a\u043e\u0434 \u043d\u0430 GitHub<\/a><\/p>\n<h4>pubspec.yaml<\/h4>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0439 \u043f\u0430\u043a\u0435\u0442 \u0432 \u0444\u0430\u0439\u043b <em>pubspec.yaml<\/em> \u0438 \u0432 \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u043c <em>flutter pub get<\/em>.<\/p>\n<pre><code class=\"yaml\">dependencies:   synchronized: ^3.0.0   ... <\/code><\/pre>\n<h4>models.dart<\/h4>\n<p>\u0412 \u0444\u0430\u0439\u043b <em>models.dart<\/em> \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043c\u043e\u0434\u0435\u043b\u044c \u043d\u043e\u0432\u043e\u0433\u043e \u0442\u0438\u043f\u0430 \u0437\u0430\u043f\u0438\u0441\u0438.<\/p>\n<pre><code class=\"dart\">\/* file: models.dart *\/  ... class ExtendedExampleRecord {   final ExampleRecord base; \/\/ 1   final bool isFavourite;    const ExtendedExampleRecord({required this.base, required this.isFavourite});    \/\/ 2   ID get id => base.id;   int get weight => base.weight;   String get title => base.title; } ... <\/code><\/pre>\n<p>\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043a\u043e\u0434\u0430:<\/p>\n<ol>\n<li>\n<p>\u041f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u0445\u0440\u0430\u043d\u0438\u0442 \u043e\u0431\u044a\u0435\u043a\u0442 \u0431\u0430\u0437\u043e\u0432\u043e\u0439 \u0437\u0430\u043f\u0438\u0441\u0438, \u0441 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043c\u044b \u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0438 \u0440\u0430\u043d\u0435\u0435. \u0427\u0442\u043e\u0431\u044b \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u0434\u0443\u0431\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0442\u0438\u043f\u043e\u0432 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u043a\u043b\u0430\u0441\u0441\u0430, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043c\u0435\u0442\u043e\u0434\u0438\u043a\u0430 \u043a\u043e\u043c\u0431\u0438\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u043a\u043b\u0430\u0441\u0441\u0430 \u0432\u043c\u0435\u0441\u0442\u043e \u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u044f. \u0422\u0430\u043a\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u0443\u0434\u043e\u0431\u0435\u043d \u043f\u0440\u0438 \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 \u043a\u043b\u0430\u0441\u0441\u0430\u043c\u0438, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u043c\u0438 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445.<\/p>\n<\/li>\n<li>\n<p>\u0414\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0430\u0434\u0430\u043f\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0443\u0436\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0439 \u0432 \u043d\u0430\u0448\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u043a\u043e\u0434 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043d\u043e\u0432\u043e\u0439 \u043c\u043e\u0434\u0435\u043b\u044c\u044e, \u0434\u0435\u043b\u0430\u0435\u043c \u043d\u043e\u0432\u0443\u044e \u043c\u043e\u0434\u0435\u043b\u044c \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u043e\u0439 \u0441 <em>ExampleRecord<\/em>. \u042d\u0442\u043e \u0441\u0434\u0435\u043b\u0430\u043d\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438 \u0438 \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u043d\u0435 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e.<\/p>\n<\/li>\n<\/ol>\n<h4>repository.dart<\/h4>\n<p>\u0412 \u043a\u043b\u0430\u0441\u0441 <em>MockRepository<\/em> \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0443\u044e \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u044b \u0437\u0430\u043f\u0438\u0441\u0435\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0438\u0437\u0431\u0440\u0430\u043d\u043d\u044b\u043c\u0438.<\/p>\n<pre><code class=\"dart\">\/* file: repository.dart *\/   ...   final Set&lt;ID> _favourites = List.generate(kRecordsToGenerate ~\/ 3, (_) => Random().nextInt(kRecordsToGenerate)).toSet();   ... <\/code><\/pre>\n<p>\u0412 \u044d\u0442\u043e\u0442 \u0436\u0435 \u043a\u043b\u0430\u0441\u0441 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u0437 \u0442\u043e\u043b\u044c\u043a\u043e \u0447\u0442\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u043e\u0439 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439.<\/p>\n<pre><code class=\"dart\">\/* file: repository.dart *\/    ...   \/\/ 1   Future&lt;List&lt;ID>> getFavourites(Iterable&lt;ID> idsToCheck) async {     return idsToCheck.where((id) => _favourites.contains(id)).toList();   }    \/\/ 2   Future&lt;List&lt;ExtendedExampleRecord>> extendRecords(Iterable&lt;ExampleRecord> records) async {     final idsToResolve = records.map((r) => r.id);     final favouriteIds = await getFavourites(idsToResolve); \/\/ 3     return records         .map((r) => ExtendedExampleRecord(               base: r,               isFavourite: favouriteIds.contains(r.id),             ))         .toList();   }   ...  <\/code><\/pre>\n<p>\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043a\u043e\u0434\u0430:<\/p>\n<ol>\n<li>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442, \u043a\u0430\u043a\u0438\u0435 \u0438\u0437 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u0432 \u0441\u043f\u0438\u0441\u043a\u0430 <em>idsToCheck<\/em> \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u0432 \u0438\u0437\u0431\u0440\u0430\u043d\u043d\u043e\u043c.<\/p>\n<\/li>\n<li>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u0435\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u0437\u0430\u043f\u0438\u0441\u0435\u0439 <em>ExampleRecord<\/em> \u0432 <em>ExtendedExampleRecord<\/em>.<\/p>\n<\/li>\n<li>\n<p>\u0414\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u043d\u0430\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e\u043c \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0439 \u043a \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0443 \u0434\u0430\u043d\u043d\u044b\u0445, \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f <em>isFavourite<\/em> \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u0437\u0430\u043f\u0438\u0441\u0435\u0439, \u0430 \u043f\u043e\u0442\u043e\u043c \u0438\u0445 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0434\u043b\u044f \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 <em>ExtendedExampleRecord<\/em>.<\/p>\n<\/li>\n<\/ol>\n<h4>list_state.dart<\/h4>\n<p>\u0412 \u043a\u043b\u0430\u0441\u0441\u0435 <em>ListState<\/em> \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u0441\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435, \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u044b\u0435 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0442\u0438\u043f\u0430 <em>ExampleRecord<\/em>, \u0437\u0430\u043c\u0435\u043d\u0438\u0442\u044c \u043d\u0430 <em>ExtendedExampleRecord<\/em>.<\/p>\n<h4>list_controller.dart<\/h4>\n<p>\u0412 \u043a\u043e\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u0441\u043f\u0438\u0441\u043a\u0430 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0438\u043c\u043f\u043e\u0440\u0442 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 synchronized: <em>import &#8216;package:synchronized\/synchronized.dart&#8217;<\/em>.<\/p>\n<p>\u0412 \u043a\u043b\u0430\u0441\u0441\u0435 <em>_ListChange<\/em> \u0442\u0430\u043a\u0436\u0435 \u0437\u0430\u043c\u0435\u043d\u0438\u043c <em>ExampleRecord<\/em> \u043d\u0430 <em>ExtendedExampleRecord<\/em> \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 recordsToRemove.<\/p>\n<pre><code class=\"dart\">\/* list_controller.dart *\/   ...   final Iterable&lt;ExampleRecord> recordsToRemove; \/\/ -   final Iterable&lt;ExtendedExampleRecord> recordsToRemove; \/\/ +   ... <\/code><\/pre>\n<p>\u0422\u043e \u0436\u0435 \u0441\u0430\u043c\u043e\u0435 \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 <em>records<\/em> \u043a\u043b\u0430\u0441\u0441\u0430 <em>_FetchRecordsResult<\/em>.<\/p>\n<pre><code class=\"dart\">\/* list_controller.dart *\/   ...   final List&lt;ExampleRecord> records; \/\/ -   final List&lt;ExtendedExampleRecord> records; \/\/ +   ... <\/code><\/pre>\n<p>\u0412 \u043a\u043b\u0430\u0441\u0441\u0435 <em>ListController<\/em> \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043e\u0431\u044a\u0435\u043a\u0442, \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0431\u0443\u0434\u0443\u0442 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0440\u0430\u0437\u043d\u044b\u0435 \u0443\u0447\u0430\u0441\u0442\u043a\u0438 \u043a\u043e\u0434\u0430:<\/p>\n<pre><code class=\"dart\">\/* file: list_controller.dart *\/   ...   final lock = Lock();   ... <\/code><\/pre>\n<p>\u0421\u0435\u0439\u0447\u0430\u0441 \u0432 \u044d\u0442\u043e\u043c \u0436\u0435 \u0444\u0430\u0439\u043b\u0435 \u043d\u0430\u0434\u043e \u043d\u0430\u0439\u0442\u0438 \u0441\u0442\u0440\u043e\u043a\u0438:<\/p>\n<pre><code class=\"dart\">\/* file: list_controller.dart *\/          .map((change) {           final result = List.of(value.records)..removeWhere((r) => change.recordsToRemove.contains(r));           return result..insertAll(0, change.recordsToInsert);         }) <\/code><\/pre>\n<p>\u0438 \u0437\u0430\u043c\u0435\u043d\u0438\u0442\u044c \u0438\u0445 \u043d\u0430:<\/p>\n<pre><code class=\"dart\">\/* file: list_controller.dart *\/          .asyncMap((change) async {           return lock.synchronized(() async { \/\/ 1             final result = List.of(value.records)..removeWhere((r) => change.recordsToRemove.contains(r));             return result..insertAll(0, await MockRepository().extendRecords(change.recordsToInsert)); \/\/ 2           });         }) <\/code><\/pre>\n<p>\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043a\u043e\u0434\u0430:<\/p>\n<ol>\n<li>\n<p>\u041e\u0431\u043e\u0437\u043d\u0430\u0447\u0430\u0435\u043c \u043e\u0431\u043b\u0430\u0441\u0442\u044c \u043a\u043e\u0434\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0435 \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e \u0441 \u0434\u0440\u0443\u0433\u0438\u043c \u043a\u043e\u0434\u043e\u043c, \u043f\u043e\u043c\u0435\u0447\u0435\u043d\u043d\u044b\u043c \u0442\u0430\u043a\u0438\u043c \u0436\u0435 \u043e\u0431\u0440\u0430\u0437\u043e\u043c.<\/p>\n<\/li>\n<li>\n<p>\u0421\u0442\u0440\u043e\u043a\u0430 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043e\u0442 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u043f\u043e\u043b\u0435\u0439. \u041e\u043d\u0430 \u0438 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0433\u043b\u0430\u0432\u043d\u044b\u043c \u0432\u0438\u043d\u043e\u0432\u043d\u0438\u043a\u043e\u043c \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<\/li>\n<\/ol>\n<p>\u041e\u0431\u044a\u0435\u043a\u0442 <em>ExampleRecordQuery<\/em> \u043c\u043e\u0436\u0435\u0442 \u0441\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0437\u0430\u043f\u0438\u0441\u0438 \u0442\u0438\u043f\u0430 <em>ExampleRecord<\/em>, \u0430 \u043c\u044b \u043f\u043e\u043c\u0435\u043d\u044f\u043b\u0438 \u0442\u0438\u043f \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u0441\u043f\u0438\u0441\u043a\u0430 \u043d\u0430 <em>ExtendedExampleRecord<\/em>, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0440\u0438\u0434\u0451\u0442\u0441\u044f \u043f\u043e\u0434\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0432\u044b\u0437\u043e\u0432 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438 \u0437\u0430\u043f\u0438\u0441\u0435\u0439.<\/p>\n<pre><code class=\"dart\">\/* file: list_controller.dart *\/    ...   .map((updatedList) {     \/\/ return updatedList..sort(query.compareRecords); \/\/ -     return updatedList..sort((r1, r2) => query.compareRecords(r1.base, r2.base)); \/\/ +   })   ... <\/code><\/pre>\n<p>\u0422\u0430\u043a \u043a\u0430\u043a \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u043d\u0430 \u0437\u0430\u043f\u0440\u043e\u0441 <em>queryRecords<\/em> \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0437\u0430\u043f\u0438\u0441\u0438 \u0442\u0438\u043f\u0430 <em>ExampleRecord<\/em>, \u0430 \u0441\u043f\u0438\u0441\u043e\u043a \u0434\u043e\u043b\u0436\u0435\u043d \u0441\u043e\u0441\u0442\u043e\u044f\u0442\u044c \u0438\u0437 <em>ExtendedExampleRecord<\/em>, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 <em>ExtendedExampleRecord<\/em>.<\/p>\n<pre><code class=\"dart\">\/* file: list_controller.dart *\/   ...   Future&lt;_FetchRecordsResult> fetchRecords(ExampleRecordQuery? query) async {     final loadedRecords = await MockRepository().queryRecords(query);     \/\/ return _FetchRecordsResult(records: loadedRecords, loadedAllRecords: loadedRecords.length &lt; kBatchSize); \/\/ -     return _FetchRecordsResult(records: await MockRepository().extendRecords(loadedRecords), \/\/ +                                loadedAllRecords: loadedRecords.length &lt; kBatchSize); \/\/ +   }   ... <\/code><\/pre>\n<p>\u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0437\u0430\u043f\u0440\u0435\u0442\u0438\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <em>loadRecords<\/em> \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e \u0441 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u043c \u0430\u043a\u0442\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0441\u043f\u0438\u0441\u043a\u0430 \u0438 \u043d\u0430\u043e\u0431\u043e\u0440\u043e\u0442.<\/p>\n<pre><code class=\"dart\">\/* file: list_controller.dart *\/   ...   Future&lt;void> loadRecords({ExampleRecordQuery? query, required bool replace}) async {     if (value.isLoading) return;     lock.synchronized(() async { \/\/ +      ...     }); \/\/ +   }   ... <\/code><\/pre>\n<h4>record_teaser.dart<\/h4>\n<p>\u0412 \u043a\u043b\u0430\u0441\u0441\u0435 \u0432\u0438\u0434\u0436\u0435\u0442\u0430 \u0442\u0438\u0437\u0435\u0440\u0430 <em>RecordTeaser<\/em> \u0438\u0437\u043c\u0435\u043d\u0438\u043c \u0442\u0438\u043f \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u0441\u043f\u0438\u0441\u043a\u0430 \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u0441\u043f\u0438\u0441\u043a\u0430 \u0434\u0440\u0443\u0433\u0438\u043c \u0446\u0432\u0435\u0442\u043e\u043c, \u0435\u0441\u043b\u0438 \u0437\u0430\u043f\u0438\u0441\u044c \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u0438\u0437\u0431\u0440\u0430\u043d\u043d\u043e\u043c:<\/p>\n<pre><code class=\"dart\">\/* file: record_teaser.dart *\/  class RecordTeaser extends StatelessWidget {   final ExampleRecord record; \/\/ -   final ExtendedExampleRecord record; \/\/ +    ...    return ListTile(     selected: record.isFavourite, \/\/ +     title: Text(record.title),     ... <\/code><\/pre>\n<p><a class=\"anchor\" name=\"list_update_records\" id=\"list_update_records\"><\/a><\/p>\n<h2>\u0421\u043f\u0438\u0441\u043e\u043a \u0438\u0437 \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c\u044b\u0445 \u0437\u0430\u043f\u0438\u0441\u0435\u0439<\/h2>\n<figure class=\"bordered\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/648\/b7b\/c94\/648b7bc94320a98faf1ecc2485516bcf.gif\" alt=\"\" title=\"\" width=\"320\" height=\"569\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/648\/b7b\/c94\/648b7bc94320a98faf1ecc2485516bcf.gif\"\/><figcaption><\/figcaption><\/figure>\n<p><a href=\"https:\/\/github.com\/astoniocom\/fl_list_example\/tree\/cubit\" rel=\"noopener noreferrer nofollow\">\u041e\u0442\u043a\u0440\u044b\u0442\u044c \u043a\u043e\u0434 \u043d\u0430 GitHub<\/a><\/p>\n<p>\u0418\u043d\u043e\u0433\u0434\u0430 \u043e\u0447\u0435\u043d\u044c \u0443\u0434\u043e\u0431\u043d\u043e \u043f\u043e\u0440\u0443\u0447\u0438\u0442\u044c \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u043d\u0435 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0443 \u0441\u043f\u0438\u0441\u043a\u0430, \u0430 \u0441\u0430\u043c\u043e\u0439 \u0437\u0430\u043f\u0438\u0441\u0438. \u041f\u043e \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0438 \u0441 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u043e\u0439 Bloc \u044f \u043d\u0430\u0437\u044b\u0432\u0430\u044e \u0442\u0430\u043a\u0438\u0435 \u0437\u0430\u043f\u0438\u0441\u0438 \u043a\u0443\u0431\u0438\u0442\u0430\u043c\u0438. \u0421\u043c\u044b\u0441\u043b \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u043a\u0443\u0431\u0438\u0442 \u0432\u0441\u0435\u0433\u0434\u0430 \u0434\u043e\u043b\u0436\u0435\u043d \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u0443\u044e \u0437\u0430\u043f\u0438\u0441\u044c. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043a\u0443\u0431\u0438\u0442 \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0435\u0442 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u043c\u0435\u043d\u044f\u0435\u0442 \u0441\u0432\u043e\u0451 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435, \u0435\u0441\u043b\u0438 \u0437\u0430\u043f\u0438\u0441\u044c \u0438\u0437\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f. \u0422\u0430\u043a\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u0443\u0434\u043e\u0431\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c, \u043a\u043e\u0433\u0434\u0430 \u0437\u0430\u043f\u0438\u0441\u0438 \u043d\u0435 \u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u0447\u0430\u0441\u0442\u043e, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432 \u0441\u043f\u0438\u0441\u043a\u0430\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439. \u041d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u043c \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043a\u043e\u043c \u0442\u0430\u043a\u043e\u0433\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0430 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0442\u043e, \u0447\u0442\u043e \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0430 \u0441\u043f\u0438\u0441\u043a\u0430 \u043f\u0440\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u0432\u0435\u0441\u0430 \u0437\u0430\u043f\u0438\u0441\u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043d\u0435 \u0431\u0443\u0434\u0435\u0442. \u042d\u0442\u0430 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0440\u0435\u0448\u0430\u0435\u043c\u0430, \u043e\u0434\u043d\u0430\u043a\u043e \u043d\u0435 \u0430\u0434\u0440\u0435\u0441\u0443\u0435\u0442\u0441\u044f \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438.<\/p>\n<h4>record_cubit.dart<\/h4>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0444\u0430\u0439\u043b record_cubit.dart \u0441\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435\u043c:<\/p>\n<pre><code class=\"dart\">\/* file: record_cubit.dart *\/  import 'dart:async';  import 'package:fl_list_example\/models.dart'; import 'package:fl_list_example\/repository.dart'; import 'package:flutter\/foundation.dart';  class ExampleRecordCubit extends ValueNotifier {   late StreamSubscription _changesSubscription;    ExampleRecordCubit(ExampleRecord initState) : super(initState) {     \/\/ 1     _changesSubscription = MockRepository()         .rawEvents         .where((event) => event is RecordUpdatedEvent &amp;&amp; event.id == value.id)         .asyncMap((event) => MockRepository().getByIds([event.id]).then((value) => value.first))         .listen((event) => value = event);   }    \/\/ 2   ID get id => value.id;   int get weight => value.weight;   String get title => value.title;    \/\/ 3   close() => _changesSubscription.cancel();  } <\/code><\/pre>\n<p>\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043a\u043e\u0434\u0430:<\/p>\n<ol>\n<li>\n<p>\u041f\u043e\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c\u0441\u044f \u043d\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0438\u0441\u0438. \u0415\u0441\u043b\u0438 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u0435\u0442 \u0441 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u043c \u0437\u0430\u043f\u0438\u0441\u0438 \u0432 <em>value<\/em>, \u0437\u043d\u0430\u0447\u0438\u0442, \u043a\u0443\u0431\u0438\u0442 \u0434\u043e\u043b\u0436\u0435\u043d \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u0441\u0432\u043e\u0451 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435, \u0437\u0430\u043f\u0438\u0441\u0430\u0432 \u043d\u043e\u0432\u0443\u044e \u0437\u0430\u043f\u0438\u0441\u044c \u0432 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e <em>value<\/em>.<\/p>\n<\/li>\n<li>\n<p>\u0414\u043b\u044f \u0442\u0435\u0445 \u0436\u0435 \u0446\u0435\u043b\u0435\u0439, \u043a\u0430\u043a \u044d\u0442\u043e \u0431\u044b\u043b\u043e \u0440\u0430\u043d\u0435\u0435, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0430\u0434\u0430\u043f\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0443\u0436\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0439 \u043a\u043e\u0434 \u0432 \u043d\u0430\u0448\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438, \u0434\u0435\u043b\u0430\u0435\u043c <em>ExampleRecordCubit<\/em> \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u044b\u043c \u0441 <em>ExampleRecord<\/em>.<\/p>\n<\/li>\n<li>\n<p>\u0422\u0430\u043a \u043a\u0430\u043a \u043a\u0443\u0431\u0438\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0443 \u043d\u0430 \u043f\u043e\u0442\u043e\u043a \u0441\u043e\u0431\u044b\u0442\u0438\u0439, \u0432 \u0441\u043b\u0443\u0447\u0430\u0435, \u0435\u0441\u043b\u0438 \u0437\u0430\u043f\u0438\u0441\u044c \u0431\u043e\u043b\u0435\u0435 \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f, \u043e\u043d \u0434\u043e\u043b\u0436\u0435\u043d \u043e\u0442\u043c\u0435\u043d\u0438\u0442\u044c \u044d\u0442\u0443 \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0443.<\/p>\n<\/li>\n<\/ol>\n<h4>lib\/list_state.dart<\/h4>\n<p>\u0417\u0430\u043c\u0435\u043d\u0438\u043c \u0432 \u0444\u0430\u0439\u043b\u0435 <em>lib\/list_state.dart<\/em> \u0438\u043c\u043f\u043e\u0440\u0442 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 <em>import &#8216;package:fl_list_example\/models.dart&#8217;<\/em> \u043d\u0430 <em>import &#8216;package:fl_list_example\/record_cubit.dart&#8217;<\/em>, \u0442\u0430\u043a \u0436\u0435 \u0437\u0430\u043c\u0435\u043d\u0438\u043c \u0432\u0441\u0435 \u0442\u0438\u043f\u044b <em>ExtendedExampleRecord<\/em> \u043d\u0430 <em>ExampleRecordCubit<\/em>.<\/p>\n<h4>list_controller.dart<\/h4>\n<p>\u0412 \u043d\u0430\u0447\u0430\u043b\u0435 \u0444\u0430\u0439\u043b\u0430 <em>list_controller.dart<\/em> \u0434\u043e\u0431\u0430\u0432\u0438\u043c <em>import &#8216;package:fl_list_example\/record_cubit.dart&#8217;<\/em>.<\/p>\n<p>\u0412 \u043a\u043b\u0430\u0441\u0441\u0435 <em>_ListChange<\/em> \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 <em>recordsToRemove<\/em> \u0443\u043a\u0430\u0436\u0435\u043c \u0442\u0438\u043f <em>Iterable&lt;ExampleRecordCubit><\/em>.<\/p>\n<p>\u0412 \u043a\u043b\u0430\u0441\u0441\u0435 <em>_FetchRecordsResult<\/em> \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 records \u0443\u043a\u0430\u0436\u0435\u043c \u0442\u0438\u043f <em>List&lt;ExampleRecordCubit><\/em>.<\/p>\n<p>\u0418\u0441\u043a\u043b\u044e\u0447\u0438\u043c \u0438\u0437 \u043a\u043e\u0434\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439 \u043e\u0431 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044f\u0445 \u043d\u0430\u0434 \u0437\u0430\u043f\u0438\u0441\u044f\u043c\u0438 \u0443\u0447\u0430\u0441\u0442\u043a\u0438, \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0435 \u0441 \u0430\u043a\u0442\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0435\u0439 \u0441\u043f\u0438\u0441\u043a\u0430 \u0432 \u0432\u0438\u0434\u0443 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0432 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0435 \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<pre><code class=\"dart\">\/* file: list_controller.dart *\/      ...     _changesSubscription = MockRepository()         .rawEvents         .where((event) => value.isInitialized)         .bufferTime(const Duration(milliseconds: 300))         .where((event) => event.isNotEmpty)         .asyncMap((event) async {           \/\/ 1           final createdIds = event.whereType&lt;RecordCreatedEvent>().map((e) => e.id);           \/\/ final updatedIds = event.whereType&lt;RecordUpdatedEvent>().map((e) => e.id) \/\/ -           \/\/ final idsToResolve = {...createdIds, ...updatedIds}; \/\/ -           final resolvedRecords = (await MockRepository().getByIds(createdIds)).toSet();            return RecordsUpdates(             insertedRecords: resolvedRecords.where((r) => createdIds.contains(r.id)).toSet(),             \/\/ updatedRecords: resolvedRecords.where((r) => updatedIds.contains(r.id)).toSet(), \/\/ -             updatedRecords: {}, \/\/ +             deletedKeys: event.whereType&lt;RecordDeletedEvent>().map((e) => e.id).toSet(),           );         })         .map(_filterRecords)         .where((event) => event.recordsToInsert.isNotEmpty || event.recordsToRemove.isNotEmpty)         \/\/ .asyncMap((change) async { \/\/ 2         \/\/   return lock.synchronized(() async {         \/\/     final result = List.of(state.records)..removeWhere((r) => change.recordsToRemove.contains(r));         \/\/     return result..insertAll(0, await MockRepository().extendRecords(change.recordsToInsert));         \/\/   });         \/\/ }         .map((change) {           change.recordsToRemove.forEach((r) => r.close()); \/\/ 3           final result = List.of(value.records)..removeWhere((r) => change.recordsToRemove.contains(r));           return result..insertAll(0, change.recordsToInsert.map((r) => ExampleRecordCubit(r)));         })         .map((updatedList) {           return updatedList..sort((r1, r2) => query.compareRecords(r1.value, r2.value)); \/\/ *         })         .listen((updatedList) {           value = value.copyWith(records: updatedList);         });         ...  <\/code><\/pre>\n<p>\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043a\u043e\u0434\u0430:<\/p>\n<ol>\n<li>\n<p>\u041f\u0435\u0440\u0435\u0441\u0442\u0430\u0451\u043c \u0430\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043b\u044e\u0431\u044b\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0438\u0441\u0435\u0439, \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u0430\u043d\u0430\u043b\u0438\u0437 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0438\u0441\u0435\u0439.<\/p>\n<\/li>\n<li>\n<p>\u0423\u0431\u0438\u0440\u0430\u0435\u043c \u0447\u0430\u0441\u0442\u044c, \u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u0443\u044e \u0437\u0430 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0443 \u0441\u0432\u044f\u0437\u043d\u044b\u0445 \u0437\u0430\u043f\u0438\u0441\u0435\u0439.<\/p>\n<\/li>\n<li>\n<p>\u0423 \u043a\u0443\u0431\u0438\u0442\u043e\u0432, \u0437\u0430\u043f\u0438\u0441\u0438 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0431\u044b\u043b\u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u044b \u0438 \u0431\u0443\u0434\u0443\u0442 \u0443\u0431\u0440\u0430\u043d\u044b \u0438\u0437 \u0441\u043f\u0438\u0441\u043a\u0430, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u044b\u0437\u0432\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e <em>close<\/em>. \u042d\u0442\u0438\u043c \u043a\u0443\u0431\u0438\u0442\u044b \u043e\u0442\u043f\u0438\u0448\u0443\u0442\u0441\u044f \u043e\u0442 \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u044f \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0437\u0430\u043f\u0438\u0441\u0435\u0439, \u0437\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u043d\u0438 \u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u044b.<\/p>\n<\/li>\n<\/ol>\n<p>\u0412 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u0438\u0437 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043a\u043e\u0434 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u044f <em>ExampleRecord<\/em> \u0432 <em>ExampleRecordCubit<\/em>.<\/p>\n<pre><code class=\"dart\">  \/* list_controller.dart *\/   Future&lt;_FetchRecordsResult> fetchRecords(ExampleRecordQuery? query) async {     final loadedRecords = await MockRepository().queryRecords(query);     return _FetchRecordsResult(         records: loadedRecords.map((r) => ExampleRecordCubit(r)).toList(), \/\/ *         loadedAllRecords: loadedRecords.length &lt; kBatchSize);   } <\/code><\/pre>\n<p>\u0412 \u043a\u043b\u0430\u0441\u0441 <em>ListController<\/em> \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043c\u0435\u0442\u043e\u0434 <em>_closeAllRecords<\/em>. \u041e\u043d \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u0432\u0441\u0435\u0445 \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u0438\u0437 \u0441\u043f\u0438\u0441\u043a\u0430 \u043b\u0438\u0431\u043e \u043f\u0435\u0440\u0435\u0434 \u0443\u043d\u0438\u0447\u0442\u043e\u0436\u0435\u043d\u0438\u0435\u043c \u0441\u0430\u043c\u043e\u0433\u043e \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430.<\/p>\n<pre><code class=\"dart\">\/* list_controller.dart *\/   ...   _closeAllRecords() {     value.records.every((r) => r.close());    }   ...  <\/code><\/pre>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0432\u044b\u0437\u043e\u0432 \u0442\u043e\u043b\u044c\u043a\u043e \u0447\u0442\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u043c\u0435\u0442\u043e\u0434\u0430 <em>_closeAllRecords<\/em> \u0432 \u043c\u0435\u0442\u043e\u0434\u044b <em>dispose<\/em> \u0438 <em>loadRecords<\/em>.<\/p>\n<pre><code class=\"dart\">\/* file: list_controller.dart *\/    @override   void dispose() {     _closeAllRecords(); \/\/ +     _changesSubscription.cancel();     super.dispose();   } <\/code><\/pre>\n<pre><code class=\"dart\">\/* file: list_controller.dart *\/    ...   final fetchResult = await fetchRecords(query);    if (replace) _closeAllRecords(); \/\/ +    final records = [   ... <\/code><\/pre>\n<h4>widgets\/record_teaser.dart<\/h4>\n<p>\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u043c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0432 \u0444\u0430\u0439\u043b <em>widgets\/record_teaser.dart<\/em>:<\/p>\n<pre><code class=\"dart\">\/* file: widgets\/record_teaser.dart *\/  import 'package:fl_list_example\/record_cubit.dart'; import 'package:provider\/provider.dart'; ... <\/code><\/pre>\n<p>\u0422\u0438\u043f \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 <em>record<\/em> \u043a\u043b\u0430\u0441\u0441\u0430 <em>RecordTeaser<\/em> \u043c\u0435\u043d\u044f\u0435\u043c \u0441 <em>ExtendedExampleRecord<\/em> \u043d\u0430 <em>ExampleRecordCubit<\/em> \u0438 \u043c\u043e\u0434\u0438\u0444\u0438\u0446\u0438\u0440\u0443\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e <em>build<\/em>. \u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0439 \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0432\u0438\u0434\u0436\u0435\u0442 \u0442\u0438\u0437\u0435\u0440\u0430 \u0431\u0443\u0434\u0435\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437, \u043a\u043e\u0433\u0434\u0430 \u0438\u0437\u043c\u0435\u043d\u0438\u043b\u043e\u0441\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0432 \u043a\u0443\u0431\u0438\u0442\u0435.<\/p>\n<pre><code class=\"dart\">\/* file: widgets\/record_teaser.dart *\/    @override   Widget build(BuildContext context) {     return ChangeNotifierProvider.value( \/\/ +       value: record, \/\/ +       child: Builder(builder: (context) { \/\/ +         final record = context.watch&lt;ExampleRecordCubit>(); \/\/ +         return ListTile(           \/\/ selected: record.isFavourite, \/\/ *           title: Text(record.title),           subtitle: Text(\"weight: ${record.weight}\"),           trailing: Row(             mainAxisSize: MainAxisSize.min,             children: [               IconButton(onPressed: () => _createRecord(context), icon: const Icon(Icons.new_label)),               IconButton(onPressed: () => _updateRecord(context), icon: const Icon(Icons.edit)),               IconButton(onPressed: () => _deleteRecord(context), icon: const Icon(Icons.delete)),             ],           ),         );       }), \/\/ +     ); \/\/ +   } <\/code><\/pre>\n<p><a class=\"anchor\" name=\"conclusion\" id=\"conclusion\"><\/a><\/p>\n<h2>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h2>\n<p>\u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u043f\u0440\u0438\u0432\u0451\u043b \u043f\u0440\u0438\u043c\u0435\u0440\u044b \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u044e \u0440\u0430\u0431\u043e\u0442\u0443 \u0441\u043e \u0441\u043f\u0438\u0441\u043a\u0430\u043c\u0438 \u0432 \u0441\u0432\u043e\u0438\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445. \u0414\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u043d\u0430 \u043f\u0435\u0440\u0432\u044b\u0439 \u0432\u0437\u0433\u043b\u044f\u0434\u0430 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0437 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u043d\u044b\u0445 \u0440\u0435\u0448\u0435\u043d\u0438\u0439 \u043c\u043e\u0433\u0443\u0442 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u0441\u043b\u043e\u0436\u043d\u044b\u043c\u0438, \u043d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u043e\u043d\u0438 \u043e\u0447\u0435\u043d\u044c \u043f\u0440\u043e\u0441\u0442\u044b \u0432 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438. \u0412 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445 \u044f \u0441\u043e\u0437\u0434\u0430\u044e \u043d\u0430\u0431\u043e\u0440 \u0431\u0430\u0437\u043e\u0432\u044b\u0445 \u043a\u043b\u0430\u0441\u0441\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u044e\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u0438\u0437 \u0441\u0442\u0430\u0442\u044c\u0438, \u043d\u043e \u0441 \u0443\u0447\u0451\u0442\u043e\u043c \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0435\u0439 \u043f\u0440\u043e\u0435\u043a\u0442\u0430. \u041d\u0430 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0438 \u044d\u0442\u0438\u0445 \u0431\u0430\u0437\u043e\u0432\u044b\u0445 \u043a\u043b\u0430\u0441\u0441\u043e\u0432 \u043c\u043e\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0438 \u043f\u043e\u043d\u044f\u0442\u043d\u044b\u0439 \u043a\u043e\u0434. <\/p>\n<p>\u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044e \u0437\u0430 \u043f\u0440\u043e\u0447\u0442\u0435\u043d\u0438\u0435 \u0441\u0442\u0430\u0442\u044c\u0438. \u0411\u0443\u0434\u0443 \u043f\u0440\u0438\u0437\u043d\u0430\u0442\u0435\u043b\u0435\u043d \u043b\u044e\u0431\u044b\u043c \u0437\u0430\u043c\u0435\u0447\u0430\u043d\u0438\u044f\u043c, \u0441\u043e\u0432\u0435\u0442\u0430\u043c \u0438 \u0432\u043e\u043f\u0440\u043e\u0441\u0430\u043c.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"v-portal\" style=\"display:none;\"><\/div>\n<\/div>\n<p> <!----> <!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/post\/656297\/\"> https:\/\/habr.com\/ru\/post\/656297\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u0418\u043d\u043e\u0433\u0434\u0430 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u0442\u043e\u0431\u0440\u0430\u0437\u0438\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a c \u0434\u0430\u043d\u043d\u044b\u043c\u0438. \u0415\u0441\u043b\u0438 \u044d\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0441\u043f\u0438\u0441\u043e\u043a, \u043e\u043d \u0440\u0435\u0434\u043a\u043e \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u0438. \u041e\u0434\u043d\u0430\u043a\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0441\u043f\u0438\u0441\u043a\u043e\u0432, \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0434\u043e\u043b\u0436\u043d\u043e \u043c\u0435\u043d\u044f\u0442\u044c\u0441\u044f, \u0447\u0430\u0441\u0442\u043e \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442 \u043a \u043e\u0448\u0438\u0431\u043a\u0430\u043c, \u0441\u043b\u043e\u0436\u043d\u044b\u043c \u0434\u043b\u044f \u0432\u044b\u044f\u0432\u043b\u0435\u043d\u0438\u044f \u0438 \u043e\u0442\u043b\u0430\u0434\u043a\u0438.<\/p>\n<p>\u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0445\u043e\u0447\u0443 \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u0442\u044c \u043e \u0441\u0432\u043e\u0451\u043c \u043e\u043f\u044b\u0442\u0435 \u0440\u0430\u0431\u043e\u0442\u044b \u0441\u043e \u0441\u043f\u0438\u0441\u043a\u0430\u043c\u0438 \u0438 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u044e \u0432 \u043d\u0438\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0439 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438, \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u0438, \u0430\u043a\u0442\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u0434\u0440\u0443\u0433\u0438\u0435.<\/p>\n<p>\u0421\u0442\u0430\u0442\u044c\u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0430 \u0432 \u0432\u0438\u0434\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0438 \u0438 \u043e\u0440\u0438\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0430 \u043d\u0430 Flutter-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u0441 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u043c \u043e\u043f\u044b\u0442\u043e\u043c, \u0445\u043e\u0442\u044f, \u043d\u0430\u0434\u0435\u044e\u0441\u044c, \u0438 \u043e\u043f\u044b\u0442\u043d\u044b\u043c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c \u043e\u043d\u0430 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u0435\u0437\u043d\u0430. \u0414\u043b\u044f \u043b\u0443\u0447\u0448\u0435\u0433\u043e \u0443\u0441\u0432\u043e\u0435\u043d\u0438\u044f \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0430 \u0436\u0435\u043b\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0437\u043d\u0430\u0442\u044c \u043e\u0441\u043d\u043e\u0432\u044b \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u0438\u043c\u0435\u0442\u044c \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0439 \u043e\u043f\u044b\u0442 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u043e\u0439 rxdart, \u043f\u043e\u043d\u0438\u043c\u0430\u0442\u044c, \u043a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 ChangeNotifier.<\/p>\n<p>\u0412\u0437\u044f\u0432 \u0437\u0430 \u043e\u0441\u043d\u043e\u0432\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441 \u043f\u0440\u0438\u043c\u0438\u0442\u0438\u0432\u043d\u044b\u043c \u0441\u043f\u0438\u0441\u043a\u043e\u043c, \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u043d\u0430\u0440\u0430\u0449\u0438\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c, \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u044f \u043e\u0442 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0441\u0442\u044b\u0445 \u0438 \u0447\u0430\u0441\u0442\u044b\u0445 \u0437\u0430\u0434\u0430\u0447 \u043a \u0431\u043e\u043b\u0435\u0435 \u0441\u043b\u043e\u0436\u043d\u044b\u043c \u0438 \u0440\u0435\u0434\u043a\u0438\u043c. \u0427\u0442\u043e\u0431\u044b \u0443\u043c\u0435\u043d\u044c\u0448\u0438\u0442\u044c \u043e\u0431\u044a\u0451\u043c \u043a\u043e\u0434\u0430 \u0438 \u0443\u043f\u0440\u043e\u0441\u0442\u0438\u0442\u044c \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u0442\u0435\u043c\u044b, \u044f \u043d\u0435 \u0431\u0443\u0434\u0443 \u0431\u0440\u0430\u0442\u044c \u043a\u0430\u043a\u043e\u0439-\u0442\u043e \u043f\u0440\u0438\u043c\u0435\u0440 \u0438\u0437 \u0436\u0438\u0437\u043d\u0438, \u0430 \u0441\u043a\u043e\u043d\u0446\u0435\u043d\u0442\u0440\u0438\u0440\u0443\u044e\u0441\u044c \u043d\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0438 \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0421\u0442\u0430\u0442\u044c\u044f \u0440\u0430\u0437\u0431\u0438\u0442\u0430 \u043d\u0430 \u0447\u0430\u0441\u0442\u0438 \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0447\u0442\u043e \u043f\u043e \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0438 \u043f\u0440\u043e\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u043e\u0447\u0435\u0440\u0435\u0434\u043d\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u0432\u044b \u0431\u0443\u0434\u0435\u0442\u0435 \u0438\u043c\u0435\u0442\u044c \u0440\u0430\u0431\u043e\u0447\u0435\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435. \u0418\u0437-\u0437\u0430 \u0442\u0430\u043a\u043e\u0433\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0430 \u0447\u0438\u0442\u0430\u0442\u044c \u0441\u0442\u0430\u0442\u044c\u044e \u043c\u043e\u0436\u043d\u043e \u043d\u0435 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e, \u0430 \u043b\u0438\u0448\u044c \u0434\u043e \u043c\u043e\u043c\u0435\u043d\u0442\u0430 \u0441 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435\u043c \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b, \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u0439 \u0432\u0430\u043c. \u0412 \u043d\u0430\u0447\u0430\u043b\u0435 \u043a\u0430\u0436\u0434\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u0441\u0442\u0430\u0442\u044c\u0438 \u044f \u0431\u0443\u0434\u0443 \u0440\u0430\u0437\u043c\u0435\u0449\u0430\u0442\u044c \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 \u043a\u043e\u0434 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u0434\u0430\u043d\u043d\u043e\u0439 \u0447\u0430\u0441\u0442\u0438.<\/p>\n<h2>\u0421\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435<\/h2>\n<ol>\n<li>\n<p><a href=\"#terms\" rel=\"noopener noreferrer nofollow\">\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0430\u044f \u0442\u0435\u0440\u043c\u0438\u043d\u043e\u043b\u043e\u0433\u0438\u044f \u0438 \u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#struct\" rel=\"noopener noreferrer nofollow\">\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#prepare\" rel=\"noopener noreferrer nofollow\">\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#async\" rel=\"noopener noreferrer nofollow\">\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#filters\" rel=\"noopener noreferrer nofollow\">\u0424\u0438\u043b\u044c\u0442\u0440 \u0438 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0430<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#load_data\" rel=\"noopener noreferrer nofollow\">\u041f\u043e\u0440\u0446\u0438\u043e\u043d\u043d\u0430\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#actual\" rel=\"noopener noreferrer nofollow\">\u0410\u043a\u0442\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#work_list\" rel=\"noopener noreferrer nofollow\">\u0420\u0430\u0431\u043e\u0442\u0430 \u0441\u043e \u0441\u043f\u0438\u0441\u043a\u043e\u043c \u0437\u0430\u043f\u0438\u0441\u0435\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u0441\u044b\u043b\u0430\u044e\u0442\u0441\u044f \u043d\u0430 \u0434\u0440\u0443\u0433\u0438\u0435 \u0437\u0430\u043f\u0438\u0441\u0438<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#list_update_records\" rel=\"noopener noreferrer nofollow\">\u0421\u043f\u0438\u0441\u043e\u043a \u0438\u0437 \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c\u044b\u0445 \u0437\u0430\u043f\u0438\u0441\u0435\u0439<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#conclusion\" rel=\"noopener noreferrer nofollow\">\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/a><\/p>\n<\/li>\n<\/ol>\n<p><a class=\"anchor\" name=\"terms\" id=\"terms\"><\/a><\/p>\n<h2>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0430\u044f \u0442\u0435\u0440\u043c\u0438\u043d\u043e\u043b\u043e\u0433\u0438\u044f \u0438 \u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f<\/h2>\n<ul>\n<li>\n<p>\u0417\u0430\u043f\u0438\u0441\u044c \u2014 \u043e\u0431\u044a\u0435\u043a\u0442, \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0431\u0443\u0434\u0435\u0442 \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043e\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0438 \u0441\u043f\u0438\u0441\u043a\u0430;<\/p>\n<\/li>\n<li>\n<p>\u0422\u0438\u0437\u0435\u0440 \u2014 \u0433\u0440\u0430\u0444\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0437\u0430\u043f\u0438\u0441\u0438 \u0441\u043f\u0438\u0441\u043a\u0430;<\/p>\n<\/li>\n<li>\n<p>\u041a\u0443\u0431\u0438\u0442 \u2014 \u043e\u0431\u044a\u0435\u043a\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u0441\u0435\u0433\u0434\u0430 \u0445\u0440\u0430\u043d\u0438\u0442 \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0437\u0430\u043f\u0438\u0441\u0438 \u0441\u043f\u0438\u0441\u043a\u0430;<\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0441\u043f\u0438\u0441\u043a\u0430 \u2014 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u044b\u043c \u0441\u043f\u0438\u0441\u043a\u0430 \u0438 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435\u043c, \u043d\u0430 \u043a\u0430\u043a\u043e\u0439 \u0441\u0442\u0430\u0434\u0438\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u043e\u043d \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f;<\/p>\n<\/li>\n<li>\n<p>\u0418\u0441\u0442\u043e\u0447\u043d\u0438\u043a \u0434\u0430\u043d\u043d\u044b\u0445 \u2014 \u043b\u044e\u0431\u043e\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435, \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435. \u041c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043a\u0430\u043a \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u0430\u044f \u0432 \u044f\u0437\u044b\u043a \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u0430\u043d\u043d\u044b\u0445, \u0442\u0430\u043a \u0438 \u043b\u044e\u0431\u043e\u0439 \u0441\u0435\u0440\u0432\u0438\u0441, \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u0439 \u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0430 \u0437\u0430\u043f\u0440\u043e\u0441 \u043e\u0442 \u043a\u043b\u0438\u0435\u043d\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0411\u0430\u0437\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u2014 \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u0441\u0442\u0430\u0442\u044c\u0438 \u044d\u0442\u043e \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0445\u0440\u0430\u043d\u0438\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u0441 \u0437\u0430\u043f\u0438\u0441\u044f\u043c\u0438;<\/p>\n<\/li>\n<li>\n<p>\/\/ + \u2014 \u0441\u0442\u0440\u043e\u043a\u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0430;<\/p>\n<\/li>\n<li>\n<p>\/\/ &#8212; \u2014 \u0441\u0442\u0440\u043e\u043a\u0430 \u0443\u0434\u0430\u043b\u0435\u043d\u0430;<\/p>\n<\/li>\n<li>\n<p>\/\/ * \u2014 \u0441\u0442\u0440\u043e\u043a\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0430.<\/p>\n<\/li>\n<\/ul>\n<p><a class=\"anchor\" name=\"struct\" id=\"struct\"><\/a><\/p>\n<h2>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/h2>\n<ul>\n<li>\n<p>models.dart \u2014 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440 \u0434\u0430\u043d\u043d\u044b\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438;<\/p>\n<\/li>\n<li>\n<p>repository.dart \u2014 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u043d\u0438\u043c\u0438;<\/p>\n<\/li>\n<li>\n<p>list_state.dart \u2014 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u0430;<\/p>\n<\/li>\n<li>\n<p>list_controller.dart \u2014 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u043e\u043c;<\/p>\n<\/li>\n<li>\n<p>widgets\\record_teaser.dart \u2014 \u0432\u0438\u0434\u0436\u0435\u0442 \u0434\u043b\u044f \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0438\u0441\u0438 \u0441\u043f\u0438\u0441\u043a\u0430 (\u0442\u0438\u0437\u0435\u0440\u0430);<\/p>\n<\/li>\n<li>\n<p>widgets\\list_status_indicator.dart \u2014 \u0432\u0438\u0434\u0436\u0435\u0442 \u0434\u043b\u044f \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u0430;<\/p>\n<\/li>\n<li>\n<p>main.dart \u2014 \u0442\u043e\u0447\u043a\u0430 \u0432\u0445\u043e\u0434\u0430 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435.<\/p>\n<\/li>\n<\/ul>\n<p>\u0421\u043f\u0438\u0441\u043e\u043a \u0444\u0430\u0439\u043b\u043e\u0432 \u043e\u0442\u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d \u0432 \u043f\u043e\u0440\u044f\u0434\u043a\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u043e\u0434\u043d\u0438\u0445 \u0444\u0430\u0439\u043b\u043e\u0432 \u043e\u0442 \u0434\u0440\u0443\u0433\u0438\u0445. \u0414\u0440\u0443\u0433\u0438\u043c\u0438 \u0441\u043b\u043e\u0432\u0430\u043c\u0438, \u0447\u0435\u043c \u0432\u044b\u0448\u0435 \u0444\u0430\u0439\u043b, \u0442\u0435\u043c \u043c\u0435\u043d\u044c\u0448\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u043e\u043d \u0438\u043c\u0435\u0435\u0442 \u043e\u0442 \u0434\u0440\u0443\u0433\u0438\u0445 \u0444\u0430\u0439\u043b\u043e\u0432. \u0422\u0430\u043a \u0436\u0435 \u0434\u0430\u043d\u043d\u044b\u0439 \u0441\u043f\u0438\u0441\u043e\u043a \u0438\u043b\u043b\u044e\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u0442 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0437\u043c\u0435\u043d\u044f\u0442\u044c \u0444\u0430\u0439\u043b\u044b \u0432 \u043a\u0430\u0436\u0434\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u0441\u0442\u0430\u0442\u044c\u0438.<\/p>\n<p><a class=\"anchor\" name=\"prepare\" id=\"prepare\"><\/a><\/p>\n<h2>\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f<\/h2>\n<figure class=\"\"><figcaption><\/figcaption><\/figure>\n<p><a href=\"https:\/\/github.com\/astoniocom\/fl_list_example\/tree\/init\" rel=\"noopener noreferrer nofollow\">\u041e\u0442\u043a\u0440\u044b\u0442\u044c \u043a\u043e\u0434 \u043d\u0430 GitHub<\/a><\/p>\n<p>\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u043c \u043a\u0430\u0440\u043a\u0430\u0441 \u0434\u043b\u044f \u0431\u0443\u0434\u0443\u0449\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0412 \u043d\u0451\u043c \u0431\u0443\u0434\u0435\u0442 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d \u0431\u0435\u0441\u043a\u043e\u043d\u0435\u0447\u043d\u044b\u0439 \u0441\u043f\u0438\u0441\u043e\u043a \u0431\u0435\u0437 \u043a\u0430\u043a\u0438\u0445-\u043b\u0438\u0431\u043e \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<p>\u0412\u044b\u043f\u043e\u043b\u043d\u0438\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043d\u043e\u0432\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<pre><code class=\"bash\">> flutter create fl_list_example<\/code><\/pre>\n<h4>main.dart<\/h4>\n<p>\u0418\u0437\u043c\u0435\u043d\u0438\u043c \u0444\u0430\u0439\u043b <em>main.dart<\/em> \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<pre><code class=\"dart\">\/* file: main.dart *\/  import 'package:flutter\/material.dart';  void main() {   runApp(const MyApp()); }  class MyApp extends StatelessWidget {   const MyApp({Key? key}) : super(key: key);    @override   Widget build(BuildContext context) {     return const MaterialApp(home: HomePage());   } }  class HomePage extends StatefulWidget {   const HomePage({Key? key}) : super(key: key);    @override   State&lt;HomePage> createState() => _HomePageState(); }  class _HomePageState extends State&lt;HomePage> {   @override   Widget build(BuildContext context) {     return Scaffold(       appBar: AppBar(title: const Text(\"List Demo\")),       body: ListView.builder(         itemBuilder: (context, index) {           return ListTile(title: Text(\"Item $index\"));         },       ),     );   } } <\/code><\/pre>\n<p>\u0421\u043e\u0437\u0434\u0430\u043d\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0438\u043c\u0435\u0435\u0442 \u043b\u0438\u0448\u044c \u043e\u0434\u0438\u043d \u044d\u043a\u0440\u0430\u043d \u0441\u043e \u0441\u043f\u0438\u0441\u043a\u043e\u043c. \u0412\u0438\u0434\u0436\u0435\u0442 <em>HomePage<\/em>, \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0431\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u0431\u0430\u0437\u0435 <em>StatelessWidget<\/em>, \u043e\u0434\u043d\u0430\u043a\u043e \u0432 \u0431\u0443\u0434\u0443\u0449\u0435\u043c \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0438\u043c\u0435\u043d\u043d\u043e <em>StatefullWidget<\/em>, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043e\u0441\u0442\u0430\u0432\u0438\u043c \u043a\u0430\u043a \u0435\u0441\u0442\u044c.<\/p>\n<p><a class=\"anchor\" name=\"async\" id=\"async\"><\/a><\/p>\n<h2>\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445<\/h2>\n<figure class=\"\"><figcaption><\/figcaption><\/figure>\n<p><a href=\"https:\/\/github.com\/astoniocom\/fl_list_example\/tree\/async\" rel=\"noopener noreferrer nofollow\">\u041e\u0442\u043a\u0440\u044b\u0442\u044c \u043a\u043e\u0434 \u043d\u0430 GitHub<\/a><\/p>\n<p>\u0412 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u043d\u0435\u0447\u0430\u0441\u0442\u043e \u0438\u043c\u0435\u044e\u0442\u0441\u044f \u0434\u0430\u043d\u043d\u044b\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0436\u043d\u043e \u0441\u0440\u0430\u0437\u0443 \u043e\u0442\u043e\u0431\u0440\u0430\u0437\u0438\u0442\u044c \u0432 \u0441\u043f\u0438\u0441\u043a\u0435. \u041e\u0431\u044b\u0447\u043d\u043e \u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0443\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0438\u0437 \u043d\u0435\u043a\u043e\u0433\u043e \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430 \u0438 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u0442\u044c.  \u041e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u0441 \u044d\u0442\u0438\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0446\u0435\u043b\u0435\u0441\u043e\u043e\u0431\u0440\u0430\u0437\u043d\u043e \u0438\u043d\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0438 \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u044e\u0449\u0438\u0445 \u043e\u0448\u0438\u0431\u043a\u0430\u0445. \u0412 \u044d\u0442\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u043c\u044b \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0443\u0435\u043c \u044d\u0442\u0438 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u044b.<\/p>\n<h4>pubspec.yaml<\/h4>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u043f\u0430\u043a\u0435\u0442\u044b \u0432 \u0444\u0430\u0439\u043b <em>pubspec.yaml<\/em> \u0438 \u0432 \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u043c <em>flutter pub get<\/em>.<\/p>\n<pre><code class=\"yaml\">dependencies:   english_words: ^4.0.0 # 1   provider: ^6.0.0 # 2   ... <\/code><\/pre>\n<p>\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043a\u043e\u0434\u0430:<\/p>\n<ol>\n<li>\n<p>\u041f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u0430\u043d\u0433\u043b\u0438\u0439\u0441\u043a\u0438\u0445 \u0441\u043b\u043e\u0432 \u0434\u043b\u044f \u043d\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445, \u0441 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c.<\/p>\n<\/li>\n<li>\n<p>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0443 \u0441\u043f\u0438\u0441\u043a\u0430.<\/p>\n<\/li>\n<\/ol>\n<h4>models.dart<\/h4>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u043c \u043a\u043b\u0430\u0441\u0441 \u0434\u043b\u044f \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u0441\u043f\u0438\u0441\u043a\u0430. \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0444\u0430\u0439\u043b <em>models.dart<\/em> \u0441 \u0442\u0430\u043a\u0438\u043c \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u044b\u043c:<\/p>\n<pre><code class=\"dart\">\/* file: models.dart *\/  class ExampleRecord {   final String title;    const ExampleRecord({required this.title}); } <\/code><\/pre>\n<p>\u041f\u043e\u043a\u0430 \u0447\u0442\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u044d\u0442\u043e\u0442 \u043a\u043b\u0430\u0441\u0441\u0430 \u0431\u0443\u0434\u0443\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u043b\u043e\u0432\u043e \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0432 \u0441\u0442\u0440\u043e\u043a\u0430\u0445 \u0432\u0438\u0434\u0436\u0435\u0442\u0430 <em>ListView<\/em>.<\/p>\n<h4>repository.dart<\/h4>\n<p>\u0412\u0441\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u043d\u0430\u0434 \u0437\u0430\u043f\u0438\u0441\u044f\u043c\u0438 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0431\u0443\u0434\u0443\u0442 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u0447\u0435\u0440\u0435\u0437 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439. \u0415\u0433\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0440\u0430\u0437\u043c\u0435\u0441\u0442\u0438\u043c \u0432 \u0444\u0430\u0439\u043b\u0435 <em>repository.dart<\/em>.<\/p>\n<pre><code class=\"dart\">\/* file: repository.dart *\/  import 'dart:math'; import 'package:english_words\/english_words.dart'; import 'package:fl_list_example\/models.dart';  const kRecordsToGenerate = 100;  class MockRepository {   \/\/ 1   final List&lt;ExampleRecord> _store = List&lt;ExampleRecord>.generate(             kRecordsToGenerate,             (i) => ExampleRecord(                 title: nouns[Random().nextInt(nouns.length)],               ));    \/\/ 2   static final MockRepository _instance = MockRepository._internal();   factory MockRepository() => _instance;   MockRepository._internal() : super();    \/\/ 3   Future&lt;List&lt;ExampleRecord>> queryRecords() async {     await Future.delayed(const Duration(seconds: 2)); \/\/ 4     return _store;   } } <\/code><\/pre>\n<p>\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043a\u043e\u0434\u0430:<\/p>\n<ol>\n<li>\n<p>\u041f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f \u0437\u0430\u043f\u043e\u043b\u043d\u0438\u043c private-\u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e <em>_store<\/em> (\u0443\u0441\u043b\u043e\u0432\u043d\u0443\u044e \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445) \u0437\u0430\u043f\u0438\u0441\u044f\u043c\u0438 \u0441\u043e \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u044b\u043c\u0438 \u0441\u043b\u043e\u0432\u0430\u043c\u0438.<\/p>\n<\/li>\n<li>\n<p>\u0427\u0442\u043e\u0431\u044b \u0432\u0441\u0435\u0433\u0434\u0430 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u043e\u0434\u043d\u0438\u043c \u0438 \u0442\u0435\u043c \u0436\u0435 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u043c \u0434\u0430\u043d\u043d\u044b\u0445, \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u043a\u043b\u0430\u0441\u0441 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f \u0431\u044b\u043b \u0441\u0438\u043d\u0433\u043b\u0442\u043e\u043d\u043e\u043c, \u0442\u043e \u0435\u0441\u0442\u044c \u043c\u043e\u0433 \u0438\u043c\u0435\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u0438\u043d \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440.<\/p>\n<\/li>\n<li>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f, \u043a \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0431\u0443\u0434\u0435\u043c \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u0438\u0437 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445. \u0412 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0432 \u043a\u043e\u0434\u0435 \u044d\u0442\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0434\u043e\u043b\u0436\u043d\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u044c \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0435 \u043a \u00ab\u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0435\u0439\u00bb \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u043b\u0438 http-\u0437\u0430\u043f\u0440\u043e\u0441.<\/p>\n<\/li>\n<li>\n<p>\u0421\u0442\u0440\u043e\u043a\u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u043c\u0438\u0442\u0430\u0446\u0438\u044e \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0438 \u043f\u0440\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<\/li>\n<\/ol>\n<h4>list_state.dart<\/h4>\n<p>\u0414\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043a\u043b\u0430\u0441\u0441\u0430, \u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e \u0437\u0430 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u0430, \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0444\u0430\u0439\u043b <em>list_state.dart<\/em> \u0441\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u044b\u043c:<\/p>\n<pre><code class=\"dart\">\/* file: list_state.dart *\/  import 'package:fl_list_example\/models.dart';  class ListState {   ListState({     List&lt;ExampleRecord>? records,     this.isLoading = false,     this.error = '', \/\/ 1   }) : recordsStore = records; \/\/ 2    final List&lt;ExampleRecord>? recordsStore; \/\/ 3    bool get isInitialized => recordsStore != null; \/\/ 3    List&lt;ExampleRecord> get records => recordsStore ?? List&lt;ExampleRecord>.empty(); \/\/ 4    final String error;    bool get hasError => error.isNotEmpty; \/\/ 5    final bool isLoading; \/\/ 6      \/\/ 7   ListState copyWith({     List&lt;ExampleRecord>? records,     bool? isLoading,     String? error,   }) {     return ListState(       records: records ?? recordsStore,       isLoading: isLoading ?? this.isLoading,       error: error ?? this.error,     );   } }  <\/code><\/pre>\n<p>\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043a\u043e\u0434\u0430:<\/p>\n<ol>\n<li>\n<p>\u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u043e\u0432\u0435\u043d\u0438\u044f \u043e\u0448\u0438\u0431\u043a\u0438 \u043f\u0440\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u0437 <em>MockRepository<\/em>, \u0432 \u044d\u0442\u0443 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u0434\u043b\u044f \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u0433\u043e \u0435\u0451 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f. \u042d\u0442\u0430 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c <em>null<\/em> \u0438 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0445\u0440\u0430\u043d\u0438\u0442 \u043f\u0443\u0441\u0442\u0443\u044e \u0441\u0442\u0440\u043e\u043a\u0443. \u0422\u0430\u043a\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u043d\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u043e\u0433\u043e \u0442\u043e\u043b\u043a\u043e\u0432\u0430\u043d\u0438\u044f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u044d\u0442\u043e\u0439 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439. \u041f\u043e\u044f\u0441\u043d\u044e. \u0415\u0441\u043b\u0438 \u0431\u044b \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u0431\u044b\u043b\u0430 <em>null<\/em> \u2014 \u044d\u0442\u043e \u0431\u044b, \u0441\u043a\u043e\u0440\u0435\u0435 \u0432\u0441\u0435\u0433\u043e, \u043e\u0437\u043d\u0430\u0447\u0430\u043b\u043e \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435 \u043e\u0448\u0438\u0431\u043a\u0438. \u041d\u043e \u0435\u0441\u043b\u0438 \u0431\u044b \u044d\u0442\u0430 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u0445\u0440\u0430\u043d\u0438\u043b\u0430 \u043f\u0443\u0441\u0442\u0443\u044e \u0441\u0442\u0440\u043e\u043a\u0443 \u0438, \u0432 \u0442\u043e \u0436\u0435 \u0432\u0440\u0435\u043c\u044f, \u0438\u043c\u0435\u043b\u0430 \u0431\u044b \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0438\u043c\u0435\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 <em>null<\/em>, \u0442\u043e \u0438\u043d\u0442\u0435\u0440\u043f\u0440\u0435\u0442\u0430\u0446\u0438\u044f \u0442\u0430\u043a\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0431\u044b\u043b\u0430 \u0431\u044b \u043d\u0435 \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0421\u0442\u0440\u043e\u043a\u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0430 \u043b\u0438\u0448\u044c \u0434\u043b\u044f \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u043d\u044f\u0442\u043d\u043e\u0433\u043e \u0438 \u044d\u0441\u0442\u0435\u0442\u0438\u0447\u043d\u043e\u0433\u043e \u043d\u0430\u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0430 \u043a\u043b\u0430\u0441\u0441\u0430.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f <em>recordsStore<\/em> \u0445\u0440\u0430\u043d\u0438\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043d\u0430 \u044d\u043a\u0440\u0430\u043d\u0435. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f <em>null<\/em> \u0441\u0434\u0435\u043b\u0430\u043d\u043e \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0440\u0430\u0437\u043b\u0438\u0447\u0430\u0442\u044c \u043f\u0440\u0438\u0447\u0438\u043d\u044b, \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u0441\u043f\u0438\u0441\u043e\u043a \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u043f\u0443\u0441\u0442. \u0415\u0441\u043b\u0438 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u0438\u043c\u0435\u0435\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 <em>null<\/em>, \u0437\u043d\u0430\u0447\u0438\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u043f\u0443\u0441\u0442, \u0442\u0430\u043a \u043a\u0430\u043a \u0435\u0449\u0451 \u043d\u0435 \u0431\u044b\u043b\u043e \u0443\u0441\u043f\u0435\u0448\u043d\u044b\u0445 \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0439 \u043a <em>MockRepository<\/em> \u043d\u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0437\u0430\u043f\u0438\u0441\u0435\u0439. \u0415\u0441\u043b\u0438 \u0436\u0435 \u0432 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 \u0441\u043e\u0445\u0440\u0430\u043d\u0451\u043d \u043f\u0443\u0441\u0442\u043e\u0439 \u0441\u043f\u0438\u0441\u043e\u043a, \u0437\u043d\u0430\u0447\u0438\u0442 \u0442\u0430\u043a\u043e\u0435 \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0435 \u0431\u044b\u043b\u043e, \u043e\u0434\u043d\u0430\u043a\u043e <em>MockRepository<\/em> \u043d\u0435 \u0432\u0435\u0440\u043d\u0443\u043b \u043d\u0438 \u043e\u0434\u043d\u043e\u0439 \u0437\u0430\u043f\u0438\u0441\u0438. \u0414\u043b\u044f \u0431\u043e\u043b\u0435\u0435 \u0443\u0434\u043e\u0431\u043d\u043e\u0433\u043e \u0440\u0430\u0437\u043b\u0438\u0447\u0438\u044f \u044d\u0442\u0438\u0445 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f <em>isInitialized<\/em>.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 <em>records<\/em> \u0432\u0441\u0435\u0433\u0434\u0430 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0441\u043f\u0438\u0441\u043e\u043a, \u0432\u043d\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0442\u043e\u0433\u043e, \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u043e \u043b\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 <em>null<\/em> \u0432 <em>recordsStore<\/em>. \u042d\u0442\u043e\u0442 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0443\u0434\u043e\u0431\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c, \u0447\u0442\u043e\u0431\u044b \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f <em>recordsStore<\/em> \u043d\u0430 <em>null<\/em>, \u043f\u0440\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0438 \u0441\u043f\u0438\u0441\u043a\u0430 \u0437\u0430\u043f\u0438\u0441\u0435\u0439.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 <em>hasError<\/em> \u0443\u0434\u043e\u0431\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c, \u043a\u043e\u0433\u0434\u0430 \u043d\u0430\u0434\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c, \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430 \u043b\u0438 \u043e\u0448\u0438\u0431\u043a\u0430 \u0432 \u0445\u043e\u0434\u0435 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u0438\u0437 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f. \u0414\u043b\u044f \u044d\u0442\u0438\u0445 \u0446\u0435\u043b\u0435\u0439 \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0431\u044b \u0430\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e <em>error<\/em>, \u043e\u0434\u043d\u0430\u043a\u043e \u0432 \u0445\u043e\u0434\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0441\u043f\u043e\u0441\u043e\u0431 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u043e\u0448\u0438\u0431\u043a\u0438 \u0432 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438 \u0441\u043f\u0438\u0441\u043a\u0430 \u043c\u043e\u0436\u0435\u0442 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c\u0441\u044f \u0438 \u0442\u043e\u0433\u0434\u0430 \u043f\u0440\u0438\u0434\u0451\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u043a\u043e\u0434\u0430. \u0414\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u044d\u0442\u043e\u0433\u043e \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430 \u0442\u0430\u043a\u0436\u0435 \u043f\u0440\u0438\u0432\u0435\u0434\u0451\u0442 \u043a \u0431\u043e\u043b\u0435\u0435 \u043a\u0440\u0430\u0442\u043a\u043e\u043c\u0443 \u0438 \u043f\u043e\u043d\u044f\u0442\u043d\u043e\u043c\u0443 \u043a\u043e\u0434\u0443.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 <em>isLoading<\/em> \u0441\u0438\u0433\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u0442 \u043e \u0442\u043e\u043c, \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043b\u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0441\u043f\u0438\u0441\u043a\u0430 \u0432 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442. \u042d\u0442\u043e\u0442 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0438\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440\u0430 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0441\u043f\u0438\u0441\u043a\u0430, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0441\u043f\u0438\u0441\u043a\u0430 \u0438\u0437 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0437.<\/p>\n<\/li>\n<li>\n<p>\u0422\u0430\u043a \u043a\u0430\u043a \u043e\u0431\u044a\u0435\u043a\u0442 \u043a\u043b\u0430\u0441\u0441\u0430 <em>ListState<\/em> \u043d\u0435\u0438\u0437\u043c\u0435\u043d\u044f\u0435\u043c\u044b\u0439, \u0444\u0443\u043d\u043a\u0446\u0438\u044f copyWith \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442<\/p>\n<\/li>\n<\/ol>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-330882","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/330882","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=330882"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/330882\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=330882"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=330882"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=330882"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}