{"id":473221,"date":"2025-09-02T15:50:48","date_gmt":"2025-09-02T15:50:48","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=473221"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=473221","title":{"rendered":"<span>\u0424\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0432 Android. \u041f\u043e\u0431\u043e\u0447\u043d\u044b\u0435 \u044d\u0444\u0444\u0435\u043a\u0442\u044b \u0438 ELM-\u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/928\/367\/9ee\/9283679eeea73cb58fd8aa0f95192715.png\" width=\"3120\" height=\"1760\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/928\/367\/9ee\/9283679eeea73cb58fd8aa0f95192715.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/928\/367\/9ee\/9283679eeea73cb58fd8aa0f95192715.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<h3>\u041e \u0447\u0451\u043c \u0441\u0442\u0430\u0442\u044c\u044f<\/h3>\n<p>\u0412 \u0447\u0435\u0442\u0432\u0451\u0440\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u0446\u0438\u043a\u043b\u0430 \u043f\u0440\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0432 Android \u043c\u044b \u0441\u043e\u0431\u0435\u0440\u0451\u043c \u0437\u043d\u0430\u043d\u0438\u044f, \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0435 \u0432 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0445 \u0447\u0430\u0441\u0442\u044f\u0445 \u0446\u0438\u043a\u043b\u0430. \u0410 \u0435\u0449\u0451 \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u043c \u0438\u0445 \u043d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u2014 \u0441\u043e\u0431\u0435\u0440\u0451\u043c \u0441\u043a\u0435\u043b\u0435\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u043c\u0435\u0434\u0438\u0442\u0430\u0446\u0438\u0438.<\/p>\n<p>\u0415\u0441\u043b\u0438 \u0432\u044b \u043d\u0435 \u043f\u043e\u043c\u043d\u0438\u0442\u0435 \u0438\u043b\u0438 \u043d\u0435 \u0437\u043d\u0430\u0435\u0442\u0435, \u0447\u0442\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u043b\u043e \u0432 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0445 \u0441\u0442\u0430\u0442\u044c\u044f\u0445 \u0446\u0438\u043a\u043b\u0430, \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u0442\u0435 \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0430\u043c \u043d\u0438\u0436\u0435, \u0430 \u043f\u043e\u0442\u043e\u043c \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0439\u0442\u0435\u0441\u044c \u043a \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435:<\/p>\n<ol>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/companies\/dododev\/articles\/917222\/\" rel=\"noopener noreferrer nofollow\">\u0424\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0432 Android. \u0417\u043d\u0430\u043a\u043e\u043c\u0441\u0442\u0432\u043e \u0441 \u043f\u0430\u0440\u0430\u0434\u0438\u0433\u043c\u043e\u0439.<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/companies\/dododev\/articles\/917960\/\" rel=\"noopener noreferrer nofollow\">\u0424\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0432 Android. \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 State Machine.<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/companies\/dododev\/articles\/922710\/\" rel=\"noopener noreferrer nofollow\">\u0424\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0432 Android. \u0422\u0435\u043e\u0440\u0438\u044f \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0439 \u0438 DI.<\/a><\/p>\n<\/li>\n<\/ol>\n<p>\u041f\u0435\u0440\u0435\u0434 \u0442\u0435\u043c, \u043a\u0430\u043a \u043f\u0435\u0440\u0435\u0439\u0442\u0438 \u043a \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044e \u043a\u043e\u0434\u0430, \u044f \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u0430\u0441 \u043f\u0440\u0435\u0434\u0443\u043f\u0440\u0435\u0434\u0438\u0442\u044c, \u0447\u0442\u043e \u043e\u043d \u0432\u043e \u043c\u043d\u043e\u0433\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u043c. \u0414\u043b\u044f \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b \u0432 \u043d\u0451\u043c \u0438 mock-\u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438, \u0438 hardcode \u2014 \u0432 \u043e\u0431\u0449\u0435\u043c, \u044d\u0442\u043e \u043d\u0435 \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u043e \u043f\u043e \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044e \u044d\u0442\u0430\u043b\u043e\u043d\u043d\u043e\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b.<\/p>\n<p>\u041a\u0430\u043a \u044f \u0443\u043f\u043e\u043c\u0438\u043d\u0430\u043b \u0440\u0430\u043d\u0435\u0435, \u0437\u0430\u0447\u0430\u0442\u043a\u0438 \u043f\u043e\u0445\u043e\u0436\u0435\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b \u0443 \u043c\u0435\u043d\u044f \u043d\u0435 \u0434\u043e\u0435\u0445\u0430\u043b\u0438 \u0434\u043e \u043f\u0440\u043e\u0434\u0430. \u0422\u0435\u043a\u0443\u0449\u0438\u0439 \u043f\u0435\u0442-\u043f\u0440\u043e\u0435\u043a\u0442 \u0434\u043e\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0435\u0451 \u0438 \u043f\u0438\u0448\u0435\u0442\u0441\u044f \u0438\u0441\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0441 \u0446\u0435\u043b\u044c\u044e \u043f\u043e\u0449\u0443\u043f\u0430\u0442\u044c \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0432 Android-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435.<\/p>\n<p>\u042d\u0442\u043e \u044f \u0432\u0441\u0451 \u043a \u0447\u0435\u043c\u0443? \u0411\u0443\u0434\u0435\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043c\u043e\u0438 \u043f\u0440\u0438\u0451\u043c\u044b \u0432 \u0441\u0432\u043e\u0438\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445 \u2014 \u0434\u0435\u043b\u0430\u0439\u0442\u0435 \u044d\u0442\u043e \u043e\u0441\u0442\u043e\u0440\u043e\u0436\u043d\u043e. \u041c\u0435\u0441\u0442\u0430 \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u044f \u0431\u0443\u0434\u0443 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u043e\u0434\u0441\u0432\u0435\u0447\u0438\u0432\u0430\u0442\u044c \u0438 \u043f\u043e\u044f\u0441\u043d\u044f\u0442\u044c.<\/p>\n<h2>\u041a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b<\/h2>\n<p>\u0412 \u043f\u0435\u0440\u0432\u044b\u0439 \u0440\u0430\u0437 \u044f \u043f\u0440\u043e\u0431\u043e\u0432\u0430\u043b \u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0424\u041f-\u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0443 \u043d\u0430 <em>ViewModel<\/em>. \u0421\u0435\u0439\u0447\u0430\u0441 \u044f \u0431\u0443\u0434\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <em>The Elm Architecture (TEA)<\/em> \u2014 \u043f\u0430\u0442\u0442\u0435\u0440\u043d \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c, \u0437\u0430\u0438\u043c\u0441\u0442\u0432\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0438\u0437 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u044f\u0437\u044b\u043a\u0430 <em>Elm<\/em>.<\/p>\n<p>\u041e\u043d \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u0441\u0442\u0440\u043e\u0433\u0438\u0439 \u043e\u0434\u043d\u043e\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0439 \u043f\u043e\u0442\u043e\u043a \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0443\u0435\u043c\u043e\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f. \u041e\u0434\u043d\u0430\u043a\u043e \u0433\u043b\u0443\u0431\u043e\u043a\u043e \u043c\u044b \u0432 \u043d\u0435\u0433\u043e \u0443\u0445\u043e\u0434\u0438\u0442\u044c \u043d\u0435 \u0431\u0443\u0434\u0435\u043c. \u0412\u0441\u0435 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u044e\u0449\u0438\u0435\u0441\u044f \u043c\u043e\u0433\u0443\u0442 \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u043d\u0438\u043c <a href=\"https:\/\/habr.com\/ru\/companies\/vivid_money\/articles\/550932\/\" rel=\"noopener noreferrer nofollow\">\u0442\u0443\u0442<\/a>, \u0430 \u043c\u044b \u0432\u0435\u0440\u0445\u043d\u0435\u0443\u0440\u043e\u0432\u043d\u0435\u0432\u043e \u0440\u0430\u0437\u0431\u0435\u0440\u0451\u043c \u0441\u0443\u0442\u044c \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432. \u0421\u0445\u0435\u043c\u0430 \u043f\u043e\u0442\u043e\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0442\u0430\u043a:<\/p>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/24c\/89d\/791\/24c89d7910f04bcabb34383925d0dfc9.png\" alt=\"\u0426\u0438\u043a\u043b \u043f\u043e\u0442\u043e\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 ELM-\u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b\" title=\"\u0426\u0438\u043a\u043b \u043f\u043e\u0442\u043e\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 ELM-\u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b\" width=\"1600\" height=\"1355\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/24c\/89d\/791\/24c89d7910f04bcabb34383925d0dfc9.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/24c\/89d\/791\/24c89d7910f04bcabb34383925d0dfc9.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u0426\u0438\u043a\u043b \u043f\u043e\u0442\u043e\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 <em>ELM-\u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b<\/em><\/figcaption><\/div>\n<\/figure>\n<p><code>State<\/code><em> <\/em>\u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u043c\u043c\u0443\u0442\u0430\u0431\u0435\u043b\u044c\u043d\u044b\u0439 \u0441\u043d\u0438\u043c\u043e\u043a \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438\u043b\u0438 \u044d\u043a\u0440\u0430\u043d\u0430<em>.<\/em> \u041e\u043d \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0438 <em>UI<\/em> \u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043a\u0430\u043a \u043b\u0435\u0433\u043a\u043e \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0443\u0435\u043c\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442. \u0415\u0433\u043e \u0438\u043c\u043c\u0443\u0442\u0430\u0431\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u0443\u0435\u0442 \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0443\u0435\u043c\u043e\u0441\u0442\u044c. \u041b\u044e\u0431\u043e\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043d\u043e\u0432\u043e\u0439 \u043a\u043e\u043f\u0438\u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f, \u0438\u0441\u043a\u043b\u044e\u0447\u0430\u044f \u0441\u043a\u0440\u044b\u0442\u044b\u0435 \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0438 \u043f\u043e\u0431\u043e\u0447\u043d\u044b\u0435 \u044d\u0444\u0444\u0435\u043a\u0442\u044b.<\/p>\n<p><code>Event<\/code><em> \u2014 <\/em>\u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u043b\u0435\u0433\u0430\u043b\u044c\u043d\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f. \u042d\u0442\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0435 \u0438\u043b\u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u2014 <code>ButtonClicked<\/code>, <code>DataLoaded<\/code> \u0438 \u0442.\u0434. \u041e\u043d\u0438 \u043d\u0435 \u0438\u0437\u043c\u0435\u043d\u044f\u044e\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u0430 \u0442\u0440\u0438\u0433\u0433\u0435\u0440\u044f\u0442 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b, \u043e\u0442\u0432\u0435\u0447\u0430\u044e\u0449\u0438\u0435 \u0437\u0430 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u044b \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439. \u0412\u0430\u0436\u043d\u043e, \u0447\u0442\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u043d\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442 \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0438, \u0430 \u043b\u0438\u0448\u044c \u0441\u0438\u0433\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u044e\u0442 \u043e \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u0435\u0434\u0448\u0435\u043c \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0438.<\/p>\n<p><code>Command<\/code><em> <\/em>\u0438\u043d\u043a\u0430\u043f\u0441\u0443\u043b\u0438\u0440\u0443\u0435\u0442 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 (<code>FetchUserData<\/code>) \u0438\u043b\u0438 \u0441\u0430\u0439\u0434-\u044d\u0444\u0444\u0435\u043a\u0442\u044b (<code>StartTimer<\/code>). \u041a\u043e\u043c\u0430\u043d\u0434\u044b \u043d\u0435 \u0438\u0437\u043c\u0435\u043d\u044f\u044e\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435, \u0430 \u043b\u0438\u0448\u044c \u0434\u0435\u043b\u0435\u0433\u0438\u0440\u0443\u044e\u0442 \u0440\u0430\u0431\u043e\u0442\u0443 \u0432\u043d\u0435\u0448\u043d\u0438\u043c \u0438\u0441\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044f\u043c. \u041e\u043d\u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0442 \u043d\u043e\u0432\u044b\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u043f\u0440\u0438\u0432\u0435\u0441\u0442\u0438 \u043a \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0443 \u0432 \u043d\u043e\u0432\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435, \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u044f \u0447\u0438\u0441\u0442\u043e\u0442\u0443 \u043f\u043e\u0442\u043e\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<p><code>Effect<\/code><em> <\/em>\u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0435 <em>UI-\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435<\/em> \u043f\u043e\u0441\u043b\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f: <code>ShowToast<\/code>, <code>NavigateToScreen<\/code>. \u0412 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 \u043a\u043e\u043c\u0430\u043d\u0434, \u044d\u0444\u0444\u0435\u043a\u0442\u044b \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442\u0441\u044f \u043f\u043e\u0441\u043b\u0435 \u0444\u0438\u043a\u0441\u0430\u0446\u0438\u0438 \u043d\u043e\u0432\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0438 \u043d\u0435 \u0441\u043e\u0437\u0434\u0430\u044e\u0442 \u0441\u043e\u0431\u044b\u0442\u0438\u044f. \u041e\u043d\u0438 \u043c\u043e\u0434\u0435\u043b\u0438\u0440\u0443\u044e\u0442 \u00ab\u0440\u0435\u0430\u043a\u0446\u0438\u044e\u00bb \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u043d\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f.<\/p>\n<h3>\u041c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u044b \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0438<\/h3>\n<p><code>Reducer<\/code><em> \u2014 <\/em>\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440 \u0441\u043e\u0431\u044b\u0442\u0438\u0439. \u042d\u0442\u043e \u0447\u0438\u0441\u0442\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f. \u041e\u043d\u0430 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0442\u0435\u043a\u0443\u0449\u0435\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u0435, \u0430 \u0435\u0449\u0451 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 <code>StateResult<\/code>. \u0412\u0430\u0436\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u0440\u0435\u0434\u044c\u044e\u0441\u0435\u0440 \u043e\u0431\u043b\u0430\u0434\u0430\u043b \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e\u043c \u0434\u0435\u0442\u0435\u0440\u043c\u0438\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0441\u0442\u0438: \u0434\u043b\u044f \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u0445 \u0432\u0445\u043e\u0434\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u043e\u043d \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u0438\u0434\u0435\u043d\u0442\u0438\u0447\u043d\u044b\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0431\u0435\u0437 \u043f\u043e\u0431\u043e\u0447\u043d\u044b\u0445 \u044d\u0444\u0444\u0435\u043a\u0442\u043e\u0432.<\/p>\n<p><code>StateResult<\/code><em> \u2014 <\/em>\u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440-\u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442\u0451\u0440. \u041e\u043d \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u0443\u0435\u0442 \u0430\u0442\u043e\u043c\u0430\u0440\u043d\u043e\u0441\u0442\u044c \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f: \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0438\u0437\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e, \u0430 \u043f\u043e\u0442\u043e\u043c \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u044e\u0442\u0441\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0438 \u044d\u0444\u0444\u0435\u043a\u0442\u044b. \u0422\u0430\u043a\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u043f\u0440\u0435\u0434\u043e\u0442\u0432\u0440\u0430\u0449\u0430\u0435\u0442 <em>RaceConditions<\/em> \u0438 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u043b\u043e\u0433\u0438\u043a\u0438.<\/p>\n<p><code>Actor<\/code><em> <\/em>\u0438\u0441\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438. \u0415\u0433\u043e \u043c\u0435\u0442\u043e\u0434 <code>execute<\/code> \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u0435\u0442 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0432 \u0441\u043e\u0431\u044b\u0442\u0438\u044f, \u0430 <code>subscribe<\/code> \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0432\u043d\u0435\u0448\u043d\u0438\u0435 \u043f\u043e\u0442\u043e\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445: <code>WebSocket<\/code>, \u0442\u0430\u0439\u043c\u0435\u0440\u044b. \u0410\u043a\u0442\u043e\u0440 \u0438\u0437\u043e\u043b\u0438\u0440\u0443\u0435\u0442 \u00ab\u0433\u0440\u044f\u0437\u043d\u0443\u044e\u00bb \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 \u0432\u043d\u0435\u0448\u043d\u0438\u043c \u043c\u0438\u0440\u043e\u043c, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044f \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0447\u0435\u0440\u0435\u0437 \u0441\u043e\u0431\u044b\u0442\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u043d\u043e\u0432\u044c \u043f\u043e\u043f\u0430\u0434\u0430\u044e\u0442 \u0432 \u0440\u0435\u0434\u044c\u044e\u0441\u0435\u0440.<\/p>\n<h3>\u0426\u0435\u043d\u0442\u0440 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f<\/h3>\n<p><code>Store<\/code><em> <\/em>\u2014 \u044d\u0442\u043e \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435, \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0438\u0440\u0443\u044e\u0449\u0435\u0435 \u0432\u0441\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b. \u041e\u043d\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043f\u043e\u0442\u043e\u043a\u0438 \u0434\u043b\u044f \u043d\u0430\u0431\u043b\u044e\u0434\u0435\u043d\u0438\u044f \u0437\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f\u043c\u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f, \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u044d\u0444\u0444\u0435\u043a\u0442\u043e\u0432 \u0438 \u043c\u0435\u0442\u043e\u0434 <code>send<\/code> \u0434\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u0439.<\/p>\n<pre><code class=\"kotlin\">interface Event interface Command interface Effect data class StateResult&lt;S : State&gt;(   val state: S,   val commands: List&lt;Command&gt; = emptyList(),   val effects: List&lt;Effect&gt; = emptyList() )  interface Reducer&lt;S : State, E : Event&gt; {   fun reduce(state: S, event: E?): StateResult&lt;S&gt; }  interface State  interface Actor {   suspend fun execute(command: Command): Event?   suspend fun subscribe(): Flow&lt;Event&gt; }  interface Store&lt;S : State, E : Event&gt; {   val state: StateFlow&lt;S&gt;   val effects: SharedFlow&lt;Effect&gt;   fun send(event: E) }<\/code><\/pre>\n<p>\u0426\u0438\u043a\u043b \u0440\u0430\u0431\u043e\u0442\u044b \u0437\u0430\u043c\u044b\u043a\u0430\u0435\u0442\u0441\u044f: \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u043f\u0440\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0438 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u044e\u0442 \u043d\u043e\u0432\u044b\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u043d\u043e\u0432\u044c \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0432 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435. \u042d\u0444\u0444\u0435\u043a\u0442\u044b \u043f\u043e\u0442\u0440\u0435\u0431\u043b\u044f\u044e\u0442\u0441\u044f <em>UI-\u0441\u043b\u043e\u0435\u043c<\/em> \u0431\u0435\u0437 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0432\u043b\u0438\u044f\u0442\u044c \u043d\u0430 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435.<\/p>\n<h3>\u041f\u043e\u0431\u043e\u0447\u043d\u044b\u0435 \u044d\u0444\u0444\u0435\u043a\u0442\u044b<\/h3>\n<p>\u0415\u0449\u0451 \u043e\u0434\u043d\u043e \u0432\u0430\u0436\u043d\u043e\u0435 \u043f\u043e\u043d\u044f\u0442\u0438\u0435 \u0434\u043b\u044f \u0441\u0442\u0430\u0442\u044c\u0438 \u2014 \u043f\u043e\u0431\u043e\u0447\u043d\u044b\u0435 \u044d\u0444\u0444\u0435\u043a\u0442\u044b (<em>Side Effect<\/em>). \u041d\u0430\u043c \u0432\u0430\u0436\u043d\u043e \u043f\u043e\u043d\u044f\u0442\u044c, \u043a\u0430\u043a \u043e\u043d\u0438 \u0432\u043b\u0438\u044f\u044e\u0442 \u043d\u0430 \u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0412 \u0446\u0435\u043b\u043e\u043c \u043f\u043e\u0431\u043e\u0447\u043d\u044b\u0439 \u044d\u0444\u0444\u0435\u043a\u0442 \u2014 \u044d\u0442\u043e \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u0438\u043b\u0438 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0441 \u0432\u043d\u0435\u0448\u043d\u0438\u043c \u043c\u0438\u0440\u043e\u043c, \u0432\u044b\u0445\u043e\u0434\u044f\u0449\u0435\u0435 \u0437\u0430 \u0440\u0430\u043c\u043a\u0438 \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u044f \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u0438. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440:<\/p>\n<ul>\n<li>\n<p>\u0437\u0430\u043f\u0438\u0441\u044c \u0432 \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445;<\/p>\n<\/li>\n<li>\n<p>\u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0430 \u0441\u0435\u0442\u0435\u0432\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430;<\/p>\n<\/li>\n<li>\n<p>\u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u043e\u0439 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439;<\/p>\n<\/li>\n<li>\n<p>\u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 UI.<\/p>\n<\/li>\n<\/ul>\n<p>\u0412 \u0438\u043c\u043f\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u043e\u043c \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u0442\u0430\u043a\u0438\u0435 \u044d\u0444\u0444\u0435\u043a\u0442\u044b \u0432\u0441\u0442\u0440\u0435\u0447\u0430\u044e\u0442\u0441\u044f \u0432\u0435\u0437\u0434\u0435, \u043d\u043e \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u043c \u2014 \u0441\u0447\u0438\u0442\u0430\u044e\u0442\u0441\u044f \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u043c \u043f\u0440\u043e\u0431\u043b\u0435\u043c. \u041e\u043d\u0438 \u0443\u0441\u043b\u043e\u0436\u043d\u044f\u044e\u0442 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435, \u0441\u043e\u0437\u0434\u0430\u044e\u0442 \u0441\u043a\u0440\u044b\u0442\u044b\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0438, \u0447\u0442\u043e \u0445\u0443\u0436\u0435 \u0432\u0441\u0435\u0433\u043e, \u043d\u0430\u0440\u0443\u0448\u0430\u044e\u0442 \u0434\u0435\u0442\u0435\u0440\u043c\u0438\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0441\u0442\u044c.<\/p>\n<p>\u0423\u043d\u0438\u0447\u0442\u043e\u0436\u0438\u0442\u044c \u043f\u043e\u0431\u043e\u0447\u043d\u044b\u0435 \u044d\u0444\u0444\u0435\u043a\u0442\u044b \u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e. \u041d\u043e \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u043c \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u043c\u043e\u0436\u043d\u043e:<\/p>\n<ul>\n<li>\n<p>\u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0443\u0435\u043c\u043e\u0441\u0442\u044c \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u044d\u0442\u0438\u0445 \u044d\u0444\u0444\u0435\u043a\u0442\u043e\u0432, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u043c\u043e\u043d\u0430\u0434\u044b; <\/p>\n<\/li>\n<li>\n<p>\u0432\u044b\u043d\u043e\u0441\u0438\u0442\u044c \u044d\u0444\u0444\u0435\u043a\u0442\u044b \u0437\u0430 \u043f\u0440\u0435\u0434\u0435\u043b\u044b \u0447\u0438\u0441\u0442\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439.<\/p>\n<\/li>\n<\/ul>\n<p>\u0418\u0437\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0431\u043e\u0447\u043d\u044b\u0435 \u044d\u0444\u0444\u0435\u043a\u0442\u044b \u043d\u0430 <em>UI-\u0441\u043b\u043e\u0435<\/em> \u043c\u043e\u0436\u043d\u043e \u0432\u043d\u0435\u0434\u0440\u0438\u0432 <em>Launch<\/em>, <em>Disposable<\/em> \u0438\u043b\u0438 <br \/><em>Side<\/em>&#8212;<em>\u044d\u0444\u0444\u0435\u043a\u0442\u044b<\/em> \u0438\u0437 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 <em>Compose<\/em>.<\/p>\n<p>\u0414\u0440\u0443\u0433\u0438\u043c \u043f\u0440\u0438\u0451\u043c\u043e\u043c \u0438\u0437\u043e\u043b\u044f\u0446\u0438\u0438 \u043f\u043e\u0431\u043e\u0447\u043d\u044b\u0445 \u044d\u0444\u0444\u0435\u043a\u0442\u043e\u0432 \u043d\u0430 <em>UI<\/em>&#8212;<em>\u0441\u043b\u043e\u0435<\/em>, \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u0435 <code>Launch<\/code><em>, <\/em><code>Disposable<\/code><em> <\/em>\u0438\u043b\u0438<em> <\/em><code>Side<\/code> \u044d\u0444\u0444\u0435\u043a\u0442\u043e\u0432 \u0438\u0437 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 <em>Compose<\/em>.<\/p>\n<p><em>Compose<\/em> \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d \u043d\u0430 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0430\u0445 \u0424\u041f: <\/p>\n<p><img decoding=\"async\" class=\"formula\" source=\"UI = func(@Composable (State) \\to UI)\" alt=\"UI = func(@Composable (State) \\to UI)\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/706\/b51\/228\/706b512283b0823232f562fe0f7dbd29.svg\" width=\"344\" height=\"22\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/706\/b51\/228\/706b512283b0823232f562fe0f7dbd29.svg 780w,&#10;       https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/706\/b51\/228\/706b512283b0823232f562fe0f7dbd29.svg 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<p>\u041a\u0430\u043a \u044f \u0443\u0436\u0435 \u0443\u043f\u043e\u043c\u0438\u043d\u0430\u043b \u0440\u0430\u043d\u0435\u0435, \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0438\u0437\u0431\u0430\u0432\u0438\u0442\u044c\u0441\u044f \u043e\u0442 \u044d\u0444\u0444\u0435\u043a\u0442\u043e\u0432 \u043d\u0435\u043b\u044c\u0437\u044f. \u0412 \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0442\u0430\u043a\u0438\u0445 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u0439 \u043c\u0430\u0441\u0441\u0430: \u0437\u0430\u043f\u0443\u0441\u043a \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438, \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0430 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0438, \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0430 \u043d\u0430 \u043f\u043e\u0442\u043e\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445. \u0415\u0441\u043b\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u044d\u0444\u0444\u0435\u043a\u0442\u044b \u043f\u0440\u044f\u043c\u043e \u0432 \u0442\u0435\u043b\u0435 <em>Composable-\u0444\u0443\u043d\u043a\u0446\u0438\u0439<\/em>, \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u043e\u0438\u0437\u043e\u0439\u0442\u0438 \u043d\u0435\u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u0443\u0435\u043c\u0430\u044f \u0440\u0435\u043a\u043e\u043c\u043f\u043e\u0437\u0438\u0446\u0438\u044f, \u0443\u0442\u0435\u0447\u043a\u0430 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u0438\u043b\u0438 \u043a\u0440\u0430\u0448 \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u0440\u0438\u0441\u043e\u0432\u043a\u0435. \u0427\u0442\u043e\u0431\u044b \u0440\u0435\u0448\u0438\u0442\u044c \u044d\u0442\u0443 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443, \u0431\u044b\u043b\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u044b <em>Effects<\/em>.<\/p>\n<p><code>LaunchedEffect<\/code> \u0434\u043b\u044f \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0445 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439. \u041e\u043d \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0443 \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u043e\u0433\u043e \u0446\u0438\u043a\u043b\u0430 <em>Composable<\/em>. \u041e\u043d\u0430 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043e\u0442\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u043f\u0440\u0438 \u0432\u044b\u0445\u043e\u0434\u0435 \u0438\u0437 \u043a\u043e\u043c\u043f\u043e\u0437\u0438\u0446\u0438\u0438. \u042d\u0442\u043e\u0442 \u0442\u0438\u043f \u044d\u0444\u0444\u0435\u043a\u0442\u043e\u0432 \u0441\u0442\u043e\u0438\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432 \u0437\u0430\u0434\u0430\u0447\u0430\u0445, \u043f\u0440\u0438\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0445 \u043a \u043a\u043b\u044e\u0447\u0430\u043c \u0438\u043b\u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f\u043c.<\/p>\n<pre><code class=\"kotlin\">@Composable  fun UserProfile(userId: String) {     LaunchedEffect(key1 = userId) { \/\/ \u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 userId         val user = api.fetchUser(userId) \/\/ \u0421\u0435\u0442\u0435\u0432\u043e\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 (\u044d\u0444\u0444\u0435\u043a\u0442)         updateUi(user)     } }<\/code><\/pre>\n<p><code>DisposableEffect<\/code> <em>\u2014 <\/em>\u0430\u043d\u0430\u043b\u043e\u0433<em> <\/em><code>LaunchedEffect<\/code><em>, <\/em>\u043d\u043e \u0441 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c\u044e \u043e\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u043a\u0430\u043a<em> <\/em><code>onDestroy<\/code><em> <\/em>\u0432<em> <\/em><code>Activity<\/code><em>.<\/em> \u0415\u0433\u043e \u0441\u0442\u043e\u0438\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0438 \u0438\u043b\u0438 \u043e\u0442\u043f\u0438\u0441\u043a\u0438 \u043d\u0430 \u043f\u043e\u0442\u043e\u043a\u0438, \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044e \u0441\u043b\u0443\u0448\u0430\u0442\u0435\u043b\u0435\u0439 \u0438\u043b\u0438 \u0435\u0451 \u043e\u0442\u043c\u0435\u043d\u0443<em>.<\/em><\/p>\n<pre><code class=\"kotlin\">@Composable fun LocationTracker() {     val player = remember { createExoPlayer(\"example.mp3\") }           DisposableEffect(player) {         val listener = object : Player.Listener {       override fun onPlaybackStateChanged(playbackState: Int) {         when (playbackState) {           Player.STATE_ENDED -&gt; {             player.seekTo(0) \/\/ \u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0432 \u043d\u0430\u0447\u0430\u043b\u043e, \u043d\u043e \u043d\u0435 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u043c           }         }       }     }     player.addListener(listener)     onDispose {       player.removeListener(listener)       player.release()     }   } }<\/code><\/pre>\n<p>\u0414\u043b\u044f \u0442\u0430\u043a\u043e\u0433\u043e \u0442\u0438\u043f\u0430 \u044d\u0444\u0444\u0435\u043a\u0442\u0430 \u0435\u0441\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u0440\u0438\u0432\u044f\u0437\u0430\u0442\u044c\u0441\u044f \u043a \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u043e\u043c\u0443 \u0446\u0438\u043a\u043b\u0443 <code>Activity<\/code>. \u0412\u0430\u0448 \u0432\u0430\u0440\u0438\u0430\u043d\u0442, \u0435\u0441\u043b\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0435 <code>lifecycleOwner<\/code> \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0435 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u0438.<\/p>\n<p><code>SideEffect<\/code><em> \u2014 <\/em>\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432\u043d\u0435\u0448\u043d\u0435\u0433\u043e \u043c\u0438\u0440\u0430. \u042d\u0442\u043e\u0442 \u0432\u0438\u0434 \u044d\u0444\u0444\u0435\u043a\u0442\u043e\u0432 \u043e\u0434\u043d\u043e\u043a\u0440\u0430\u0442\u043d\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u043a\u043e\u0434 \u043f\u043e\u0441\u043b\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0439 \u0440\u0435\u043a\u043e\u043c\u043f\u043e\u0437\u0438\u0446\u0438\u0438. \u041e\u043d \u043d\u0435 \u0438\u043c\u0435\u0435\u0442 \u0441\u0432\u043e\u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0438 \u043f\u0440\u0438\u0432\u044f\u0437\u043a\u0438 \u043a \u043a\u043b\u044e\u0447\u0430\u043c \u2014 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u043d\u0435\u043c\u0435\u0434\u043b\u0435\u043d\u043d\u043e, \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e \u0438 \u0432 <em>UI-\u043f\u043e\u0442\u043e\u043a\u0435<\/em>.<\/p>\n<p>\u042d\u0442\u043e\u0442 \u0432\u0438\u0434 \u043f\u043e\u0431\u043e\u0447\u043d\u044b\u0445 \u044d\u0444\u0444\u0435\u043a\u0442\u043e\u0432 \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u0434\u043b\u044f:<\/p>\n<ul>\n<li>\n<p>\u043b\u0435\u0433\u043a\u043e\u0432\u0435\u0441\u043d\u044b\u0445 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439: \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435, \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0430 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0438, \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0432\u043d\u0435\u0448\u043d\u0438\u0445 \u043a\u044d\u0448\u0435\u0439;<\/p>\n<\/li>\n<li>\n<p>\u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u044b\u0445 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0439: \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0445 <em>UI-\u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432<\/em> \u0438 \u0442.\u0434.<\/p>\n<\/li>\n<li>\n<p>\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u0441 \u0432\u043d\u0435\u0448\u043d\u0438\u043c\u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u0430\u043c\u0438: \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 <em>legacy-\u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432<\/em>: <code>View<\/code>, <code>Fragment<\/code>; \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0441 \u043d\u0430\u0442\u0438\u0432\u043d\u044b\u043c\u0438 <em>API<\/em>: <code>WebView<\/code>, <code>CameraX<\/code>; \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f \u0441 <em>\u043d\u0435-Compose<\/em> \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430\u043c\u0438.<\/p>\n<\/li>\n<\/ul>\n<pre><code class=\"kotlin\">@Composable fun rememberFirebaseAnalytics(user: User): FirebaseAnalytics {     val analytics: FirebaseAnalytics = remember {         FirebaseAnalytics()     }      SideEffect {         analytics.setUserProperty(\"userType\", user.userType)     }     return analytics }<\/code><\/pre>\n<p>\u041d\u043e \u043d\u0435 \u0432\u0441\u0451 \u0442\u0430\u043a \u0438\u0434\u0435\u0430\u043b\u044c\u043d\u043e. <code>SideEffetct<\/code> \u043d\u0435 \u0434\u043e\u043b\u0436\u0435\u043d \u0438\u0437\u043c\u0435\u043d\u044f\u0442\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 <em>Compose<\/em>, \u0438\u043d\u0430\u0447\u0435 \u044d\u0442\u043e \u0432\u044b\u0437\u043e\u0432\u0435\u0442 \u0431\u0435\u0441\u043a\u043e\u043d\u0435\u0447\u043d\u0443\u044e \u0440\u0435\u043a\u043e\u043c\u043f\u043e\u0437\u0438\u0446\u0438\u044e. \u042d\u0442\u043e\u0442 \u0432\u0438\u0434 \u044d\u0444\u0444\u0435\u043a\u0442\u043e\u0432 \u043d\u0435 \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043a\u043e\u0440\u0443\u0442\u0438\u043d \u2014 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0435\u0441\u0442\u044c <code>LaunchedEffect<\/code>.<\/p>\n<p>\u0410 \u0435\u0449\u0451 \u0441 <code>SideEffect<\/code> \u0431\u043e\u043b\u0435\u0437\u043d\u0435\u043d\u043d\u043e \u043f\u0435\u0440\u0435\u043d\u043e\u0441\u0438\u0442\u044c \u0442\u044f\u0436\u0435\u043b\u043e\u0432\u0435\u0441\u043d\u044b\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043e\u043d \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0432 <em>UI-\u043f\u043e\u0442\u043e\u043a\u0435<\/em>. \u0422\u0430\u043a \u043a\u0430\u043a \u0436\u0438\u0442\u044c \u0441 \u043f\u043e\u0431\u043e\u0447\u043d\u044b\u043c\u0438 \u044d\u0444\u0444\u0435\u043a\u0442\u0430\u043c\u0438 \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u043c \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438?<\/p>\n<ul>\n<li>\n<p>\u043f\u0440\u0438\u0437\u043d\u0430\u0439\u0442\u0435 \u0438\u0445 \u043d\u0435\u0438\u0437\u0431\u0435\u0436\u043d\u043e\u0441\u0442\u044c. \u0411\u0435\u0437 \u044d\u0444\u0444\u0435\u043a\u0442\u043e\u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0431\u0435\u0441\u043f\u043e\u043b\u0435\u0437\u043d\u043e;<\/p>\n<\/li>\n<li>\n<p>\u0438\u0437\u043e\u043b\u0438\u0440\u0443\u0439\u0442\u0435 \u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u0443\u0439\u0442\u0435 \u0438\u0445. \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b \u2014 \u043c\u043e\u043d\u0430\u0434\u044b \u0438\u043b\u0438 <em>Compose Effects<\/em>;<\/p>\n<\/li>\n<li>\n<p>\u0441\u043b\u0435\u0434\u0443\u0439\u0442\u0435 \u043f\u0440\u043e\u0441\u0442\u044b\u043c \u043f\u0440\u0430\u0432\u0438\u043b\u0430\u043c: \u044d\u0444\u0444\u0435\u043a\u0442\u044b \u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u044b \u0437\u0430\u0432\u0438\u0441\u0435\u0442\u044c \u043e\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0438\u043b\u0438 \u043a\u043b\u044e\u0447\u0435\u0439; \u0440\u0435\u0441\u0443\u0440\u0441\u044b \u043d\u0443\u0436\u043d\u043e \u043e\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0430\u0442\u044c; \u0432 \u0442\u0435\u043b\u0435 <em>Composable<\/em> \u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u043d\u0435 \u0434\u0435\u0442\u0435\u0440\u043c\u0438\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u044d\u0444\u0444\u0435\u043a\u0442\u043e\u0432.<\/p>\n<\/li>\n<\/ul>\n<p><em>Compose-\u044d\u0444\u0444\u0435\u043a\u0442\u044b \u2014 <\/em>\u044d\u0442\u043e \u044d\u043b\u0435\u0433\u0430\u043d\u0442\u043d\u043e\u0435 \u0432\u043e\u043f\u043b\u043e\u0449\u0435\u043d\u0438\u0435 \u0438\u0434\u0435\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0432<em> Android. <\/em>\u041e\u043d\u0438 \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u044e\u0442 \u0445\u0430\u043e\u0442\u0438\u0447\u043d\u044b\u0435 \u043f\u043e\u0431\u043e\u0447\u043d\u044b\u0435 \u044d\u0444\u0444\u0435\u043a\u0442\u044b \u0432 \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0443\u0435\u043c\u044b\u0435 \u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c\u044b\u0435 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438. \u0422\u0430\u043a\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0441\u0442\u0440\u043e\u0438\u0442\u044c \u043e\u0442\u0437\u044b\u0432\u0447\u0438\u0432\u044b\u0435 \u0438 \u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u044b\u0435 <em>UI-\u0441\u0438\u0441\u0442\u0435\u043c\u044b.<\/em><\/p>\n<h2>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f\u0445 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0439 \u0444\u0438\u0447\u0438<\/h2>\n<p>\u0423 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c:<\/p>\n<ul>\n<li>\n<p>\u0447\u0438\u0441\u0442\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438;<\/p>\n<\/li>\n<li>\n<p><em>Either<\/em> \u0438 <em>Compose Effects<\/em> \u0434\u043b\u044f \u0431\u043e\u0440\u044c\u0431\u044b \u0441 \u00ab\u0433\u0440\u044f\u0437\u043d\u044b\u043c\u0438\u00bb \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u043c\u0438;<\/p>\n<\/li>\n<li>\n<p><em>Closure (Capability Passing)<\/em> \u0434\u043b\u044f \u0437\u0430\u043c\u0435\u043d\u044b <em>DI<\/em>;<\/p>\n<\/li>\n<li>\n<p><em>ELM-\u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430<\/em>, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u044d\u0442\u043e \u0432\u0441\u0451 \u0434\u043e\u043b\u0436\u043d\u043e \u043f\u043e \u0438\u0434\u0435\u0435 \u0437\u0430\u0432\u0435\u0441\u0442\u0438\u0441\u044c.<\/p>\n<\/li>\n<\/ul>\n<p>\u0414\u043e\u0441\u043a\u043e\u043d\u0430\u043b\u044c\u043d\u043e \u0440\u0430\u0441\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u043a\u0430\u0436\u0434\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 \u0438 \u044d\u043a\u0440\u0430\u043d \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u044f \u043d\u0435 \u0431\u0443\u0434\u0443 \u2014 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u044e \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u0430\u043c\u044b\u0435 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0435 \u043a\u0435\u0439\u0441\u044b. \u0418\u0442\u043e\u0433\u043e\u0432\u044b\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043d\u0430\u0439\u0434\u0451\u0442\u0435 \u0432 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u043c \u043a\u043e\u0434\u0435 \u2014 <a href=\"https:\/\/github.com\/realist-pessimist\/FRP-SilentMoon\" rel=\"noopener noreferrer nofollow\">\u043e\u043d \u0442\u0443\u0442, \u0432 \u0432\u0435\u0442\u043a\u0435 <em>feature\/make_application<\/em><\/a>.<\/p>\n<p>\u041d\u0430\u0447\u043d\u0451\u043c \u0441 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u0439 \u0444\u0438\u0447\u0438 \u2014 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0440\u0435\u0436\u0438\u043c\u0430 \u0441\u043d\u0430 \u0438 \u0431\u043e\u0434\u0440\u0441\u0442\u0432\u043e\u0432\u0430\u043d\u0438\u044f. \u041d\u0430 \u043f\u0435\u0440\u0432\u044b\u0439 \u0432\u0437\u0433\u043b\u044f\u0434, \u0437\u0430\u0434\u0430\u0447\u0430 \u043f\u0440\u043e\u0441\u0442\u0430\u044f \u2014 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u0432\u0438\u0442\u0447\u0435\u0440 \u00ab\u0441\u0432\u0435\u0442\u043b\u0430\u044f\/\u0442\u0451\u043c\u043d\u0430\u044f \u0442\u0435\u043c\u0430\u00bb. \u041e\u0434\u043d\u0430\u043a\u043e \u043d\u0430 \u0434\u0435\u043b\u0435 \u0432\u0441\u0451 \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0441\u043b\u043e\u0436\u043d\u0435\u0435, \u0432\u0435\u0434\u044c \u0441\u0432\u0438\u0442\u0447\u0435\u0440 \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u0442\u044c\u0441\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0441\u0443\u0442\u043e\u043a.<\/p>\n<p>\u041c\u043e\u0436\u043d\u043e \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u0442\u0435\u043a\u0443\u0449\u0443\u044e \u0442\u0435\u043c\u0443 \u0432 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u0438\u043b\u0438 \u0431\u0430\u0437\u0443 \u0438 \u043f\u043e\u043c\u0435\u0449\u0430\u0442\u044c \u0432 <em>closure<\/em>. \u041d\u043e \u044f \u0445\u043e\u0447\u0443 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u043d\u0430 \u0441\u0442\u044b\u043a\u0435 \u043f\u0430\u0440\u0430\u0434\u0438\u0433\u043c. \u041f\u043e\u0439\u0434\u0451\u043c \u043f\u0440\u043e\u0442\u0438\u0432 \u043f\u0440\u0430\u0432\u0438\u043b \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e <code>CompositionLocalProvider<\/code>.\u00a0<\/p>\n<p>\u0423 \u044d\u0442\u043e\u0433\u043e \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430 \u0435\u0441\u0442\u044c \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u043a \u2014 \u043d\u0435\u044f\u0432\u043d\u0430\u044f \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0430 \u0434\u0430\u043d\u043d\u044b\u0445. \u041e\u0434\u043d\u0430\u043a\u043e \u043f\u043e\u0434 \u043d\u0430\u0448\u0443 \u0437\u0430\u0434\u0430\u0447\u0443 \u043e\u043d \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u043d\u0435\u043f\u043b\u043e\u0445\u043e.\u00a0<\/p>\n<p>\u041d\u043e \u0435\u0441\u0442\u044c \u0434\u0440\u0443\u0433\u043e\u0435 \u0432\u0430\u0436\u043d\u043e\u0435 \u0437\u0430\u043c\u0435\u0447\u0430\u043d\u0438\u0435: \u0441\u043e\u0433\u043b\u0430\u0441\u043d\u043e <a href=\"https:\/\/developer.android.com\/develop\/ui\/compose\/compositionlocal?hl=ru\" rel=\"noopener noreferrer nofollow\">\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 Google<\/a>, <code>CompositionLocal<\/code> \u0438\u043c\u0435\u0435\u0442 \u0441\u043c\u044b\u0441\u043b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c, \u043a\u043e\u0433\u0434\u0430 \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e, \u0438 \u0435\u0441\u043b\u0438 \u044d\u0442\u043e \u043f\u043e\u0442\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u043c\u043e\u0436\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043b\u044e\u0431\u043e\u0439 \u043f\u043e\u0442\u043e\u043c\u043e\u043a, \u0430 \u043d\u0435 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0438\u0437 \u043d\u0438\u0445. \u041a\u0430\u0436\u0435\u0442\u0441\u044f, \u0447\u0442\u043e \u043f\u043e \u043e\u0431\u043e\u0438\u043c \u0443\u0441\u043b\u043e\u0432\u0438\u044f\u043c \u043c\u044b \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u043c, \u0434\u0430 \u0438 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0431\u0443\u0434\u0435\u0442 \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u044c \u0432 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 <em>Composable-\u0444\u0443\u043d\u043a\u0446\u0438\u0438<\/em>.<\/p>\n<pre><code class=\"kotlin\">enum class ThemeMode {   WAKE, SLEEP }  class ThemePreferences(   private val prefs: SharedPreferences ) {   fun getThemeMode(): Either&lt;Throwable, ThemeMode?&gt; = Either.catch {     when (prefs.getString(\"theme_mode\", null)) {       \"SLEEP\" -&gt; ThemeMode.SLEEP       \"WAKE\" -&gt; ThemeMode.WAKE       else -&gt; null     }   }    fun setThemeMode(mode: ThemeMode): Either&lt;Throwable, Unit&gt; = Either.catch {     prefs.edit { putString(\"theme_mode\", mode.name) }   } }<\/code><\/pre>\n<p>\u041c\u044b \u0437\u0430\u0433\u043e\u0442\u043e\u0432\u0438\u043b\u0438 <em>Enum-\u043a\u043b\u0430\u0441\u0441<\/em> \u0434\u043b\u044f \u0432\u0438\u0434\u043e\u0432 \u0442\u0435\u043c\u044b \u0438 \u043a\u043b\u0430\u0441\u0441-\u043e\u0431\u0451\u0440\u0442\u043a\u0443 \u043d\u0430\u0434 <code>SharedPrefs<\/code> \u0434\u043b\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0442\u0435\u043c\u044b. \u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043c\u044b \u0437\u0430\u0432\u0438\u0441\u0438\u043c \u043e\u0442 \u043f\u043e\u0431\u043e\u0447\u043d\u043e\u0433\u043e \u044d\u0444\u0444\u0435\u043a\u0442\u0430 \u2014 \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u2014, \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043e\u0431\u0435\u0440\u043d\u0443\u0442\u044c \u0432\u0441\u0451 \u0432 \u043c\u043e\u043d\u0430\u0434\u0443, \u0447\u0442\u043e\u0431\u044b \u0438\u0437\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u043e\u0442 \u044d\u0444\u0444\u0435\u043a\u0442.<\/p>\n<pre><code class=\"kotlin\">class SleepWakeHandler(   private val prefs: ThemePreferences,   private val timeProvider: () -&gt; Calendar = { Calendar.getInstance() } ) {   fun getCurrentMode(): Either&lt;Throwable, ThemeMode&gt; =     prefs.getThemeMode()       .flatMap { savedMode -&gt;         savedMode?.right() ?: getDefaultThemeByTime()       }    fun setThemeMode(mode: ThemeMode): Either&lt;Throwable, Unit&gt; =     prefs.setThemeMode(mode)    private fun getDefaultThemeByTime(): Either&lt;Throwable, ThemeMode&gt; = Either.catch {     val hour = timeProvider().get(Calendar.HOUR_OF_DAY)     if (hour in 6..21) ThemeMode.WAKE else ThemeMode.SLEEP   } }<\/code><\/pre>\n<p>\u0413\u043e\u0442\u043e\u0432\u043e. \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440 \u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0434\u0430\u043d\u043d\u044b\u043c \u0432\u043d\u0443\u0442\u0440\u0438 \u043d\u0435\u0433\u043e:<\/p>\n<pre><code class=\"kotlin\">val LocalSleepWakeHandler = staticCompositionLocalOf&lt;SleepWakeHandler&gt; {   error(\"No ThemeManager provided\") }<\/code><\/pre>\n<pre><code class=\"kotlin\">@Composable fun SilentMoonApp {   val sleepWakeHandler = remember {     SleepWakeHandler(       ThemePreferences(context.getSharedPreferences(\"theme_prefs\", Context.MODE_PRIVATE))     )   }    CompositionLocalProvider(     LocalSleepWakeHandler provides sleepWakeHandler   ) {     \/*..*\/   } }<\/code><\/pre>\n<p>\u0421 <em>Base-\u0441\u043b\u043e\u0435\u043c<\/em> \u0437\u0430\u043a\u043e\u043d\u0447\u0438\u043b\u0438. \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c\u0441\u044f \u0441 \u043b\u043e\u0433\u0438\u043a\u043e\u0439 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u043e\u0432 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438.<\/p>\n<h3>\u041d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u044f<\/h3>\n<p>\u0423\u0434\u0430\u0440\u044f\u0442\u044c\u0441\u044f \u0432 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0438 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0441 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043d\u044b\u043c \u0443\u043a\u043b\u043e\u043d\u043e\u043c \u2014 \u0442\u0438\u043f\u0430 <em>Decompose \u2014<\/em> \u043d\u0435 \u0445\u043e\u0447\u0435\u0442\u0441\u044f. \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0441 <em>Jetpack Compose<\/em> \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u0435\u0439. \u041e\u043f\u0438\u0448\u0435\u043c \u043b\u043e\u0433\u0438\u043a\u0443 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u043e\u0432 \u043c\u0435\u0436\u0434\u0443 \u044d\u043a\u0440\u0430\u043d\u0430\u043c\u0438:<\/p>\n<ol>\n<li>\n<p>\u041f\u0440\u0438 \u043e\u0442\u043a\u0440\u044b\u0442\u0438\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0432\u0441\u0442\u0440\u0435\u0442\u0438\u0442 <em>Welcome-\u044d\u043a\u0440\u0430\u043d<\/em>.<\/p>\n<\/li>\n<li>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043e\u043d \u0443\u0432\u0438\u0434\u0438\u0442 <em>Onboarding-\u044d\u043a\u0440\u0430\u043d<\/em> \u0434\u043b\u044f \u0432\u044b\u0431\u043e\u0440\u0430 \u043f\u0440\u0435\u0434\u043f\u043e\u0447\u0442\u0435\u043d\u0438\u0439 \u0432 \u043c\u0435\u0434\u0438\u0442\u0430\u0446\u0438\u0438 \u2014 \u044d\u0442\u043e\u0442 \u0432\u044b\u0431\u043e\u0440 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442\u0441\u044f.<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u043f\u0430\u0434\u0430\u0435\u043c \u043d\u0430 \u0433\u043b\u0430\u0432\u043d\u0443\u044e. \u041f\u0440\u0438 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u043c \u043e\u0442\u043a\u0440\u044b\u0442\u0438\u0438 <em>Welcome-\u044d\u043a\u0440\u0430\u043d<\/em> \u0438 <em>Onboarding <\/em>\u0431\u0443\u0434\u0443\u0442 \u043f\u0440\u043e\u043f\u0443\u0449\u0435\u043d\u044b, \u0435\u0441\u043b\u0438 \u043e\u043d\u0438 \u0443\u0436\u0435 \u0431\u044b\u043b\u0438 \u043f\u0440\u043e\u0439\u0434\u0435\u043d\u044b.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430 \u0433\u043b\u0430\u0432\u043d\u043e\u0439 \u2014 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u0435\u0439 \u043a\u043e\u0440\u043d\u0435\u0432\u044b\u0445 \u044d\u043a\u0440\u0430\u043d\u043e\u0432: <em>Home, Meditate, Sleep<\/em>.<\/p>\n<\/li>\n<\/ol>\n<p>\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0433\u043e:<\/p>\n<ol>\n<li>\n<p>\u041d\u0430 \u0433\u043b\u0430\u0432\u043d\u043e\u0439 \u2014 \u043f\u0440\u0438\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0435 \u0441 \u0443\u0447\u0451\u0442\u043e\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0441\u0443\u0442\u043e\u043a, <em>Suggests-\u043f\u0430\u043d\u0435\u043b\u044c<\/em> \u0438 \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0430\u0446\u0438\u0438.<\/p>\n<\/li>\n<li>\n<p>\u042d\u043a\u0440\u0430\u043d \u0441 \u0434\u0435\u0442\u0430\u043b\u044c\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0435\u0439 \u043a\u0443\u0440\u0441\u0430: \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0430 \u043f\u043e \u0438\u0437\u0431\u0440\u0430\u043d\u043d\u044b\u043c \u0438 \u043f\u0440\u043e\u0441\u043b\u0443\u0448\u0438\u0432\u0430\u043d\u0438\u044f\u043c, \u043f\u043e\u0434\u0431\u043e\u0440\u043a\u0430 \u0438\u0437 \u0430\u0443\u0434\u0438\u043e\u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u0441 \u0434\u0432\u0443\u043c\u044f \u0442\u0438\u043f\u0430\u043c\u0438 \u0433\u043e\u043b\u043e\u0441\u043e\u0432.<\/p>\n<\/li>\n<li>\n<p>\u041c\u0435\u0434\u0438\u0442\u0430\u0446\u0438\u044f \u2014 \u043f\u043e\u0434\u0431\u043e\u0440\u043a\u0430 \u043c\u0435\u0434\u0438\u0442\u0430\u0446\u0438\u0439 \u0438 \u043f\u0430\u043d\u0435\u043b\u044c \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u0438. \u041f\u0440\u0438 \u043a\u043b\u0438\u043a\u0435 \u043d\u0430 \u044d\u0442\u0443 \u0432\u043a\u043b\u0430\u0434\u043a\u0443 \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u0440\u0435\u0436\u0438\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0435\u0441\u043b\u0438 \u0434\u043e \u044d\u0442\u043e\u0433\u043e \u0431\u044b\u043b \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d \u0440\u0435\u0436\u0438\u043c \u0441\u043d\u0430.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u043e\u0438\u0433\u0440\u044b\u0432\u0430\u0442\u0435\u043b\u044c. \u041f\u0435\u0440\u0435\u043c\u043e\u0442\u043a\u0430 \u0436\u0435\u0441\u0442\u043e\u043c \u043d\u0430 \u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0443\u044e \u0432\u0435\u043b\u0438\u0447\u0438\u043d\u0443, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0435 \u043f\u0440\u043e\u0438\u0433\u0440\u044b\u0432\u0430\u043d\u0438\u0435.<\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u043d. \u0410\u043d\u0430\u043b\u043e\u0433 \u044d\u043a\u0440\u0430\u043d\u0430 \u043c\u0435\u0434\u0438\u0442\u0430\u0446\u0438\u0438, \u043d\u043e \u0441 \u043f\u043e\u0434\u0431\u043e\u0440\u043a\u0430\u043c\u0438 \u0434\u043b\u044f \u0441\u043d\u0430. \u041f\u0440\u0438 \u043a\u043b\u0438\u043a\u0435 \u043d\u0430 \u044d\u0442\u0443 \u0432\u043a\u043b\u0430\u0434\u043a\u0443 \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0440\u0435\u0436\u0438\u043c \u0441\u043d\u0430 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438.<\/p>\n<\/li>\n<\/ol>\n<pre><code class=\"kotlin\">enum class Destination(   val route: String,   val label: String,   val contentDescription: String,   @DrawableRes val icon: Int ) {   HOME(     route = \"home\",     label = \"Home\",     contentDescription = \"Home screen\",     icon = R.drawable.ic_home   ),   \/*\u041e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u0442\u0430\u0431\u044b*\/ } <\/code><\/pre>\n<pre><code class=\"kotlin\">@Composable fun BottomBar(   navController: NavHostController, ) {   val navBackStackEntry by navController.currentBackStackEntryAsState()   val currentDestination = navBackStackEntry?.destination   val sleepWakeHandler = LocalSleepWakeHandler.current    val themeMode by sleepWakeHandler.currentModeFlow.collectAsState()   val themeResources = remember(themeMode) {     themeMode.fold(       ifLeft = { getThemeResources(ThemeMode.WAKE) },       ifRight = { getThemeResources(it) }     )   }    NavigationBar(     windowInsets = NavigationBarDefaults.windowInsets,     containerColor = themeResources.animatedBackgroundColor,   ) {     Destination.entries.forEach { destination -&gt;       NavigationBarItem(         selected = destination.route == currentDestination?.route,         onClick = {           if (destination.route != currentDestination?.route) {             navController.navigate(destination.route) {               popUpTo(navController.graph.startDestinationId) {                 saveState = true               }               launchSingleTop = true               restoreState = true             }             when (destination) {               Destination.SLEEP -&gt; sleepWakeHandler.setThemeMode(ThemeMode.SLEEP)               Destination.MEDITATION -&gt; sleepWakeHandler.setThemeMode(ThemeMode.WAKE)               else -&gt; {}             }           }         }, }<\/code><\/pre>\n<p>\u0412 \u043a\u043e\u0434\u0435 \u0432\u044b\u0448\u0435 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0443\u044e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e <code>BottomBar<\/code> \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u0438. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u044e\u0441\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u043f\u0430\u0440\u0435 \u043c\u0435\u0441\u0442. \u0422\u0430\u043a \u043a\u0430\u043a \u0437\u0430\u0434\u0430\u0447\u0430 \u0441\u0442\u043e\u0438\u0442 \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u043e \u0440\u0435\u0430\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0442\u0435\u043c\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u043e\u0434\u043f\u0438\u0441\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u043f\u043e\u0442\u043e\u043a, \u043e\u0442\u0432\u0435\u0447\u0430\u044e\u0449\u0438\u0439 \u0437\u0430 \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u0439 \u0440\u0435\u0436\u0438\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043c\u044b \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0434\u043e\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c <code>SleepWakeHandler<\/code>. \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043f\u043e\u0442\u043e\u043a \u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439. \u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0440\u0438 \u0432\u044b\u0431\u043e\u0440\u0435 \u0432\u043a\u043b\u0430\u0434\u043a\u0438 <em>Sleep<\/em> \u0438 <em>Meditate<\/em> \u0445\u044d\u043d\u0434\u043b\u0435\u0440 \u0431\u0443\u0434\u0435\u0442 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u0440\u0435\u0436\u0438\u043c \u043f\u0440\u0438 \u043a\u043b\u0438\u043a\u0435 \u043d\u0430 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u0442\u0430\u0431\u044b.<\/p>\n<pre><code class=\"kotlin\">class SleepWakeHandler(\/*..*\/) {    private val _currentModeFlow = MutableStateFlow&lt;Either&lt;Throwable, ThemeMode&gt;&gt;(Either.Right(ThemeMode.WAKE))   val currentModeFlow: StateFlow&lt;Either&lt;Throwable, ThemeMode&gt;&gt; = _currentModeFlow    init {     refreshTheme()   }    fun getCurrentMode(): Either&lt;Throwable, ThemeMode&gt; = _currentModeFlow.value    private fun refreshTheme() {     prefs.getThemeMode()       .flatMap { savedMode -&gt;         savedMode?.right() ?: getDefaultThemeByTime()       }       .fold(         ifLeft = { error -&gt;           _currentModeFlow.value = Either.Left(error)         },         ifRight = { mode -&gt;           _currentModeFlow.value = Either.Right(mode)         }       )   } }<\/code><\/pre>\n<p>\u041f\u043e \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0438 \u0441\u043e <code>SleepWakeHandler<\/code> \u0434\u043b\u044f \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0437\u0430\u0434\u0430\u0447\u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c <code><em>ProfileProvider<\/em><\/code>, \u0447\u0442\u043e\u0431\u044b \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0431\u0435\u0441\u0448\u043e\u0432\u043d\u044b\u043c \u043e\u0442\u043a\u0440\u044b\u0442\u0438\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f: \u0434\u043b\u044f \u0441\u043b\u0443\u0447\u0430\u044f, \u043a\u043e\u0433\u0434\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0443\u0436\u0435 \u043f\u0440\u043e\u0448\u0451\u043b \u043e\u043d\u0431\u043e\u0440\u0434\u0438\u043d\u0433, \u0438 \u0434\u043b\u044f \u0441\u043b\u0443\u0447\u0430\u044f, \u043a\u043e\u0433\u0434\u0430 \u043e\u043d \u0435\u0433\u043e \u0435\u0449\u0451 \u043d\u0435 \u043f\u0440\u043e\u0448\u0451\u043b. \u041e\u043d \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0441\u0442\u0430\u0432\u0449\u0438\u043a\u043e\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u0434\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u044d\u0442\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u0438. \u0422\u043e\u043b\u044c\u043a\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u0431\u0443\u0434\u0435\u043c \u0443\u0436\u0435 \u0431\u0435\u0437 <code>CompositionLocalProvider<\/code>.\u00a0<\/p>\n<p><code>CompositionLocalProvider<\/code> \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u043c \u0440\u0435\u0448\u0435\u043d\u0438\u0435\u043c \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u0432 <em>Compose-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445<\/em>. \u041e\u0434\u043d\u0430\u043a\u043e \u043d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u043e\u043d \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u0431\u043e\u043b\u044c\u0448\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c, \u0447\u0435\u043c \u0440\u0435\u0448\u0430\u0435\u0442.<\/p>\n<p>\u0415\u0433\u043e \u0433\u043b\u0430\u0432\u043d\u0430\u044f \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0432 \u043d\u0435\u044f\u0432\u043d\u043e\u0441\u0442\u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439. \u041a\u043e\u0433\u0434\u0430 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0431\u0435\u0440\u0451\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u0447\u0435\u0440\u0435\u0437 <code>CompositionLocal.current<\/code>, \u0435\u0433\u043e \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u043a \u0432\u043d\u0435\u0448\u043d\u0435\u043c\u0443 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0443 \u0441\u0442\u0430\u043d\u043e\u0432\u044f\u0442\u0441\u044f \u0441\u043a\u0440\u044b\u0442\u044b\u043c\u0438. \u041f\u0440\u043e\u0441\u0442\u043e \u0432\u0437\u0433\u043b\u044f\u043d\u0443\u0442\u044c \u043d\u0430 \u0441\u0438\u0433\u043d\u0430\u0442\u0443\u0440\u0443 \u0438 \u043f\u043e\u043d\u044f\u0442\u044c, \u0447\u0442\u043e \u043d\u0443\u0436\u043d\u043e \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b, \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0441\u044f, \u0430 \u044d\u0442\u043e \u0443\u0441\u043b\u043e\u0436\u043d\u044f\u0435\u0442 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435, \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043a\u043e\u0434\u0430 \u0438 \u0430\u043d\u0430\u043b\u0438\u0437 \u043f\u043e\u0442\u043e\u043a\u043e\u0432 \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<p>\u0410 \u0435\u0449\u0451 <code>CompositionalLocal<\/code> \u043d\u0430\u0440\u0443\u0448\u0430\u0435\u0442 \u043f\u0440\u0438\u043d\u0446\u0438\u043f \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u0443\u0435\u043c\u043e\u0439 \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438. \u0412 \u043a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u043e\u043c <em>DI <\/em>\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u044b \u0441\u0432\u043e\u0435\u0439 \u043e\u0431\u043b\u0430\u0441\u0442\u044c\u044e \u2014 \u044d\u043a\u0440\u0430\u043d\u043e\u043c \u0438\u043b\u0438 \u043c\u043e\u0434\u0443\u043b\u0435\u043c \u2014 \u0430 \u0442\u0443\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043c\u043e\u0436\u0435\u0442 \u00ab\u043f\u0440\u043e\u0442\u0435\u043a\u0430\u0442\u044c\u00bb \u0432 \u043b\u044e\u0431\u0443\u044e \u0434\u043e\u0447\u0435\u0440\u043d\u044e\u044e \u043a\u043e\u043c\u043f\u043e\u0437\u0438\u0446\u0438\u044e, \u0434\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u044d\u0442\u043e\u0433\u043e \u043d\u0435 \u043f\u0440\u0435\u0434\u043f\u043e\u043b\u0430\u0433\u0430\u043b\u043e\u0441\u044c. \u0412 \u0438\u0442\u043e\u0433\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u0445\u0440\u0443\u043f\u043a\u0443\u044e \u0441\u0432\u044f\u0437\u044c \u043c\u0435\u0436\u0434\u0443 \u043d\u0435 \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u043c\u0438 \u0447\u0430\u0441\u0442\u044f\u043c\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<p>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <code>CompositionLocalProvider<\/code> \u043a\u0430\u043a \u0437\u0430\u043c\u0435\u043d\u0443 <em>DI-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430<\/em> \u0432\u043e\u043e\u0431\u0449\u0435 \u043e\u043f\u0430\u0441\u043d\u043e. \u0412 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 \u0441\u0438\u0441\u0442\u0435\u043c \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u044f \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439, \u043e\u043d \u043d\u0435 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u044b\u043c \u0446\u0438\u043a\u043b\u043e\u043c \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432, \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u043a\u0432\u0430\u043b\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u044b \u0438\u043b\u0438 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u0432. \u041f\u043e \u0441\u0443\u0442\u0438, \u044d\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e \u0434\u0435\u0440\u0435\u0432\u0443 <em>UI<\/em>.<\/p>\n<p>\u0414\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044f\u043c\u0438 \u043b\u0443\u0447\u0448\u0435 \u0432\u044b\u0431\u0440\u0430\u0442\u044c <em>Dagger\/Hilt, Koin<\/em> \u0438\u043b\u0438 \u0440\u0443\u0447\u043d\u043e\u0435 \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u0435 \u0447\u0435\u0440\u0435\u0437 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0438 \u0434\u0435\u043b\u0435\u0433\u0430\u0442\u044b. <code>CompositionLocal<\/code> \u0441\u0442\u043e\u0438\u0442 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0442\u044c \u0434\u043b\u044f \u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0440\u0438\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0445 \u043a <em>UI<\/em> \u0434\u0430\u043d\u043d\u044b\u0445: \u0442\u0435\u043c\u0435, \u043b\u043e\u043a\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438, \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0443, \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u0438. \u0412\u0441\u0451 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0435 \u043f\u0440\u0438\u0432\u0435\u0434\u0451\u0442 \u043a \u0441\u043f\u0430\u0433\u0435\u0442\u0442\u0438-\u043a\u043e\u0434\u0443, \u0433\u0434\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043d\u0435\u044f\u0432\u043d\u044b, \u0430 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u043d\u0435\u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0443\u0435\u043c\u043e.<\/p>\n<p>\u0412\u0435\u0440\u043d\u0451\u043c\u0441\u044f \u043a \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u0438:<\/p>\n<pre><code class=\"kotlin\">NavHost(   navController = navController,   startDestination = if (profileProvider.isOnboardingCompleted()) Destination.HOME.route else \"welcome\", ) {   composable(\"welcome\") {     sleepWakeHandler.getCurrentMode().fold(       ifLeft = { ErrorScreen() },       ifRight = { mode -&gt;         handleThemeMode(           mode = mode,            onWake = {              WelcomeScreen {                navigateFromWelcomeToHome(profileProvider, navController)              }            },            onSleep = {              WelcomeSleepScreen {                navigateFromWelcomeToHome(profileProvider, navController)              }            }          )        }     )  }   composable(\"choose_topic\") {    ChooseTopicScreen {      navigateFromOnboardingToHome(profileProvider, navController)    } }<\/code><\/pre>\n<p>\u042f \u043d\u0435 \u0441\u0442\u0430\u043b \u0443\u0441\u043b\u043e\u0436\u043d\u044f\u0442\u044c \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0443 \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u0438, \u0442\u0430\u043a \u0447\u0442\u043e \u0432\u0441\u0451 \u0432 \u043e\u0434\u043d\u043e\u0439 \u0433\u0440\u0430\u0444\u0435. \u0412 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445 \u044d\u0442\u043e\u043c\u0443 \u0441\u0442\u043e\u0438\u0442 \u0443\u0434\u0435\u043b\u0438\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u0438 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u0433\u0440\u0430\u0444\u044b \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u0438 \u043f\u043e\u0434 \u0432\u0430\u0448\u0438 \u043d\u0443\u0436\u0434\u044b.<\/p>\n<h2>ELM-\u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u0432 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0438<\/h2>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0440\u043e\u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0438\u0440\u0443\u044e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e <em>ELM<\/em>. \u0421\u0434\u0435\u043b\u0430\u044e \u044d\u0442\u043e \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u044d\u043a\u0440\u0430\u043d\u0430 \u043c\u0435\u0434\u0438\u0430\u043f\u0440\u043e\u0438\u0433\u0440\u044b\u0432\u0430\u0442\u0435\u043b\u044f. \u0410\u043b\u0433\u043e\u0440\u0438\u0442\u043c \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0444\u0438\u0447\u0435\u0439 \u0442\u0430\u043a\u043e\u0439:<\/p>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/475\/d93\/126\/475d93126c1b6d74508705540230559a.png\" alt=\"\u0422\u0438\u043f\u043e\u0432\u043e\u0439 \u043d\u0430\u0431\u043e\u0440 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u0434\u043b\u044f \u0444\u0438\u0447\u0438\" title=\"\u0422\u0438\u043f\u043e\u0432\u043e\u0439 \u043d\u0430\u0431\u043e\u0440 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u0434\u043b\u044f \u0444\u0438\u0447\u0438\" width=\"556\" height=\"430\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/475\/d93\/126\/475d93126c1b6d74508705540230559a.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/475\/d93\/126\/475d93126c1b6d74508705540230559a.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u0422\u0438\u043f\u043e\u0432\u043e\u0439 \u043d\u0430\u0431\u043e\u0440 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u0434\u043b\u044f \u0444\u0438\u0447\u0438<\/figcaption><\/div>\n<\/figure>\n<ul>\n<li>\n<p>\u0432\u0432\u043e\u0434\u0438\u043c \u0441\u0442\u0435\u0439\u0442 \u044d\u043a\u0440\u0430\u043d\u0430, \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u043d\u0435\u0433\u043e;<\/p>\n<\/li>\n<li>\n<p>\u0441\u043e\u0437\u0434\u0430\u0451\u043c \u0441\u043f\u0438\u0441\u043e\u043a \u0441\u043e\u0431\u044b\u0442\u0438\u0439, \u044d\u0444\u0444\u0435\u043a\u0442\u043e\u0432 \u0438 \u043a\u043e\u043c\u0430\u043d\u0434;<\/p>\n<\/li>\n<li>\n<p>\u0432\u044b\u0434\u0435\u043b\u044f\u0435\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438;<\/p>\n<\/li>\n<li>\n<p>\u043f\u0438\u0448\u0435\u043c \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 <code>Actor<\/code> \u0438 <code>Reducer<\/code>.<\/p>\n<\/li>\n<\/ul>\n<pre><code class=\"kotlin\">data class PlayerState(   val musicItem: MusicItem? = null,   val isPlaying: Boolean = false,   val progress: Long = 0,   val isFavorite: Boolean = false,   val error: String? = null ) : State  sealed class PlayerCommand : Command {   data class LoadMusic(val musicId: MusicId) : PlayerCommand()   data class StartPlayback(val item: MusicItem) : PlayerCommand()   data object PausePlayback : PlayerCommand()   data object StopPlayback : PlayerCommand()   data class SeekToPosition(val offsetMs: Long) : PlayerCommand()   data class RewindPlayback(val offsetMs: Long) : PlayerCommand()   data class ToggleFavoriteStatus(val musicId: MusicId) : PlayerCommand() }  sealed class PlayerEffect : Effect {   data class ShowError(val message: String) : PlayerEffect() }  sealed class PlayerEvent : Event {   data class StartLoad(val musicId: MusicId) : PlayerEvent()   data class MusicLoaded(val musicItem: MusicItem) : PlayerEvent()   data class ErrorOccurred(val message: String) : PlayerEvent()      data object PlaybackStateChanged : PlayerEvent()   data object PlaybackStopped : PlayerEvent()      data class PaybackSought(val offsetMs: Long) : PlayerEvent()   data class PaybackRewound(val offsetMs: Long) : PlayerEvent()   data class PositionChanged(val position: Long) : PlayerEvent()    data class FavoriteClicked(val musicId: MusicId) : PlayerEvent()   data class FavoriteStatusChanged(val isFavorite: Boolean) : PlayerEvent() }<\/code><\/pre>\n<pre><code class=\"kotlin\">interface MusicPlayerCapability {   val audioPlayer: AudioPlayer }  interface MusicDataCapability {   val musicRepository: MusicRepository }  class PlayerCapabilityImpl(   override val audioPlayer: AudioPlayer,   override val musicRepository: MusicRepository ) : MusicDataCapability, MusicPlayerCapability  fun makePlayerCapability(   context: Context,   coroutineScope: CoroutineScope,   audioPlayer: AudioPlayer = ExoAudioPlayer(context, coroutineScope),   musicRepository: MusicRepository = FakeMusicRepository(context), ) = PlayerCapabilityImpl(   audioPlayer = audioPlayer,   musicRepository = musicRepository, )<\/code><\/pre>\n<p>\u041d\u0430\u043f\u043e\u043b\u043d\u0438\u043c \u043b\u043e\u0433\u0438\u043a\u043e\u0439 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 <code>ExoAudioPlayer<\/code> \u0438 <code>FakeMusicRepository<\/code>:<\/p>\n<details class=\"spoiler\">\n<summary>FakeMusicRepository<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"kotlin\">class FakeMusicRepository(context: Context) : MusicRepository {   private val mutex = Mutex()   private val databaseFile = File(context.filesDir, \"music_database.json\")   private val json = Json { prettyPrint = true }     private val initialDatabase = MusicDatabase(     items = mapOf(       MusicId(\"1\") to MusicItem(\/*..*\/),       \/*..*\/     )   )    private fun loadDatabase(): Either&lt;MusicError, MusicDatabase&gt; = either {     if (!databaseFile.exists()) {       return@either initialDatabase     }      Either.catch { json.decodeFromString&lt;MusicDatabase&gt;(databaseFile.readText()) }       .mapLeft { MusicError.FileReadError }       .getOrElse { initialDatabase }   }    private fun saveDatabase(db: MusicDatabase): Either&lt;MusicError, Unit&gt; = either {     Either.catch { databaseFile.writeText(json.encodeToString(db)) }       .mapLeft { MusicError.FileWriteError }       .bind()   }    private val currentDatabase: MutableStateFlow&lt;Either&lt;MusicError, MusicDatabase&gt;&gt; by lazy {     MutableStateFlow(loadDatabase())   }    override suspend fun getMusicById(id: MusicId): Either&lt;MusicError, MusicItem&gt; = either {     val db = currentDatabase.value.bind()     db.items[id] ?: raise(MusicError.NotFound)   }    override suspend fun toggleFavorite(id: MusicId): Either&lt;MusicError, Boolean&gt; = either {     mutex.withLock {       val currentDb = currentDatabase.value.bind()       val currentItem = currentDb.items[id] ?: raise(MusicError.NotFound)       val updatedItem = currentItem.copy(isFavorite = !currentItem.isFavorite)       val newDb = currentDb.copy(items = currentDb.items + (id to updatedItem))        saveDatabase(newDb).bind()       currentDatabase.value = Either.Right(newDb)        updatedItem.isFavorite     }   } }<\/code><\/pre>\n<\/div>\n<\/details>\n<p>\u041a\u043b\u0430\u0441\u0441 <code>FakeMusicRepository<\/code> \u0445\u0440\u0430\u043d\u0438\u0442 \u043c\u0443\u0437\u044b\u043a\u0430\u043b\u044c\u043d\u044b\u0435 \u0442\u0440\u0435\u043a\u0438 \u0432 <em>JSON-\u0444\u0430\u0439\u043b\u0435<\/em>, \u0430 \u043d\u0435 \u0432 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0435\u0439 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445. \u042d\u0442\u043e \u0441\u0434\u0435\u043b\u0430\u043d\u043e \u0434\u043b\u044f \u0443\u043f\u0440\u043e\u0449\u0435\u043d\u0438\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430: \u043d\u0430\u043c \u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u0441\u043b\u043e\u0436\u043d\u044b\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u2014 <em>Room<\/em> \u0438\u043b\u0438 <em>SQLite<\/em> \u2014, \u043d\u043e \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043b\u043e\u0433\u0438\u043a\u0443 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435\u043c: \u0447\u0442\u0435\u043d\u0438\u0435, \u0437\u0430\u043f\u0438\u0441\u044c, \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435.<\/p>\n<p>\u041d\u0430\u0447\u0430\u043b\u044c\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 <code>initialDatabase<\/code> \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0445 \u0442\u0440\u0435\u043a\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043b\u0438\u0431\u043e \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u044e\u0442\u0441\u044f \u0438\u0437 \u0444\u0430\u0439\u043b\u0430, \u043b\u0438\u0431\u043e \u0441\u043e\u0437\u0434\u0430\u044e\u0442\u0441\u044f \u043f\u0440\u0438 \u043f\u0435\u0440\u0432\u043e\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0435.<\/p>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0441 \u0444\u0430\u0439\u043b\u043e\u043c \u043c\u043e\u0433\u0443\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u0438\u0437 \u0440\u0430\u0437\u043d\u044b\u0445 \u043f\u043e\u0442\u043e\u043a\u043e\u0432, \u043d\u0443\u0436\u0435\u043d \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0438, \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u0443\u044e\u0449\u0438\u0439, \u0447\u0442\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0430 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u043c\u043e\u0436\u0435\u0442 \u0438\u0437\u043c\u0435\u043d\u044f\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u0432\u0440\u0435\u043c\u0435\u043d\u0438. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u0440\u0438 \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u043c \u0432\u044b\u0437\u043e\u0432\u0435 <code>toggleFavorite<\/code> \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f <code>Mutex<\/code>. \u0411\u0435\u0437 \u043d\u0435\u0433\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b \u043a\u043e\u043d\u0444\u043b\u0438\u043a\u0442\u044b \u043f\u0440\u0438 \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e\u0439 \u0437\u0430\u043f\u0438\u0441\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u043f\u043e\u0432\u0440\u0435\u0434\u0438\u0442\u044c \u0444\u0430\u0439\u043b.<\/p>\n<p><code>either{}<\/code><em> <\/em>\u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u0431\u043b\u043e\u043a, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0441 \u043e\u0448\u0438\u0431\u043a\u043e\u0439. \u0415\u0441\u043b\u0438 \u043d\u0430 \u043a\u0430\u043a\u043e\u043c-\u0442\u043e \u044d\u0442\u0430\u043f\u0435 \u043f\u0440\u043e\u0438\u0437\u043e\u0439\u0434\u0451\u0442 \u0441\u0431\u043e\u0439, \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0438\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441\u043a\u0438\u043f\u043d\u0443\u0442\u0441\u044f \u0438 \u0441\u0440\u0430\u0437\u0443 \u0432\u0435\u0440\u043d\u0451\u0442\u0441\u044f \u043e\u0448\u0438\u0431\u043a\u0430.<\/p>\n<p><code>bind()<\/code><em> <\/em>\u00ab\u0440\u0430\u0437\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0435\u0442\u00bb \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438. \u041f\u043e\u043b\u0443\u0447\u0438\u043b\u0438<em> <\/em><code>Either.Left <\/code><em>\u2014 <\/em>\u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043f\u0440\u0435\u0440\u0432\u0451\u0442\u0441\u044f \u0438 \u043e\u0448\u0438\u0431\u043a\u0430 \u0432\u0435\u0440\u043d\u0451\u0442\u0441\u044f \u0438\u0437 <code>either<\/code><em>, <\/em>\u0430 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438<em> <\/em><code>Either.Right<\/code><em> \u2014 <\/em>\u0440\u0430\u0431\u043e\u0442\u0430 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u0441\u044f \u0441 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c.<\/p>\n<p><code>ensure()<\/code> \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0443\u0441\u043b\u043e\u0432\u0438\u0435. \u0415\u0441\u043b\u0438 \u043e\u043d\u043e \u043d\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430. \u042d\u0442\u043e \u0430\u043d\u0430\u043b\u043e\u0433 <code>if (!condition) return error<\/code> \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u043c \u0441\u0442\u0438\u043b\u0435.<\/p>\n<p><code>raise()<\/code> \u043f\u0440\u0438\u043d\u0443\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u0440\u0435\u0440\u044b\u0432\u0430\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0441 \u043e\u0448\u0438\u0431\u043a\u043e\u0439 \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e <code>throw<\/code>, \u043d\u043e \u0431\u0435\u0437 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0439.<\/p>\n<p>\u0415\u0441\u043b\u0438 \u043d\u0430 \u043b\u044e\u0431\u043e\u043c \u0438\u0437 \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u044b\u0445 \u0432\u044b\u0448\u0435 \u044d\u0442\u0430\u043f\u043e\u0432 \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u0435\u0442 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430, \u0432\u0441\u044f \u0446\u0435\u043f\u043e\u0447\u043a\u0430 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f.<\/p>\n<details class=\"spoiler\">\n<summary>ExoAudioPlayer<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"kotlin\">class ExoAudioPlayer(context: Context, scope: CoroutineScope) : AudioPlayer {          \/\/ \u041c\u043e\u0434\u0435\u043b\u044c \u043e\u0448\u0438\u0431\u043e\u043a \u043f\u043b\u0435\u0435\u0440\u0430     sealed interface Error {          data class PlaybackFailed(val cause: Throwable) : Error      }          \/\/ \u0421\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043f\u043b\u0435\u0435\u0440\u0430 (\u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0447\u0435\u0440\u0435\u0437 Either \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043e\u0448\u0438\u0431\u043e\u043a)     private val playerState = MutableStateFlow&lt;Either&lt;Error, ExoPlayer&gt;&gt;(...)     private val playbackState = MutableStateFlow&lt;Either&lt;Error, PlaybackState&gt;&gt;(...)     private val positionState = MutableStateFlow&lt;Either&lt;Error, Long&gt;&gt;(...)     private var updatingPosition = false      init {         \/\/ \u041d\u0430\u0447\u0430\u043b\u044c\u043d\u0430\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0438 \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0430 \u043d\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f         observePlayerState()     }      \/\/ \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0438 \u0431\u0430\u0437\u043e\u0432\u0430\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 ExoPlayer     private fun createPlayer(context: Context): ExoPlayer {         return ExoPlayer.Builder(context)             .setAudioAttributes(...)             .build().apply {                 addListener(object : Player.Listener {                     \/\/ \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043f\u043b\u0435\u0435\u0440\u0430                     override fun onPlaybackStateChanged(state: Int) { ... }                     override fun onIsPlayingChanged(isPlaying: Boolean) { ... }                 })             }     }      override fun play(url: String) {         _playerState.value.map { player -&gt;             Either.catch {                 if (needNewMediaItem(player, url)) {                     player.setMediaItem(...)                     player.prepare()                 }                 player.play()             }.onLeft { handlePlaybackError(it) }         }     }      override fun pause() {         \/\/ \u041f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f         _playerState.value.map { it.pause().also { updatingPosition = false } }     }      override fun seekBy(ms: Long) {         \/\/ \u041f\u0435\u0440\u0435\u043c\u043e\u0442\u043a\u0430 \u043d\u0430 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043c\u0438\u043b\u043b\u0438\u0441\u0435\u043a\u0443\u043d\u0434         _playerState.value.map { it.seekTo(...) }     }      override fun release() {         \/\/ \u041e\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0435\u043d\u0438\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u043f\u043b\u0435\u0435\u0440\u0430         _playerState.value.map { it.release() }     }      \/\/ \u0412\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0435 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b     private fun observePlayerState() {         \/\/ \u041f\u043e\u0434\u043f\u0438\u0441\u043a\u0430 \u043d\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043f\u043b\u0435\u0435\u0440\u0430         scope.launch {              _playerState.collect {...}         }     }      private fun startPositionUpdates() {         \/\/ \u041f\u0435\u0440\u0438\u043e\u0434\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u043e\u0437\u0438\u0446\u0438\u0438 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f         scope.launch {              while (updatingPosition) {                 updateCurrentPosition()                 delay(200)             }         }     }      \/\/ \u0421\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f     private sealed class PlaybackState {         object Idle : PlaybackState()         object Ready : PlaybackState()         object Buffering : PlaybackState()         object Ended : PlaybackState()     } } <\/code><\/pre>\n<\/div>\n<\/details>\n<p>\u041a\u043b\u0430\u0441\u0441 <code>ExoAudioPlayer<\/code> \u0438\u043d\u043a\u0430\u043f\u0441\u0443\u043b\u0438\u0440\u0443\u0435\u0442 \u0442\u0440\u0438 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u043f\u043e\u0442\u043e\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445:<\/p>\n<ul>\n<li>\n<p>\u0442\u0435\u043a\u0443\u0449\u0435\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043f\u043b\u0435\u0435\u0440\u0430 \u2014 \u0437\u0430\u0434\u0435\u043b \u043d\u0430 \u0431\u0443\u0434\u0443\u0449\u0435\u0435 \u0434\u043b\u044f \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043f\u043b\u0435\u0435\u0440\u043e\u043c \u0432 \u0444\u043e\u043d\u0435 \u0438\u043b\u0438 \u0431\u0435\u0437 \u043f\u0440\u0438\u0432\u044f\u0437\u043a\u0438 \u043a \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u043c\u0443 \u044d\u043a\u0440\u0430\u043d\u0443;<\/p>\n<\/li>\n<li>\n<p>\u043f\u043e\u0437\u0438\u0446\u0438\u044f \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f;<\/p>\n<\/li>\n<li>\n<p>\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0435 \u043e\u0448\u0438\u0431\u043a\u0438.<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u0440\u0438 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0441\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 <code>ExoPlayer<\/code> \u0441 \u0431\u0430\u0437\u043e\u0432\u043e\u0439 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0435\u0439 \u0434\u043b\u044f \u043c\u0443\u0437\u044b\u043a\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u0430, \u0432\u043a\u043b\u044e\u0447\u0430\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u043f\u0440\u0435\u0440\u044b\u0432\u0430\u043d\u0438\u0439 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f. \u041f\u043b\u0435\u0435\u0440 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0435\u0442 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0447\u0435\u0440\u0435\u0437 <code>Player.Listener<\/code> \u0438 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 <code>StateFlow<\/code>.<\/p>\n<p>\u041b\u043e\u0433\u0438\u043a\u0430 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0432 \u0441\u0435\u0431\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043d\u0430 \u0442\u0435\u043a\u0443\u0449\u0435\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435. \u041f\u0440\u0438 \u0432\u044b\u0437\u043e\u0432\u0435 <code>play()<\/code> \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043b\u0438\u0431\u043e \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043d\u043e\u0432\u043e\u0433\u043e \u043c\u0435\u0434\u0438\u0430-\u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430, \u043b\u0438\u0431\u043e \u0432\u043e\u0437\u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u0441 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u043f\u043e\u0437\u0438\u0446\u0438\u0438. \u0423 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0442\u0440\u0435\u043a\u0430 \u043e\u043d\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441 \u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u043c \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b\u043e\u043c \u0432 <code>200\u043c\u0441<\/code> \u0442\u043e\u043b\u044c\u043a\u043e \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0433\u043e \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f, \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u0443\u044f \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c. \u041e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0441 \u043f\u043b\u0435\u0435\u0440\u043e\u043c \u2014 \u043f\u0430\u0443\u0437\u0430, \u043f\u0435\u0440\u0435\u043c\u043e\u0442\u043a\u0430 \u0438 \u0442.\u0434. \u2014 \u0437\u0430\u0449\u0438\u0449\u0435\u043d\u044b \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u043e\u0439 \u0447\u0435\u0440\u0435\u0437 <code>Either<\/code>. \u0410 \u0437\u043d\u0430\u0447\u0438\u0442 \u043e\u043d\u0438 \u0431\u0443\u0434\u0443\u0442 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u0434\u0430\u0436\u0435 \u043f\u0440\u0438 \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u043e\u0432\u0435\u043d\u0438\u0438 \u043e\u0448\u0438\u0431\u043e\u043a.<\/p>\n<p>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0441\u0442\u0438: <code>ExoPlayer<\/code> \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u043d\u0438\u0437\u043a\u043e\u0443\u0440\u043e\u0432\u043d\u0435\u0432\u044b\u043c\u0438 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044f\u043c\u0438, \u0430 \u043a\u043b\u0430\u0441\u0441-\u043e\u0431\u0451\u0440\u0442\u043a\u0430 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0447\u0438\u0441\u0442\u044b\u0439 \u0438 \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0441 \u044f\u0432\u043d\u043e\u0439 \u0442\u0438\u043f\u0438\u0437\u0430\u0446\u0438\u0435\u0439 \u0432\u0441\u0435\u0445 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0445 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439 \u0438 \u043e\u0448\u0438\u0431\u043e\u043a.<\/p>\n<p>\u042f \u043d\u0435 \u0441\u0442\u0430\u043b \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442\u044c \u044d\u0442\u0438 \u043a\u043b\u0430\u0441\u0441\u044b \u043a \u043f\u0440\u0438\u0432\u044b\u0447\u043d\u043e\u043c\u0443 <em>closure<\/em>-\u0432\u0438\u0434\u0443 \u2014 \u043d\u0435 \u0445\u043e\u0447\u0435\u0442\u0441\u044f \u0437\u0430\u0433\u0440\u043e\u043c\u043e\u0436\u0434\u0430\u0442\u044c \u043a\u043e\u0434. \u041e\u0434\u043d\u0430\u043a\u043e \u0432 \u0438\u0434\u0435\u0430\u043b\u0435 \u0438\u0445 \u0441\u0442\u043e\u0438\u0442 \u0443\u043d\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u0442\u044c.<\/p>\n<p>\u041d\u0430\u043f\u0438\u0448\u0435\u043c \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 <code>Actor<\/code> \u0438 <code>Reducer<\/code>:<\/p>\n<pre><code class=\"kotlin\">class PlayerActor&lt;Ctx&gt;(private val capabilities: Ctx) : Actor         where Ctx: MusicPlayerCapability,               Ctx: MusicDataCapability {   override suspend fun execute(command: Command): Event = when (command) {     is PlayerCommand.LoadMusic -&gt; loadMusicData(command.musicId)     is PlayerCommand.StartPlayback -&gt; playMusic(command.item)     is PlayerCommand.PausePlayback -&gt; pauseMusic()     is PlayerCommand.SeekToPosition -&gt; seekTo(command.offsetMs)     is PlayerCommand.RewindPlayback -&gt; rewind(command.offsetMs)     is PlayerCommand.ToggleFavoriteStatus -&gt; toggleFavorite(command.musicId)     is PlayerCommand.StopPlayback -&gt; stopMusic()     else -&gt; throw IllegalArgumentException(\"Unknown command\")   }    @OptIn(ExperimentalCoroutinesApi::class)   override suspend fun subscribe(): Flow&lt;Event&gt; {     return merge(       capabilities.audioPlayer.playbackState.flatMapConcat { stateEither -&gt;         stateEither.fold(           ifLeft = { ... },           ifRight = { ... }         )       },       capabilities.audioPlayer.currentPosition.flatMapConcat { positionEither -&gt;         positionEither.fold(           ifLeft = { ... },           ifRight = { ... }         )       }     )   }    private suspend fun loadMusicData(id: MusicId): Event {     return capabilities.musicRepository.getMusicById(id).fold(       ifRight = { PlayerEvent.MusicLoaded(it) },       ifLeft = { PlayerEvent.ErrorOccurred(\"Failed to load music data: $it\") }     )   }    private fun playMusic(musicItem: MusicItem): Event {     capabilities.audioPlayer.play(musicItem.audioUrl)     return PlayerEvent.NoOp   }   \/\/\u041e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u044b\/\/ }<\/code><\/pre>\n<p>\u0422\u0443\u0442 \u0432\u0441\u0451 \u043f\u0440\u043e\u0441\u0442\u043e, \u043d\u043e \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u044e\u0442 \u044f\u0432\u043d\u043e\u0433\u043e \u0440\u0435\u0430\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f <em>UI<\/em>. \u0422\u0430\u043a \u0447\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 <code>NoOp<\/code>. \u041c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0431\u044b \u0438 <em>Nullable-\u0442\u0438\u043f\u0430\u043c\u0438<\/em> \u043e\u0431\u043e\u0439\u0442\u0438\u0441\u044c, \u043d\u043e \u043c\u043d\u0435 \u0442\u0430\u043a\u043e\u0439 \u043f\u0443\u0442\u044c \u043d\u0435 \u043d\u0440\u0430\u0432\u0438\u0442\u0441\u044f, \u043e \u0447\u0451\u043c \u044f \u043f\u0438\u0441\u0430\u043b <a href=\"https:\/\/habr.com\/ru\/companies\/dododev\/articles\/917960\/\" rel=\"noopener noreferrer nofollow\">\u0432\u043e \u0432\u0442\u043e\u0440\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u0446\u0438\u043a\u043b\u0430<\/a>.<\/p>\n<pre><code class=\"kotlin\">class PlayerReducer : Reducer&lt;PlayerState, PlayerEvent&gt; {    override fun reduce(state: PlayerState, event: PlayerEvent): StateResult&lt;PlayerState&gt; {     return when (event) {       is PlayerEvent.StartLoad -&gt; handleLoadData(state, event)       is PlayerEvent.MusicLoaded -&gt; handleDataLoaded(state, event)       is PlayerEvent.ErrorOccurred -&gt; handleError(state, event)       is PlayerEvent.PlaybackStateChanged -&gt; handlePlayPause(state)       is PlayerEvent.PlaybackStopped -&gt; handleStop(state)       is PlayerEvent.PaybackSought -&gt; handleSeek(state, event)       is PlayerEvent.PaybackRewound -&gt; handleRewind(state, event)       is PlayerEvent.FavoriteClicked -&gt; handleToggleFavorite(state, event.musicId)       is PlayerEvent.PositionChanged -&gt; handlePositionChanged(state, event.position)       is PlayerEvent.PaybackEnded -&gt; handleEndedTrack(state)       else -&gt; StateResult(state)     }   }  private fun handleError(     state: PlayerState,     event: PlayerEvent.ErrorOccurred   ): StateResult&lt;PlayerState&gt; {     return StateResult(       state = state.copy(error = event.message),       effects = listOf(PlayerEffect.ShowError(event.message))     )   }   private fun handlePlayPause(     state: PlayerState,   ): StateResult&lt;PlayerState&gt; {     require(state.musicItem != null)     return StateResult(       state = state.copy(isPlaying = !state.isPlaying),       commands = listOf(         if (state.isPlaying) PlayerCommand.PausePlayback         else PlayerCommand.StartPlayback(state.musicItem)       )     )   }  \/\/ \u041e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u044f }<\/code><\/pre>\n<p>C \u0440\u0435\u0434\u044c\u044e\u0441\u0435\u0440\u043e\u043c \u0434\u0435\u043b\u043e \u043e\u0431\u0441\u0442\u043e\u0438\u0442 \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e: \u043f\u0435\u0440\u0435\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u043c\u0435\u0442\u043e\u0434 <code>reduce<\/code>, \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u2014 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435, \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0438\u043b\u0438 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c \u044d\u0444\u0444\u0435\u043a\u0442\u044b.\u00a0<\/p>\n<p>\u041d\u0430\u043c \u043d\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u0432\u044f\u0437\u0443\u044e\u0449\u0435\u0433\u043e \u0437\u0432\u0435\u043d\u0430 <code>Store<\/code>. \u0418\u043c \u0431\u0443\u0434\u0435\u0442 \u0431\u0430\u0437\u043e\u0432\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e \u043e\u0442 \u0444\u0438\u0447\u0438:<\/p>\n<pre><code class=\"kotlin\">class ElmStore&lt;S : State, E : Event&gt;(   initialState: S,   private val reducer: Reducer&lt;S, E&gt;,   private val actor: Actor,   private val coroutineScope: CoroutineScope, ) : Store&lt;S, E&gt; {    private val _state = MutableStateFlow(initialState)   private val _effects = MutableSharedFlow&lt;Effect&gt;(extraBufferCapacity = DEFAULT_EFFECTS_BUFFER)   override val state = _state.asStateFlow()   override val effects: SharedFlow&lt;Effect&gt; = _effects.asSharedFlow()    init {     coroutineScope.launch {       actor.subscribe().collect { event -&gt;         @Suppress(\"UNCHECKED_CAST\")         (event as? E)?.let { processEvent(it) }       }     }   }    override fun send(event: E) {     coroutineScope.launch {       processEvent(event)     }   }    private fun processEvent(event: E) {     val currentState = _state.value     val result = reducer.reduce(currentState, event)      _state.value = result.state      result.commands.forEach { command -&gt;       coroutineScope.launch {         when (val commandResult = actor.execute(command)) {           else -&gt; @Suppress(\"UNCHECKED_CAST\") {             processEvent(commandResult as E)           }         }       }     }      result.effects.forEach { effect -&gt;       coroutineScope.launch {         _effects.emit(effect)       }     }   }    companion object {     const val DEFAULT_EFFECTS_BUFFER = 64   } }<\/code><\/pre>\n<p>\u041a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u0430 <code>DEFAULT_EFFECTS_BUFFER<\/code> \u0441\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c <code>64<\/code> \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u0440\u0430\u0437\u043c\u0435\u0440 \u0431\u0443\u0444\u0435\u0440\u0430 \u0434\u043b\u044f <code>MutableSharedFlow<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u044d\u0444\u0444\u0435\u043a\u0442\u043e\u0432. \u042d\u0442\u043e \u043a\u043e\u043c\u043f\u0440\u043e\u043c\u0438\u0441\u0441 \u043c\u0435\u0436\u0434\u0443 \u043f\u043e\u0442\u0440\u0435\u0431\u043b\u0435\u043d\u0438\u0435\u043c \u043f\u0430\u043c\u044f\u0442\u0438 \u0438 \u0443\u0441\u0442\u043e\u0439\u0447\u0438\u0432\u043e\u0441\u0442\u044c\u044e \u043a \u043f\u0435\u0440\u0435\u0433\u0440\u0443\u0437\u043a\u0430\u043c. \u0412\u044b\u0431\u043e\u0440 \u0434\u0435\u0444\u043e\u043b\u0442\u043d\u043e\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u2014 \u0443\u0441\u043b\u043e\u0432\u043d\u044b\u0439. \u0421\u0435\u0439\u0447\u0430\u0441 \u0435\u0433\u043e \u0445\u0432\u0430\u0442\u0438\u0442 \u0441 \u0437\u0430\u043f\u0430\u0441\u043e\u043c \u0434\u043b\u044f \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u0430 \u0442\u0438\u043f\u043e\u0432\u044b\u0445 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0435\u0432, \u043a\u043e\u0433\u0434\u0430 \u044d\u0444\u0444\u0435\u043a\u0442\u044b \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0431\u044b\u0441\u0442\u0440\u043e, \u0430 \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u0432\u044b\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u043a\u0440\u0430\u0442\u043a\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0432\u0441\u043f\u043b\u0435\u0441\u043a\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0431\u0435\u0437 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0438.<\/p>\n<p>\u0411\u0443\u0444\u0435\u0440\u0438\u0437\u0430\u0446\u0438\u044f \u044d\u0444\u0444\u0435\u043a\u0442\u043e\u0432 \u0440\u0435\u0448\u0430\u0435\u0442 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443 <em>backpressure<\/em> \u2014 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u0438, \u043a\u043e\u0433\u0434\u0430 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u2014 \u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 <code>Store<\/code> \u2014 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u0431\u044b\u0441\u0442\u0440\u0435\u0435, \u0447\u0435\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u044c \u043c\u043e\u0436\u0435\u0442 \u0438\u0445 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c. \u041f\u0440\u0438 \u043f\u0435\u0440\u0435\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0438 \u0431\u0443\u0444\u0435\u0440\u0430 \u043d\u043e\u0432\u044b\u0435 \u044d\u0444\u0444\u0435\u043a\u0442\u044b \u0431\u0443\u0434\u0443\u0442 \u043e\u0442\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u0442\u044c\u0441\u044f, \u0430 \u044d\u0442\u043e \u043a\u0440\u0438\u0442\u0438\u0447\u043d\u043e \u0434\u043b\u044f \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0442\u0438\u043f\u043e\u0432 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439. \u0414\u043b\u044f \u044d\u0444\u0444\u0435\u043a\u0442\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435\u043b\u044c\u0437\u044f \u0442\u0435\u0440\u044f\u0442\u044c, \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0442 \u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0435 \u043f\u043e\u0434\u0445\u043e\u0434\u044b.<\/p>\n<p>\u041e\u0434\u0438\u043d \u0438\u0437 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 \u2014 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0431\u0435\u0441\u043a\u043e\u043d\u0435\u0447\u043d\u043e\u0433\u043e \u0431\u0443\u0444\u0435\u0440\u0430. \u041d\u043e \u044d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u0432\u0435\u0441\u0442\u0438 \u043a \u0443\u0442\u0435\u0447\u043a\u0430\u043c \u043f\u0430\u043c\u044f\u0442\u0438 \u043f\u0440\u0438 \u0434\u043e\u043b\u0433\u043e\u043c \u043d\u0430\u043a\u043e\u043f\u043b\u0435\u043d\u0438\u0438 \u043d\u0435\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043d\u044b\u0445 \u0441\u043e\u0431\u044b\u0442\u0438\u0439. \u041d\u0430\u0434\u0451\u0436\u043d\u0435\u0435 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438, \u043a\u043e\u0433\u0434\u0430 \u043a\u0430\u0436\u0434\u044b\u0439 \u044d\u0444\u0444\u0435\u043a\u0442 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u044f\u0432\u043d\u043e\u0433\u043e <em>ack<\/em> \u043e\u0442 \u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u044f \u043f\u0435\u0440\u0435\u0434 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u043e\u0439 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u044d\u0444\u0444\u0435\u043a\u0442\u0430. \u0412 \u044d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <code>Channel<\/code> \u0432\u043c\u0435\u0441\u0442\u043e <code>SharedFlow<\/code> \u0441 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0439 \u043b\u043e\u0433\u0438\u043a\u043e\u0439 \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u044f.<\/p>\n<p>\u0414\u043b\u044f \u0441\u0438\u0441\u0442\u0435\u043c, \u0433\u0434\u0435 \u043a\u0440\u0438\u0442\u0438\u0447\u043d\u0430 \u043d\u0430\u0434\u0451\u0436\u043d\u0430\u044f \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u0430, \u0441\u0442\u043e\u0438\u0442 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043f\u043e\u043b\u0438\u0442\u0438\u043a\u0443 <em>retry<\/em> \u0434\u043b\u044f \u044d\u0444\u0444\u0435\u043a\u0442\u043e\u0432 \u2014 \u043f\u0440\u0438 \u043d\u0435\u0443\u0434\u0430\u0447\u043d\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u044d\u0444\u0444\u0435\u043a\u0442 \u043f\u043e\u043c\u0435\u0449\u0430\u0435\u0442\u0441\u044f \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u0439 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438. \u0412 \u0441\u043b\u043e\u0436\u043d\u044b\u0445 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u044f\u0445 \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u044d\u0444\u0444\u0435\u043a\u0442\u043e\u0432 \u043d\u0430 \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0438 \u2014 \u043a\u0440\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0438 \u043d\u0435\u043a\u0440\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u2014 \u0441 \u0440\u0430\u0437\u043d\u044b\u043c\u0438 \u0441\u0442\u0440\u0430\u0442\u0435\u0433\u0438\u044f\u043c\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0438\u043b\u0438 \u0432\u0430\u0436\u043d\u044b\u0435 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f \u0434\u043e\u043b\u0436\u043d\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043a\u0430\u043d\u0430\u043b \u0441 \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0439 \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u043e\u0439, \u0430 \u0432\u0442\u043e\u0440\u043e\u0441\u0442\u0435\u043f\u0435\u043d\u043d\u044b\u0435 <em>UI-\u044d\u0444\u0444\u0435\u043a\u0442\u044b<\/em> \u043c\u043e\u0433\u0443\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0438 \u0447\u0435\u0440\u0435\u0437 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u0431\u0443\u0444\u0435\u0440\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u043f\u043e\u0442\u043e\u043a.<\/p>\n<p>\u0422\u043e\u0447\u043a\u0430 \u0432\u0445\u043e\u0434\u0430 \u0441\u0432\u044f\u0437\u0438 \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0438 \u0441 <em>UI<\/em> \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0442\u0430\u043a:<\/p>\n<pre><code class=\"kotlin\">@Composable fun &lt;Ctx&gt; rememberPlayerStore(   musicId: MusicId,   context: Ctx,   coroutineScope: CoroutineScope = rememberCoroutineScope() ): Store&lt;PlayerState, PlayerEvent&gt;         where Ctx : MusicPlayerCapability,               Ctx : MusicDataCapability {    return remember(musicId) {     ElmStore(       initialState = PlayerState(),       reducer = PlayerReducer(),       actor = PlayerActor(context),       coroutineScope = coroutineScope     )   } }<\/code><\/pre>\n<pre><code class=\"kotlin\">@Composable fun PlayerScreen(   modifier: Modifier = Modifier,   musicId: MusicId,   onBack: () -&gt; Unit, ) {   val coroutineScope = rememberCoroutineScope()   val context = LocalContext.current    val store = rememberPlayerStore(     musicId = musicId,     context = makePlayerCapability(context, coroutineScope)   )   val state by store.state.collectAsState()   BackHandler {     store.send(PlayerEvent.PlaybackStopped)     onBack()   }    LaunchedEffect(Unit) {     store.send(PlayerEvent.StartLoad(musicId))   }    LaunchedEffect(store) {     store.effects.collect { effect -&gt;       when (effect) {         is PlayerEffect.ShowError -&gt; { showToast(context, effect.message) }       }     }   }    PlayerContent(     modifier = modifier,     state = state,     onSeekBackward = { store.send(PlayerEvent.PaybackSought(-15_000)) },     onSeekForward = { store.send(PlayerEvent.PaybackSought(15_000)) },     onPlayPause = { store.send(PlayerEvent.PlaybackStateChanged) },     onRewind = { store.send(PlayerEvent.PaybackRewound((it * 1000).toLong())) },     onToggleFavorite = { store.send(PlayerEvent.FavoriteClicked(musicId)) },   ) }<\/code><\/pre>\n<p>\u042d\u043a\u0440\u0430\u043d <code>PlayerScreen<\/code> \u2014 \u043f\u0440\u043e\u0441\u043b\u043e\u0439\u043a\u0430 \u043c\u0435\u0436\u0434\u0443 <em>UI<\/em> \u0438 \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u043e\u0439. \u041e\u043d \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u0442 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f <code>ElmStore<\/code> \u0447\u0435\u0440\u0435\u0437 <code>rememberPlayerStore<\/code>. \u0410 \u044d\u0442\u043e \u0437\u043d\u0430\u0447\u0438\u0442, \u0447\u0442\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 <em>Composable-\u0444\u0443\u043d\u043a\u0446\u0438\u0438<\/em>, \u043d\u043e \u0441\u0431\u0440\u043e\u0441\u0438\u0442\u0441\u044f \u043f\u0440\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 <code>musicId<\/code>. \u041e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u044f \u0442\u0440\u0438 \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430, \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u043e\u0431\u0440\u0430\u0437\u0443\u0435\u0442 \u0437\u0430\u043c\u043a\u043d\u0443\u0442\u044b\u0439 \u0446\u0438\u043a\u043b \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u0439.<\/p>\n<p><code>LaunchedEffect<\/code><em> <\/em>\u0432 <code>PlayerScreen<\/code> \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u0434\u0432\u0435 \u0432\u0430\u0436\u043d\u044b\u0435 \u0437\u0430\u0434\u0430\u0447\u0438. \u0412\u043e-\u043f\u0435\u0440\u0432\u044b\u0445, \u0438\u043d\u0438\u0446\u0438\u0438\u0440\u0443\u0435\u0442 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0443 \u0434\u0430\u043d\u043d\u044b\u0445 \u0447\u0435\u0440\u0435\u0437 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 <code>StartLoad<\/code> \u043f\u0440\u0438 \u043f\u0435\u0440\u0432\u043e\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u044d\u043a\u0440\u0430\u043d\u0430. \u0422\u0430\u043a \u043e\u043d \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u0442 \u043f\u0440\u0438\u043d\u0446\u0438\u043f \u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0439 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f.<\/p>\n<p>\u0412\u043e-\u0432\u0442\u043e\u0440\u044b\u0445, \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 <code>LaunchedEffect<\/code> \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u044d\u0444\u0444\u0435\u043a\u0442\u043e\u0432 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442 \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u0443\u044e \u043c\u043e\u0434\u0435\u043b\u044c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043f\u043e\u0431\u043e\u0447\u043d\u044b\u0445 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043e\u0448\u0438\u0431\u043e\u043a \u0434\u043b\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439. \u0422\u0430\u043a \u0438 \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u0432 \u0444\u0438\u043b\u043e\u0441\u043e\u0444\u0438\u0438 <em>Elm<\/em>, \u0433\u0434\u0435 \u043f\u043e\u0431\u043e\u0447\u043d\u044b\u0435 \u044d\u0444\u0444\u0435\u043a\u0442\u044b \u044f\u0432\u043d\u043e \u043e\u0442\u0434\u0435\u043b\u0435\u043d\u044b \u043e\u0442 \u0447\u0438\u0441\u0442\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u0438 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f<em>.<\/em><\/p>\n<p>\u0421\u043b\u043e\u0439 <code>PlayerContent<\/code> \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0442\u0435\u043a\u0443\u0449\u0435\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0438 \u043a\u043e\u043b\u0431\u044d\u043a\u0438 \u0434\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u0439, \u0434\u0435\u043b\u0430\u044f \u044d\u0442\u043e\u0442 \u044d\u043a\u0440\u0430\u043d \u00ab\u0433\u043b\u0443\u043f\u044b\u043c\u00bb \u043f\u0440\u0435\u0437\u0435\u043d\u0442\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u043c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u043c. \u0422\u0430\u043a \u0440\u0430\u0437\u0434\u0435\u043b\u044f\u044e\u0442\u0441\u044f \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0430 \u0438 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435. \u041a\u043e\u043d\u0442\u0435\u043d\u0442 \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0437\u043d\u0430\u0435\u0442 \u043e\u0431 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u0439, \u0430 \u043b\u0438\u0448\u044c \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u044f\u0435\u0442 \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u043e \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. \u041f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0438 \u0431\u0438\u0437\u043d\u0435\u0441-\u043f\u0440\u0430\u0432\u0438\u043b\u0430 \u0438\u043d\u043a\u0430\u043f\u0441\u0443\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u044b \u0432 \u0440\u0435\u0434\u044c\u044e\u0441\u0435\u0440\u0435 \u0438 \u0430\u043a\u0442\u043e\u0440\u0435.<\/p>\n<p>\u0421\u0442\u0440\u043e\u0433\u0430\u044f \u043e\u0434\u043d\u043e\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u0442\u043e\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u2014 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u044b \u0441 <code>ElmStore<\/code>. \u0421\u043e\u0431\u044b\u0442\u0438\u044f \u043e\u0442 <em>UI<\/em> \u043f\u0440\u043e\u0445\u043e\u0434\u044f\u0442 \u0447\u0435\u0440\u0435\u0437 \u0440\u0435\u0434\u044c\u044e\u0441\u0435\u0440, \u043f\u043e\u0440\u043e\u0436\u0434\u0430\u044e\u0442 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0434\u043b\u044f \u0430\u043a\u0442\u043e\u0440\u0430, \u043f\u0440\u0438\u0432\u043e\u0434\u044f \u043a \u043d\u043e\u0432\u044b\u043c \u0441\u043e\u0431\u044b\u0442\u0438\u044f\u043c \u0438 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f. \u042d\u0442\u043e \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0443\u0435\u043c\u044b\u0439 \u0446\u0438\u043a\u043b \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0439, \u0433\u0434\u0435 \u043a\u0430\u0436\u0434\u043e\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u2014 \u044d\u0442\u043e \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u044f\u0432\u043d\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043d\u043e\u0433\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u044f.<\/p>\n<p>\u042f \u0437\u0430\u043f\u0438\u0441\u0430\u043b <em>GIF-\u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044e<\/em> \u0441 \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u0435\u0439 \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u043b\u0435\u0435\u0440\u0430. \u0427\u0442\u043e\u0431\u044b \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f, \u0447\u0442\u043e \u0432\u0441\u0451 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0441\u043e \u0437\u0432\u0443\u043a\u043e\u043c, \u043a\u043b\u043e\u043d\u0438\u0440\u0443\u0439\u0442\u0435 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0438 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e.<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/361\/c1a\/ea3\/361c1aea38d9747d9475ba0f88d7a114.gif\" alt=\"\u0410\u043d\u0438\u043c\u0430\u0446\u0438\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u0440\u043e\u0438\u0433\u0440\u044b\u0432\u0430\u0442\u0435\u043b\u044f\" title=\"\u0410\u043d\u0438\u043c\u0430\u0446\u0438\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u0440\u043e\u0438\u0433\u0440\u044b\u0432\u0430\u0442\u0435\u043b\u044f\" width=\"216\" height=\"480\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/361\/c1a\/ea3\/361c1aea38d9747d9475ba0f88d7a114.gif 780w,&#10;       https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/361\/c1a\/ea3\/361c1aea38d9747d9475ba0f88d7a114.gif 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u0410\u043d\u0438\u043c\u0430\u0446\u0438\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u0440\u043e\u0438\u0433\u0440\u044b\u0432\u0430\u0442\u0435\u043b\u044f<\/figcaption><\/div>\n<\/figure>\n<p>\u041d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u0442\u0430\u043a\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0434\u0438\u0441\u0446\u0438\u043f\u043b\u0438\u043d\u044b \u2014 <em>UI<\/em> \u0434\u043e\u043b\u0436\u0435\u043d \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0441\u043e\u0431\u044b\u0442\u0438\u044f, \u043d\u0435 \u043c\u0435\u043d\u044f\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e. \u0411\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0430 \u043a\u043e\u043d\u0446\u0435\u043d\u0442\u0440\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0432 \u0440\u0435\u0434\u044c\u044e\u0441\u0435\u0440\u0435, \u0430 \u0441\u0430\u0439\u0434-\u044d\u0444\u0444\u0435\u043a\u0442\u044b \u0432\u044b\u043d\u043e\u0441\u044f\u0442\u0441\u044f \u0432 \u0430\u043a\u0442\u043e\u0440. \u0422\u0430\u043a\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u0430 \u0432 \u0441\u043b\u043e\u0436\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445 \u0441\u043e \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e\u043c \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0445 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439, \u0433\u0434\u0435 \u043a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u043f\u043e\u0434\u0445\u043e\u0434\u044b \u0447\u0430\u0441\u0442\u043e \u043f\u0440\u0438\u0432\u043e\u0434\u044f\u0442 \u043a \u00ab\u0440\u0430\u0441\u043f\u044b\u043b\u0435\u043d\u0438\u044e\u00bb \u043b\u043e\u0433\u0438\u043a\u0438.<\/p>\n<p>\u0410\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u043d\u0435 \u043b\u0438\u0448\u0435\u043d\u0430 \u043a\u043e\u043c\u043f\u0440\u043e\u043c\u0438\u0441\u0441\u043e\u0432, \u0434\u0430 \u0438 \u0443\u043b\u0443\u0447\u0448\u0430\u0442\u044c \u0435\u0441\u0442\u044c \u0447\u0442\u043e. \u041d\u0430\u0447\u0430\u043b\u044c\u043d\u0430\u044f \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u044f \u0438 \u0438\u0437\u0431\u044b\u0442\u043e\u0447\u043d\u043e\u0441\u0442\u044c \u043a\u043e\u0434\u0430 \u0434\u043b\u044f \u043f\u0440\u043e\u0441\u0442\u044b\u0445 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0435\u0432 \u043c\u043e\u0433\u0443\u0442 \u043e\u0442\u043f\u0443\u0433\u043d\u0443\u0442\u044c \u043d\u043e\u0432\u0438\u0447\u043a\u043e\u0432 \u2014 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0431\u043e\u0439\u043b\u0435\u0440\u043f\u043b\u0435\u0439\u0442\u0430 \u0437\u0434\u0435\u0441\u044c \u0445\u0432\u0430\u0442\u0430\u0435\u0442. \u0412\u043f\u0440\u043e\u0447\u0435\u043c, \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <em>LiveTemplates<\/em> \u0432 <em>IDE<\/em> \u043c\u043e\u0436\u043d\u043e \u0443\u043f\u0440\u043e\u0441\u0442\u0438\u0442\u044c \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0448\u0430\u0431\u043b\u043e\u043d\u043d\u044b\u0445 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439, \u0441\u043e\u043a\u0440\u0430\u0442\u0438\u0432 \u0440\u0443\u0442\u0438\u043d\u043d\u0443\u044e \u0440\u0430\u0431\u043e\u0442\u0443 \u0434\u043e \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u043a\u043b\u0438\u043a\u043e\u0432.<\/p>\n<p>\u041d\u0443 \u0438 \u043f\u0440\u043e \u043d\u0430\u0434\u0451\u0436\u043d\u043e\u0441\u0442\u044c. \u0412 \u0442\u0435\u043e\u0440\u0438\u0438 \u0442\u0430\u043a\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u0432\u044b\u0441\u043e\u043a\u0438\u0439 \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044f \u043d\u0430\u0434 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445 \u0441\u043e \u0441\u0442\u0440\u043e\u0433\u0438\u043c\u0438 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f\u043c\u0438. \u041d\u043e \u0432 \u043a\u0440\u0443\u043f\u043d\u044b\u0445 \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u043d-\u0441\u0440\u0435\u0434\u0430\u0445 \u044f \u044d\u0442\u043e\u0442 \u043f\u043e\u0434\u0445\u043e\u0434 \u043d\u0435 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043b, \u0442\u0430\u043a \u0447\u0442\u043e \u043d\u0438\u0447\u0435\u0433\u043e \u0443\u0442\u0432\u0435\u0440\u0436\u0434\u0430\u0442\u044c \u043d\u0435 \u043c\u043e\u0433\u0443. \u0423\u043f\u043e\u0440\u044f\u0434\u043e\u0447\u0438\u0442\u044c \u0445\u0430\u043e\u0442\u0438\u0447\u043d\u044b\u0435 \u043f\u043e\u0442\u043e\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u043e\u043d\u0430 \u043c\u043e\u0436\u0435\u0442, \u043d\u043e \u0442\u0443\u0442 \u0432\u0441\u0451 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0438 \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0430 \u0432\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430.<\/p>\n<h2>\u0427\u0442\u043e \u0434\u0430\u043b\u044c\u0448\u0435<\/h2>\n<p>\u041d\u0430 \u044d\u0442\u043e\u043c \u0446\u0438\u043a\u043b \u0441\u0442\u0430\u0442\u0435\u0439 \u043e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0435 \u0432 <em>Android<\/em> \u043f\u043e\u0434\u043e\u0448\u0451\u043b \u043a \u043a\u043e\u043d\u0446\u0443. \u041f\u043e\u0441\u043b\u0435\u0434\u043d\u044f\u044f \u0447\u0430\u0441\u0442\u044c \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0430\u0441\u044c \u0431\u043e\u043b\u044c\u0448\u043e\u0439, \u0442\u0430\u043a \u0447\u0442\u043e \u0442\u0435\u043c\u0430 <em>Unit<\/em> \u0438 <em>UI-\u0442\u0435\u0441\u0442\u043e\u0432<\/em> \u0441\u044e\u0434\u0430 \u043d\u0435 \u0432\u043b\u0435\u0437\u043b\u0430. \u0415\u0441\u043b\u0438 \u043e\u043d\u0430 \u0432\u0430\u043c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u0430, \u043d\u0430\u043f\u0438\u0448\u0438\u0442\u0435 \u0432 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0445 \u2014 \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u043e \u043d\u0435\u0439 \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435. <br \/>\u0414\u0430 \u0438 <em>benchmark-\u0437\u0430\u043c\u0435\u0440\u044b<\/em> \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 <em>ELM-\u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b<\/em> \u043d\u0435 \u043f\u043e\u043c\u0435\u0448\u0430\u043b\u0438 \u0431\u044b. \u041d\u0430\u0434\u0435\u044e\u0441\u044c, \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u043e\u043a\u0430\u0437\u0430\u043b\u0441\u044f \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u043c \u0438\u043b\u0438, \u043a\u0430\u043a \u043c\u0438\u043d\u0438\u043c\u0443\u043c, \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u043b \u0440\u0430\u0441\u0448\u0438\u0440\u0438\u0442\u044c \u043a\u0440\u0443\u0433\u043e\u0437\u043e\u0440.\u00a0<\/p>\n<p>\u041a\u043e\u0434 \u0438\u0437 \u0447\u0438\u0441\u0442\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u0431\u043e\u043b\u0435\u0435 \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0443\u0435\u043c\u044b\u0439, \u0432\u0435\u0434\u044c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u0432\u0445\u043e\u0434\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445, \u0430 \u043d\u0435 \u043e\u0442 \u0441\u043a\u0440\u044b\u0442\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f. \u0418\u0437\u0431\u0435\u0433\u0430\u044f \u043c\u0443\u0442\u0430\u0446\u0438\u0439 \u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u044f \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u043a\u0430\u043a \u0441 \u043d\u0435\u0438\u0437\u043c\u0435\u043d\u043d\u044b\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c, \u0432\u044b \u0441\u043c\u043e\u0436\u0435\u0442\u0435 \u043b\u0443\u0447\u0448\u0435 \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0442\u044c \u043b\u043e\u0433\u0438\u043a\u0443 \u0438 \u043f\u0440\u0435\u0434\u043e\u0442\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u044b\u0435 \u043e\u0448\u0438\u0431\u043a\u0438. \u041f\u0440\u0438 \u044d\u0442\u043e\u043c \u043d\u0435 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u043e\u0434\u043d\u043e\u0439 \u043f\u0430\u0440\u0430\u0434\u0438\u0433\u043c\u043e\u0439: \u043c\u043e\u0436\u043d\u043e \u0441\u043e\u0447\u0435\u0442\u0430\u0442\u044c \u0434\u0435\u043a\u043b\u0430\u0440\u0430\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0430 \u0441 \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u043e\u043c \u041e\u041e\u041f, \u0433\u0434\u0435 \u044d\u0442\u043e \u0443\u043c\u0435\u0441\u0442\u043d\u043e. \u0413\u043b\u0430\u0432\u043d\u043e\u0435 \u2014 \u0447\u0442\u043e\u0431\u044b \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u043e\u0441\u0442\u0430\u0432\u0430\u043b\u0430\u0441\u044c \u0433\u0438\u0431\u043a\u043e\u0439, \u0430 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0441\u043b\u0430\u0431\u043e \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u043c\u0438. \u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u0438\u043d\u043e\u0433\u0434\u0430 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0442\u044c \u044d\u0442\u0438 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u044b. \u0421\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0435\u043c \u0437\u0430\u043c\u0435\u0442\u0438\u0442\u0435, \u043d\u0430\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u043e\u0449\u0435 \u0441\u0442\u0430\u043b\u043e \u0432\u043d\u043e\u0441\u0438\u0442\u044c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0438 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c \u043a\u043e\u0434.<\/p>\n<p>\u0421\u043f\u0430\u0441\u0438\u0431\u043e, \u0447\u0442\u043e \u0434\u043e\u0447\u0438\u0442\u0430\u043b\u0438 \u0441\u0442\u0430\u0442\u044c\u044e! \u0421\u0442\u0430\u0432\u044c\u0442\u0435 \u043f\u043b\u044e\u0441\u0438\u043a\u0438, \u0435\u0441\u043b\u0438 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u043f\u043e\u043a\u0430\u0437\u0430\u043b\u0441\u044f \u0432\u0430\u043c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u043c, \u0438 \u0434\u0435\u043b\u0438\u0442\u0435\u0441\u044c \u0438\u043c \u0441 \u0434\u0440\u0443\u0437\u044c\u044f\u043c\u0438. \u0410 \u0447\u0442\u043e\u0431\u044b \u0431\u044b\u0442\u044c \u0432 \u043a\u0443\u0440\u0441\u0435 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0445 \u043d\u043e\u0432\u043e\u0441\u0442\u0435\u0439 Dodo Engineering, \u043f\u043e\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u0439\u0442\u0435\u0441\u044c \u043d\u0430 <a href=\"https:\/\/t.me\/+en2c05Bh6ihlM2Yy\" rel=\"noopener noreferrer nofollow\">\u043d\u0430\u0448 Telegram-\u043a\u0430\u043d\u0430\u043b<\/a>.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/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\/articles\/927100\/\"> https:\/\/habr.com\/ru\/articles\/927100\/<\/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 article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width\"><\/figure>\n<h3>\u041e \u0447\u0451\u043c \u0441\u0442\u0430\u0442\u044c\u044f<\/h3>\n<p>\u0412 \u0447\u0435\u0442\u0432\u0451\u0440\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u0446\u0438\u043a\u043b\u0430 \u043f\u0440\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0432 Android \u043c\u044b \u0441\u043e\u0431\u0435\u0440\u0451\u043c \u0437\u043d\u0430\u043d\u0438\u044f, \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0435 \u0432 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0445 \u0447\u0430\u0441\u0442\u044f\u0445 \u0446\u0438\u043a\u043b\u0430. \u0410 \u0435\u0449\u0451 \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u043c \u0438\u0445 \u043d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u2014 \u0441\u043e\u0431\u0435\u0440\u0451\u043c \u0441\u043a\u0435\u043b\u0435\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u043c\u0435\u0434\u0438\u0442\u0430\u0446\u0438\u0438.<\/p>\n<p>\u0415\u0441\u043b\u0438 \u0432\u044b \u043d\u0435 \u043f\u043e\u043c\u043d\u0438\u0442\u0435 \u0438\u043b\u0438 \u043d\u0435 \u0437\u043d\u0430\u0435\u0442\u0435, \u0447\u0442\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u043b\u043e \u0432 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0445 \u0441\u0442\u0430\u0442\u044c\u044f\u0445 \u0446\u0438\u043a\u043b\u0430, \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u0442\u0435 \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0430\u043c \u043d\u0438\u0436\u0435, \u0430 \u043f\u043e\u0442\u043e\u043c \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0439\u0442\u0435\u0441\u044c \u043a \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435:<\/p>\n<ol>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/companies\/dododev\/articles\/917222\/\" rel=\"noopener noreferrer nofollow\">\u0424\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0432 Android. \u0417\u043d\u0430\u043a\u043e\u043c\u0441\u0442\u0432\u043e \u0441 \u043f\u0430\u0440\u0430\u0434\u0438\u0433\u043c\u043e\u0439.<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/companies\/dododev\/articles\/917960\/\" rel=\"noopener noreferrer nofollow\">\u0424\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0432 Android. \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 State Machine.<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/companies\/dododev\/articles\/922710\/\" rel=\"noopener noreferrer nofollow\">\u0424\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0432 Android. \u0422\u0435\u043e\u0440\u0438\u044f \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0439 \u0438 DI.<\/a><\/p>\n<\/li>\n<\/ol>\n<p>\u041f\u0435\u0440\u0435\u0434 \u0442\u0435\u043c, \u043a\u0430\u043a \u043f\u0435\u0440\u0435\u0439\u0442\u0438 \u043a \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044e \u043a\u043e\u0434\u0430, \u044f \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u0430\u0441 \u043f\u0440\u0435\u0434\u0443\u043f\u0440\u0435\u0434\u0438\u0442\u044c, \u0447\u0442\u043e \u043e\u043d \u0432\u043e \u043c\u043d\u043e\u0433\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u043c. \u0414\u043b\u044f \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b \u0432 \u043d\u0451\u043c \u0438 mock-\u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438, \u0438 hardcode \u2014 \u0432 \u043e\u0431\u0449\u0435\u043c, \u044d\u0442\u043e \u043d\u0435 \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u043e \u043f\u043e \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044e \u044d\u0442\u0430\u043b\u043e\u043d\u043d\u043e\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b.<\/p>\n<p>\u041a\u0430\u043a \u044f \u0443\u043f\u043e\u043c\u0438\u043d\u0430\u043b \u0440\u0430\u043d\u0435\u0435, \u0437\u0430\u0447\u0430\u0442\u043a\u0438 \u043f\u043e\u0445\u043e\u0436\u0435\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b \u0443 \u043c\u0435\u043d\u044f \u043d\u0435 \u0434\u043e\u0435\u0445\u0430\u043b\u0438 \u0434\u043e \u043f\u0440\u043e\u0434\u0430. \u0422\u0435\u043a\u0443\u0449\u0438\u0439 \u043f\u0435\u0442-\u043f\u0440\u043e\u0435\u043a\u0442 \u0434\u043e\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0435\u0451 \u0438 \u043f\u0438\u0448\u0435\u0442\u0441\u044f \u0438\u0441\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0441 \u0446\u0435\u043b\u044c\u044e \u043f\u043e\u0449\u0443\u043f\u0430\u0442\u044c \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0432 Android-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435.<\/p>\n<p>\u042d\u0442\u043e \u044f \u0432\u0441\u0451 \u043a \u0447\u0435\u043c\u0443? \u0411\u0443\u0434\u0435\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043c\u043e\u0438 \u043f\u0440\u0438\u0451\u043c\u044b \u0432 \u0441\u0432\u043e\u0438\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445 \u2014 \u0434\u0435\u043b\u0430\u0439\u0442\u0435 \u044d\u0442\u043e \u043e\u0441\u0442\u043e\u0440\u043e\u0436\u043d\u043e. \u041c\u0435\u0441\u0442\u0430 \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u044f \u0431\u0443\u0434\u0443 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u043e\u0434\u0441\u0432\u0435\u0447\u0438\u0432\u0430\u0442\u044c \u0438 \u043f\u043e\u044f\u0441\u043d\u044f\u0442\u044c.<\/p>\n<h2>\u041a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b<\/h2>\n<p>\u0412 \u043f\u0435\u0440\u0432\u044b\u0439 \u0440\u0430\u0437 \u044f \u043f\u0440\u043e\u0431\u043e\u0432\u0430\u043b \u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0424\u041f-\u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0443 \u043d\u0430 <em>ViewModel<\/em>. \u0421\u0435\u0439\u0447\u0430\u0441 \u044f \u0431\u0443\u0434\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <em>The Elm Architecture (TEA)<\/em> \u2014 \u043f\u0430\u0442\u0442\u0435\u0440\u043d \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c, \u0437\u0430\u0438\u043c\u0441\u0442\u0432\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0438\u0437 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u044f\u0437\u044b\u043a\u0430 <em>Elm<\/em>.<\/p>\n<p>\u041e\u043d \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u0441\u0442\u0440\u043e\u0433\u0438\u0439 \u043e\u0434\u043d\u043e\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0439 \u043f\u043e\u0442\u043e\u043a \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0443\u0435\u043c\u043e\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f. \u041e\u0434\u043d\u0430\u043a\u043e \u0433\u043b\u0443\u0431\u043e\u043a\u043e \u043c\u044b \u0432 \u043d\u0435\u0433\u043e \u0443\u0445\u043e\u0434\u0438\u0442\u044c \u043d\u0435 \u0431\u0443\u0434\u0435\u043c. \u0412\u0441\u0435 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u044e\u0449\u0438\u0435\u0441\u044f \u043c\u043e\u0433\u0443\u0442 \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u043d\u0438\u043c <a href=\"https:\/\/habr.com\/ru\/companies\/vivid_money\/articles\/550932\/\" rel=\"noopener noreferrer nofollow\">\u0442\u0443\u0442<\/a>, \u0430 \u043c\u044b \u0432\u0435\u0440\u0445\u043d\u0435\u0443\u0440\u043e\u0432\u043d\u0435\u0432\u043e \u0440\u0430\u0437\u0431\u0435\u0440\u0451\u043c \u0441\u0443\u0442\u044c \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432. \u0421\u0445\u0435\u043c\u0430 \u043f\u043e\u0442\u043e\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0442\u0430\u043a:<\/p>\n<figure class=\"full-width\">\n<div><figcaption>\u0426\u0438\u043a\u043b \u043f\u043e\u0442\u043e\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 <em>ELM-\u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b<\/em><\/figcaption><\/div>\n<\/figure>\n<p><code>State<\/code><em> <\/em>\u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u043c\u043c\u0443\u0442\u0430\u0431\u0435\u043b\u044c\u043d\u044b\u0439 \u0441\u043d\u0438\u043c\u043e\u043a \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438\u043b\u0438 \u044d\u043a\u0440\u0430\u043d\u0430<em>.<\/em> \u041e\u043d \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0438 <em>UI<\/em> \u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043a\u0430\u043a \u043b\u0435\u0433\u043a\u043e \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0443\u0435\u043c\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442. \u0415\u0433\u043e \u0438\u043c\u043c\u0443\u0442\u0430\u0431\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u0443\u0435\u0442 \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0443\u0435\u043c\u043e\u0441\u0442\u044c. \u041b\u044e\u0431\u043e\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043d\u043e\u0432\u043e\u0439 \u043a\u043e\u043f\u0438\u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f, \u0438\u0441\u043a\u043b\u044e\u0447\u0430\u044f \u0441\u043a\u0440\u044b\u0442\u044b\u0435 \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0438 \u043f\u043e\u0431\u043e\u0447\u043d\u044b\u0435 \u044d\u0444\u0444\u0435\u043a\u0442\u044b.<\/p>\n<p><code>Event<\/code><em> \u2014 <\/em>\u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u043b\u0435\u0433\u0430\u043b\u044c\u043d\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f. \u042d\u0442\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0435 \u0438\u043b\u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u2014 <code>ButtonClicked<\/code>, <code>DataLoaded<\/code> \u0438 \u0442.\u0434. \u041e\u043d\u0438 \u043d\u0435 \u0438\u0437\u043c\u0435\u043d\u044f\u044e\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u0430 \u0442\u0440\u0438\u0433\u0433\u0435\u0440\u044f\u0442 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b, \u043e\u0442\u0432\u0435\u0447\u0430\u044e\u0449\u0438\u0435 \u0437\u0430 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u044b \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439. \u0412\u0430\u0436\u043d\u043e, \u0447\u0442\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u043d\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442 \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0438, \u0430 \u043b\u0438\u0448\u044c \u0441\u0438\u0433\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u044e\u0442 \u043e \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u0435\u0434\u0448\u0435\u043c \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0438.<\/p>\n<p><code>Command<\/code><em> <\/em>\u0438\u043d\u043a\u0430\u043f\u0441\u0443\u043b\u0438\u0440\u0443\u0435\u0442 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 (<code>FetchUserData<\/code>) \u0438\u043b\u0438 \u0441\u0430\u0439\u0434-\u044d\u0444\u0444\u0435\u043a\u0442\u044b (<code>StartTimer<\/code>). \u041a\u043e\u043c\u0430\u043d\u0434\u044b \u043d\u0435 \u0438\u0437\u043c\u0435\u043d\u044f\u044e\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435, \u0430 \u043b\u0438\u0448\u044c \u0434\u0435\u043b\u0435\u0433\u0438\u0440\u0443\u044e\u0442 \u0440\u0430\u0431\u043e\u0442\u0443 \u0432\u043d\u0435\u0448\u043d\u0438\u043c \u0438\u0441\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044f\u043c. \u041e\u043d\u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0442 \u043d\u043e\u0432\u044b\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u043f\u0440\u0438\u0432\u0435\u0441\u0442\u0438 \u043a \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0443 \u0432 \u043d\u043e\u0432\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435, \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u044f \u0447\u0438\u0441\u0442\u043e\u0442\u0443 \u043f\u043e\u0442\u043e\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<p><code>Effect<\/code><em> <\/em>\u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0435 <em>UI-\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435<\/em> \u043f\u043e\u0441\u043b\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f: <code>ShowToast<\/code>, <code>NavigateToScreen<\/code>. \u0412 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 \u043a\u043e\u043c\u0430\u043d\u0434, \u044d\u0444\u0444\u0435\u043a\u0442\u044b \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442\u0441\u044f \u043f\u043e\u0441\u043b\u0435 \u0444\u0438\u043a\u0441\u0430\u0446\u0438\u0438 \u043d\u043e\u0432\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0438 \u043d\u0435 \u0441\u043e\u0437\u0434\u0430\u044e\u0442 \u0441\u043e\u0431\u044b\u0442\u0438\u044f. \u041e\u043d\u0438 \u043c\u043e\u0434\u0435\u043b\u0438\u0440\u0443\u044e\u0442 \u00ab\u0440\u0435\u0430\u043a\u0446\u0438\u044e\u00bb \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u043d\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f.<\/p>\n<h3>\u041c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u044b \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0438<\/h3>\n<p><code>Reducer<\/code><em> \u2014 <\/em>\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440 \u0441\u043e\u0431\u044b\u0442\u0438\u0439. \u042d\u0442\u043e \u0447\u0438\u0441\u0442\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f. \u041e\u043d\u0430 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0442\u0435\u043a\u0443\u0449\u0435\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u0435, \u0430 \u0435\u0449\u0451 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 <code>StateResult<\/code>. \u0412\u0430\u0436\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u0440\u0435\u0434\u044c\u044e\u0441\u0435\u0440 \u043e\u0431\u043b\u0430\u0434\u0430\u043b \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e\u043c \u0434\u0435\u0442\u0435\u0440\u043c\u0438\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0441\u0442\u0438: \u0434\u043b\u044f \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u0445 \u0432\u0445\u043e\u0434\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u043e\u043d \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u0438\u0434\u0435\u043d\u0442\u0438\u0447\u043d\u044b\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0431\u0435\u0437 \u043f\u043e\u0431\u043e\u0447\u043d\u044b\u0445 \u044d\u0444\u0444\u0435\u043a\u0442\u043e\u0432.<\/p>\n<p><code>StateResult<\/code><em> \u2014 <\/em>\u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440-\u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442\u0451\u0440. \u041e\u043d \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u0443\u0435\u0442 \u0430\u0442\u043e\u043c\u0430\u0440\u043d\u043e\u0441\u0442\u044c \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f: \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0438\u0437\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e, \u0430 \u043f\u043e\u0442\u043e\u043c \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u044e\u0442\u0441\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0438 \u044d\u0444\u0444\u0435\u043a\u0442\u044b. \u0422\u0430\u043a\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u043f\u0440\u0435\u0434\u043e\u0442\u0432\u0440\u0430\u0449\u0430\u0435\u0442 <em>RaceConditions<\/em> \u0438 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u043b\u043e\u0433\u0438\u043a\u0438.<\/p>\n<p><code>Actor<\/code><em> <\/em>\u0438\u0441\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438. \u0415\u0433\u043e \u043c\u0435\u0442\u043e\u0434 <code>execute<\/code> \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u0435\u0442 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0432 \u0441\u043e\u0431\u044b\u0442\u0438\u044f, \u0430 <code>subscribe<\/code> \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0432\u043d\u0435\u0448\u043d\u0438\u0435 \u043f\u043e\u0442\u043e\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445: <code>WebSocket<\/code>, \u0442\u0430\u0439\u043c\u0435\u0440\u044b. \u0410\u043a\u0442\u043e\u0440 \u0438\u0437\u043e\u043b\u0438\u0440\u0443\u0435\u0442 \u00ab\u0433\u0440\u044f\u0437\u043d\u0443\u044e\u00bb \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 \u0432\u043d\u0435\u0448\u043d\u0438\u043c \u043c\u0438\u0440\u043e\u043c, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044f \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0447\u0435\u0440\u0435\u0437 \u0441\u043e\u0431\u044b\u0442\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u043d\u043e\u0432\u044c \u043f\u043e\u043f\u0430\u0434\u0430\u044e\u0442 \u0432 \u0440\u0435\u0434\u044c\u044e\u0441\u0435\u0440.<\/p>\n<h3>\u0426\u0435\u043d\u0442\u0440 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f<\/h3>\n<p><code>Store<\/code><em> <\/em>\u2014 \u044d\u0442\u043e \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435, \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0438\u0440\u0443\u044e\u0449\u0435\u0435 \u0432\u0441\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b. \u041e\u043d\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043f\u043e\u0442\u043e\u043a\u0438 \u0434\u043b\u044f \u043d\u0430\u0431\u043b\u044e\u0434\u0435\u043d\u0438\u044f \u0437\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f\u043c\u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f, \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u044d\u0444\u0444\u0435\u043a\u0442\u043e\u0432 \u0438 \u043c\u0435\u0442\u043e\u0434 <code>send<\/code> \u0434\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u0439.<\/p>\n<pre><code class=\"kotlin\">interface Event interface Command interface Effect data class StateResult&lt;S : State&gt;(   val state: S,   val commands: List&lt;Command&gt; = emptyList(),   val effects: List&lt;Effect&gt; = emptyList() )  interface Reducer&lt;S : State, E : Event&gt; {   fun reduce(state: S, event: E?): StateResult&lt;S&gt; }  interface State  interface Actor {   suspend fun execute(command: Command): Event?   suspend fun subscribe(): Flow&lt;Event&gt; }  interface Store&lt;S : State, E : Event&gt; {   val state: StateFlow&lt;S&gt;   val effects: SharedFlow&lt;Effect&gt;   fun send(event: E) }<\/code><\/pre>\n<p>\u0426\u0438\u043a\u043b \u0440\u0430\u0431\u043e\u0442\u044b \u0437\u0430\u043c\u044b\u043a\u0430\u0435\u0442\u0441\u044f: \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u043f\u0440\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0438 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u044e\u0442 \u043d\u043e\u0432\u044b\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u043d\u043e\u0432\u044c \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0432 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435. \u042d\u0444\u0444\u0435\u043a\u0442\u044b \u043f\u043e\u0442\u0440\u0435\u0431\u043b\u044f\u044e\u0442\u0441\u044f <em>UI-\u0441\u043b\u043e\u0435\u043c<\/em> \u0431\u0435\u0437 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0432\u043b\u0438\u044f\u0442\u044c \u043d\u0430 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435.<\/p>\n<h3>\u041f\u043e\u0431\u043e\u0447\u043d\u044b\u0435 \u044d\u0444\u0444\u0435\u043a\u0442\u044b<\/h3>\n<p>\u0415\u0449\u0451 \u043e\u0434\u043d\u043e \u0432\u0430\u0436\u043d\u043e\u0435 \u043f\u043e\u043d\u044f\u0442\u0438\u0435 \u0434\u043b\u044f \u0441\u0442\u0430\u0442\u044c\u0438 \u2014 \u043f\u043e\u0431\u043e\u0447\u043d\u044b\u0435 \u044d\u0444\u0444\u0435\u043a\u0442\u044b (<em>Side Effect<\/em>). \u041d\u0430\u043c \u0432\u0430\u0436\u043d\u043e \u043f\u043e\u043d\u044f\u0442\u044c, \u043a\u0430\u043a \u043e\u043d\u0438 \u0432\u043b\u0438\u044f\u044e\u0442 \u043d\u0430 \u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0412 \u0446\u0435\u043b\u043e\u043c \u043f\u043e\u0431\u043e\u0447\u043d\u044b\u0439 \u044d\u0444\u0444\u0435\u043a\u0442 \u2014 \u044d\u0442\u043e \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u0438\u043b\u0438 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0441 \u0432\u043d\u0435\u0448\u043d\u0438\u043c \u043c\u0438\u0440\u043e\u043c, \u0432\u044b\u0445\u043e\u0434\u044f\u0449\u0435\u0435 \u0437\u0430 \u0440\u0430\u043c\u043a\u0438 \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u044f \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u0438. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440:<\/p>\n<ul>\n<li>\n<p>\u0437\u0430\u043f\u0438\u0441\u044c \u0432 \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445;<\/p>\n<\/li>\n<li>\n<p>\u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0430 \u0441\u0435\u0442\u0435\u0432\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430;<\/p>\n<\/li>\n<li>\n<p>\u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u043e\u0439 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439;<\/p>\n<\/li>\n<li>\n<p>\u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 UI.<\/p>\n<\/li>\n<\/ul>\n<p>\u0412 \u0438\u043c\u043f\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u043e\u043c \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u0442\u0430\u043a\u0438\u0435 \u044d\u0444\u0444\u0435\u043a\u0442\u044b \u0432\u0441\u0442\u0440\u0435\u0447\u0430\u044e\u0442\u0441\u044f \u0432\u0435\u0437\u0434\u0435, \u043d\u043e \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u043c \u2014 \u0441\u0447\u0438\u0442\u0430\u044e\u0442\u0441\u044f \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u043c \u043f\u0440\u043e\u0431\u043b\u0435\u043c. \u041e\u043d\u0438 \u0443\u0441\u043b\u043e\u0436\u043d\u044f\u044e\u0442 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435, \u0441\u043e\u0437\u0434\u0430\u044e\u0442 \u0441\u043a\u0440\u044b\u0442\u044b\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0438, \u0447\u0442\u043e \u0445\u0443\u0436\u0435 \u0432\u0441\u0435\u0433\u043e, \u043d\u0430\u0440\u0443\u0448\u0430\u044e\u0442 \u0434\u0435\u0442\u0435\u0440\u043c\u0438\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0441\u0442\u044c.<\/p>\n<p>\u0423\u043d\u0438\u0447\u0442\u043e\u0436\u0438\u0442\u044c \u043f\u043e\u0431\u043e\u0447\u043d\u044b\u0435 \u044d\u0444\u0444\u0435\u043a\u0442\u044b \u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e. \u041d\u043e \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u043c \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u043c\u043e\u0436\u043d\u043e:<\/p>\n<ul>\n<li>\n<p>\u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0443\u0435\u043c\u043e\u0441\u0442\u044c \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u044d\u0442\u0438\u0445 \u044d\u0444\u0444\u0435\u043a\u0442\u043e\u0432, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u043c\u043e\u043d\u0430\u0434\u044b; <\/p>\n<\/li>\n<li>\n<p>\u0432\u044b\u043d\u043e\u0441\u0438\u0442\u044c \u044d\u0444\u0444\u0435\u043a\u0442\u044b \u0437\u0430 \u043f\u0440\u0435\u0434\u0435\u043b\u044b \u0447\u0438\u0441\u0442\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439.<\/p>\n<\/li>\n<\/ul>\n<p>\u0418\u0437\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0431\u043e\u0447\u043d\u044b\u0435 \u044d\u0444\u0444\u0435\u043a\u0442\u044b \u043d\u0430 <em>UI-\u0441\u043b\u043e\u0435<\/em> \u043c\u043e\u0436\u043d\u043e \u0432\u043d\u0435\u0434\u0440\u0438\u0432 <em>Launch<\/em>, <em>Disposable<\/em> \u0438\u043b\u0438 <br \/><em>Side<\/em>&#8212;<em>\u044d\u0444\u0444\u0435\u043a\u0442\u044b<\/em> \u0438\u0437 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 <em>Compose<\/em>.<\/p>\n<p>\u0414\u0440\u0443\u0433\u0438\u043c \u043f\u0440\u0438\u0451\u043c\u043e\u043c \u0438\u0437\u043e\u043b\u044f\u0446\u0438\u0438 \u043f\u043e\u0431\u043e\u0447\u043d\u044b\u0445 \u044d\u0444\u0444\u0435\u043a\u0442\u043e\u0432 \u043d\u0430 <em>UI<\/em>&#8212;<em>\u0441\u043b\u043e\u0435<\/em>, \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u0435 <code>Launch<\/code><em>, <\/em><code>Disposable<\/code><em> <\/em>\u0438\u043b\u0438<em> <\/em><code>Side<\/code> \u044d\u0444\u0444\u0435\u043a\u0442\u043e\u0432 \u0438\u0437 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 <em>Compose<\/em>.<\/p>\n<p><em>Compose<\/em> \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d \u043d\u0430 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0430\u0445 \u0424\u041f: <\/p>\n<p>\u041a\u0430\u043a \u044f \u0443\u0436\u0435 \u0443\u043f\u043e\u043c\u0438\u043d\u0430\u043b \u0440\u0430\u043d\u0435\u0435, \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0438\u0437\u0431\u0430\u0432\u0438\u0442\u044c\u0441\u044f \u043e\u0442 \u044d\u0444\u0444\u0435\u043a\u0442\u043e\u0432 \u043d\u0435\u043b\u044c\u0437\u044f. \u0412 \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0442\u0430\u043a\u0438\u0445 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u0439 \u043c\u0430\u0441\u0441\u0430: \u0437\u0430\u043f\u0443\u0441\u043a \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438, \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0430 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0438, \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0430 \u043d\u0430 \u043f\u043e\u0442\u043e\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445. \u0415\u0441\u043b\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u044d\u0444\u0444\u0435\u043a\u0442\u044b \u043f\u0440\u044f\u043c\u043e \u0432 \u0442\u0435\u043b\u0435 <em>Composable-\u0444\u0443\u043d\u043a\u0446\u0438\u0439<\/em>, \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u043e\u0438\u0437\u043e\u0439\u0442\u0438 \u043d\u0435\u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u0443\u0435\u043c\u0430\u044f \u0440\u0435\u043a\u043e\u043c\u043f\u043e\u0437\u0438\u0446\u0438\u044f, \u0443\u0442\u0435\u0447\u043a\u0430 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u0438\u043b\u0438 \u043a\u0440\u0430\u0448 \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u0440\u0438\u0441\u043e\u0432\u043a\u0435. \u0427\u0442\u043e\u0431\u044b \u0440\u0435\u0448\u0438\u0442\u044c \u044d\u0442\u0443 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443, \u0431\u044b\u043b\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u044b <em>Effects<\/em>.<\/p>\n<p><code>LaunchedEffect<\/code> \u0434\u043b\u044f \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0445 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439. \u041e\u043d \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0443 \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u043e\u0433\u043e \u0446\u0438\u043a\u043b\u0430 <em>Composable<\/em>. \u041e\u043d\u0430 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043e\u0442\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u043f\u0440\u0438 \u0432\u044b\u0445\u043e\u0434\u0435 \u0438\u0437 \u043a\u043e\u043c\u043f\u043e\u0437\u0438\u0446\u0438\u0438. \u042d\u0442\u043e\u0442 \u0442\u0438\u043f \u044d\u0444\u0444\u0435\u043a\u0442\u043e\u0432 \u0441\u0442\u043e\u0438\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432 \u0437\u0430\u0434\u0430\u0447\u0430\u0445, \u043f\u0440\u0438\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0445 \u043a \u043a\u043b\u044e\u0447\u0430\u043c \u0438\u043b\u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f\u043c.<\/p>\n<pre><code class=\"kotlin\">@Composable  fun UserProfile(userId: String) {     LaunchedEffect(key1 = userId) { \/\/ \u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 userId         val user = api.fetchUser(userId) \/\/ \u0421\u0435\u0442\u0435\u0432\u043e\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 (\u044d\u0444\u0444\u0435\u043a\u0442)         updateUi(user)     } }<\/code><\/pre>\n<p><code>DisposableEffect<\/code> <em>\u2014 <\/em>\u0430\u043d\u0430\u043b\u043e\u0433<em> <\/em><code>LaunchedEffect<\/code><em>, <\/em>\u043d\u043e \u0441 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c\u044e \u043e\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u043a\u0430\u043a<em> <\/em><code>onDestroy<\/code><em> <\/em>\u0432<em> <\/em><code>Activity<\/code><em>.<\/em> \u0415\u0433\u043e \u0441\u0442\u043e\u0438\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0438 \u0438\u043b\u0438 \u043e\u0442\u043f\u0438\u0441\u043a\u0438 \u043d\u0430 \u043f\u043e\u0442\u043e\u043a\u0438, \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044e \u0441\u043b\u0443\u0448\u0430\u0442\u0435\u043b\u0435\u0439 \u0438\u043b\u0438 \u0435\u0451 \u043e\u0442\u043c\u0435\u043d\u0443<em>.<\/em><\/p>\n<pre><code class=\"kotlin\">@Composable fun LocationTracker() {     val player = remember { createExoPlayer(\"example.mp3\") }           DisposableEffect(player) {         val listener = object : Player.Listener {       override fun onPlaybackStateChanged(playbackState: Int) {         when (playbackState) {           Player.STATE_ENDED -&gt; {             player.seekTo(0) \/\/ \u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0432 \u043d\u0430\u0447\u0430\u043b\u043e, \u043d\u043e \u043d\u0435 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u043c           }         }       }     }     player.addListener(listener)     onDispose {       player.removeListener(listener)       player.release()     }   } }<\/code><\/pre>\n<p>\u0414\u043b\u044f \u0442\u0430\u043a\u043e\u0433\u043e \u0442\u0438\u043f\u0430 \u044d\u0444\u0444\u0435\u043a\u0442\u0430 \u0435\u0441\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u0440\u0438\u0432\u044f\u0437\u0430\u0442\u044c\u0441\u044f \u043a \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u043e\u043c\u0443 \u0446\u0438\u043a\u043b\u0443 <code>Activity<\/code>. \u0412\u0430\u0448 \u0432\u0430\u0440\u0438\u0430\u043d\u0442, \u0435\u0441\u043b\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0435 <code>lifecycleOwner<\/code> \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0435 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u0438.<\/p>\n<p><code>SideEffect<\/code><em> \u2014 <\/em>\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432\u043d\u0435\u0448\u043d\u0435\u0433\u043e \u043c\u0438\u0440\u0430. \u042d\u0442\u043e\u0442 \u0432\u0438\u0434 \u044d\u0444\u0444\u0435\u043a\u0442\u043e\u0432 \u043e\u0434\u043d\u043e\u043a\u0440\u0430\u0442\u043d\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u043a\u043e\u0434 \u043f\u043e\u0441\u043b\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0439 \u0440\u0435\u043a\u043e\u043c\u043f\u043e\u0437\u0438\u0446\u0438\u0438. \u041e\u043d \u043d\u0435 \u0438\u043c\u0435\u0435\u0442 \u0441\u0432\u043e\u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0438 \u043f\u0440\u0438\u0432\u044f\u0437\u043a\u0438 \u043a \u043a\u043b\u044e\u0447\u0430\u043c \u2014 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u043d\u0435\u043c\u0435\u0434\u043b\u0435\u043d\u043d\u043e, \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e \u0438 \u0432 <em>UI-\u043f\u043e\u0442\u043e\u043a\u0435<\/em>.<\/p>\n<p>\u042d\u0442\u043e\u0442 \u0432\u0438\u0434 \u043f\u043e\u0431\u043e\u0447\u043d\u044b\u0445 \u044d\u0444\u0444\u0435\u043a\u0442\u043e\u0432 \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u0434\u043b\u044f:<\/p>\n<ul>\n<li>\n<p>\u043b\u0435\u0433\u043a\u043e\u0432\u0435\u0441\u043d\u044b\u0445 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439: \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435, \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0430 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0438, \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0432\u043d\u0435\u0448\u043d\u0438\u0445 \u043a\u044d\u0448\u0435\u0439;<\/p>\n<\/li>\n<li>\n<p>\u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u044b\u0445 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0439: \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0445 <em>UI-\u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432<\/em> \u0438 \u0442.\u0434.<\/p>\n<\/li>\n<li>\n<p>\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u0441 \u0432\u043d\u0435\u0448\u043d\u0438\u043c\u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u0430\u043c\u0438: \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 <em>legacy-\u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432<\/em>: <code>View<\/code>, <code>Fragment<\/code>; \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0441 \u043d\u0430\u0442\u0438\u0432\u043d\u044b\u043c\u0438 <em>API<\/em>: <code>WebView<\/code>, <code>CameraX<\/code>; \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f \u0441 <em>\u043d\u0435-Compose<\/em> \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430\u043c\u0438.<\/p>\n<\/li>\n<\/ul>\n<pre><code class=\"kotlin\">@Composable fun rememberFirebaseAnalytics(user: User): FirebaseAnalytics {     val analytics: FirebaseAnalytics = remember {         FirebaseAnalytics()     }      SideEffect {         analytics.setUserProperty(\"userType\", user.userType)     }     return analytics }<\/code><\/pre>\n<p>\u041d\u043e \u043d\u0435 \u0432\u0441\u0451 \u0442\u0430\u043a \u0438\u0434\u0435\u0430\u043b\u044c\u043d\u043e. <code>SideEffetct<\/code> \u043d\u0435 \u0434\u043e\u043b\u0436\u0435\u043d \u0438\u0437\u043c\u0435\u043d\u044f\u0442\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 <em>Compose<\/em>, \u0438\u043d\u0430\u0447\u0435 \u044d\u0442\u043e \u0432\u044b\u0437\u043e\u0432\u0435\u0442 \u0431\u0435\u0441\u043a\u043e\u043d\u0435\u0447\u043d\u0443\u044e \u0440\u0435\u043a\u043e\u043c\u043f\u043e\u0437\u0438\u0446\u0438\u044e. \u042d\u0442\u043e\u0442 \u0432\u0438\u0434 \u044d\u0444\u0444\u0435\u043a\u0442\u043e\u0432 \u043d\u0435 \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043a\u043e\u0440\u0443\u0442\u0438\u043d \u2014 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0435\u0441\u0442\u044c <code>LaunchedEffect<\/code>.<\/p>\n<p>\u0410 \u0435\u0449\u0451 \u0441 <code>SideEffect<\/code> \u0431\u043e\u043b\u0435\u0437\u043d\u0435\u043d\u043d\u043e \u043f\u0435\u0440\u0435\u043d\u043e\u0441\u0438\u0442\u044c \u0442\u044f\u0436\u0435\u043b\u043e\u0432\u0435\u0441\u043d\u044b\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043e\u043d \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0432 <em>UI-\u043f\u043e\u0442\u043e\u043a\u0435<\/em>. \u0422\u0430\u043a \u043a\u0430\u043a \u0436\u0438\u0442\u044c \u0441 \u043f\u043e\u0431\u043e\u0447\u043d\u044b\u043c\u0438 \u044d\u0444\u0444\u0435\u043a\u0442\u0430\u043c\u0438 \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u043c \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438?<\/p>\n<ul>\n<li>\n<p>\u043f\u0440\u0438\u0437\u043d\u0430\u0439\u0442\u0435 \u0438\u0445 \u043d\u0435\u0438\u0437\u0431\u0435\u0436\u043d\u043e\u0441\u0442\u044c. \u0411\u0435\u0437 \u044d\u0444\u0444\u0435\u043a\u0442\u043e\u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0431\u0435\u0441\u043f\u043e\u043b\u0435\u0437\u043d\u043e;<\/p>\n<\/li>\n<li>\n<p>\u0438\u0437\u043e\u043b\u0438\u0440\u0443\u0439\u0442\u0435 \u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u0443\u0439\u0442\u0435 \u0438\u0445. \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b \u2014 \u043c\u043e\u043d\u0430\u0434\u044b \u0438\u043b\u0438 <em>Compose Effects<\/em>;<\/p>\n<\/li>\n<li>\n<p>\u0441\u043b\u0435\u0434\u0443\u0439\u0442\u0435 \u043f\u0440\u043e\u0441\u0442\u044b\u043c \u043f\u0440\u0430\u0432\u0438\u043b\u0430\u043c: \u044d\u0444\u0444\u0435\u043a\u0442\u044b \u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u044b \u0437\u0430\u0432\u0438\u0441\u0435\u0442\u044c \u043e\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0438\u043b\u0438 \u043a\u043b\u044e\u0447\u0435\u0439; \u0440\u0435\u0441\u0443\u0440\u0441\u044b \u043d\u0443\u0436\u043d\u043e \u043e\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0430\u0442\u044c; \u0432 \u0442\u0435\u043b\u0435 <em>Composable<\/em> \u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u043d\u0435 \u0434\u0435\u0442\u0435\u0440\u043c\u0438\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u044d\u0444\u0444\u0435\u043a\u0442\u043e\u0432.<\/p>\n<\/li>\n<\/ul>\n<p><em>Compose-\u044d\u0444\u0444\u0435\u043a\u0442\u044b \u2014 <\/em>\u044d\u0442\u043e \u044d\u043b\u0435\u0433\u0430\u043d\u0442\u043d\u043e\u0435 \u0432\u043e\u043f\u043b\u043e\u0449\u0435\u043d\u0438\u0435 \u0438\u0434\u0435\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0432<em> Android. <\/em>\u041e\u043d\u0438 \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u044e\u0442 \u0445\u0430\u043e\u0442\u0438\u0447\u043d\u044b\u0435 \u043f\u043e\u0431\u043e\u0447\u043d\u044b\u0435 \u044d\u0444\u0444\u0435\u043a\u0442\u044b \u0432 \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0443\u0435\u043c\u044b\u0435 \u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c\u044b\u0435 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438. \u0422\u0430\u043a\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0441\u0442\u0440\u043e\u0438\u0442\u044c \u043e\u0442\u0437\u044b\u0432\u0447\u0438\u0432\u044b\u0435 \u0438 \u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u044b\u0435 <em>UI-\u0441\u0438\u0441\u0442\u0435\u043c\u044b.<\/em><\/p>\n<h2>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f\u0445 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0439 \u0444\u0438\u0447\u0438<\/h2>\n<p>\u0423 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c:<\/p>\n<ul>\n<li>\n<p>\u0447\u0438\u0441\u0442\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438;<\/p>\n<\/li>\n<li>\n<p><em>Either<\/em> \u0438 <em>Compose Effects<\/em> \u0434\u043b\u044f \u0431\u043e\u0440\u044c\u0431\u044b \u0441 \u00ab\u0433\u0440\u044f\u0437\u043d\u044b\u043c\u0438\u00bb \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u043c\u0438;<\/p>\n<\/li>\n<li>\n<p><em>Closure (Capability Passing)<\/em> \u0434\u043b\u044f \u0437\u0430\u043c\u0435\u043d\u044b <em>DI<\/em>;<\/p>\n<\/li>\n<li>\n<p><em>ELM-\u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430<\/em>, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u044d\u0442\u043e \u0432\u0441\u0451 \u0434\u043e\u043b\u0436\u043d\u043e \u043f\u043e \u0438\u0434\u0435\u0435 \u0437\u0430\u0432\u0435\u0441\u0442\u0438\u0441\u044c.<\/p>\n<\/li>\n<\/ul>\n<p>\u0414\u043e\u0441\u043a\u043e\u043d\u0430\u043b\u044c\u043d\u043e \u0440\u0430\u0441\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u043a\u0430\u0436\u0434\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 \u0438 \u044d\u043a\u0440\u0430\u043d \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u044f \u043d\u0435 \u0431\u0443\u0434\u0443 \u2014 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u044e \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u0430\u043c\u044b\u0435 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0435 \u043a\u0435\u0439\u0441\u044b. \u0418\u0442\u043e\u0433\u043e\u0432\u044b\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043d\u0430\u0439\u0434\u0451\u0442\u0435 \u0432 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u043c \u043a\u043e\u0434\u0435 \u2014 <a href=\"https:\/\/github.com\/realist-pessimist\/FRP-SilentMoon\" rel=\"noopener noreferrer nofollow\">\u043e\u043d \u0442\u0443\u0442, \u0432 \u0432\u0435\u0442\u043a\u0435 <em>feature\/make_application<\/em><\/a>.<\/p>\n<p>\u041d\u0430\u0447\u043d\u0451\u043c \u0441 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u0439 \u0444\u0438\u0447\u0438 \u2014 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0440\u0435\u0436\u0438\u043c\u0430 \u0441\u043d\u0430 \u0438 \u0431\u043e\u0434\u0440\u0441\u0442\u0432\u043e\u0432\u0430\u043d\u0438\u044f. \u041d\u0430 \u043f\u0435\u0440\u0432\u044b\u0439 \u0432\u0437\u0433\u043b\u044f\u0434, \u0437\u0430\u0434\u0430\u0447\u0430 \u043f\u0440\u043e\u0441\u0442\u0430\u044f \u2014 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u0432\u0438\u0442\u0447\u0435\u0440<\/p>\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-473221","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/473221","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=473221"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/473221\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=473221"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=473221"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=473221"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}