{"id":324141,"date":"2021-06-01T15:00:53","date_gmt":"2021-06-01T15:00:53","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=324141"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=324141","title":{"rendered":"Proto DataStore + AndroidX Preferences \u043d\u0430 Kotlin"},"content":{"rendered":"\n<div class=\"post__text post__text_v2\" id=\"post-content-body\">\n<p>\u0421 \u0442\u0435\u0445 \u043f\u043e\u0440, \u043a\u0430\u043a \u043a\u043e\u043c\u0430\u043d\u0434\u0430 Google AndroidX \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u043b\u0430 \u043d\u0430 \u0437\u0430\u043c\u0435\u043d\u0443 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 SharedPreferences <a href=\"https:\/\/developer.android.com\/topic\/libraries\/architecture\/datastore\" rel=\"noopener noreferrer nofollow\">\u043d\u043e\u0432\u0443\u044e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 DataStore<\/a>, \u043f\u0440\u043e\u0448\u0435\u043b \u043f\u043e\u0447\u0442\u0438 \u0433\u043e\u0434, \u043e\u0434\u043d\u0430\u043a\u043e \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u0438\u0437\u0430\u0446\u0438\u044f \u043d\u043e\u0432\u043e\u0439 \u043b\u0438\u0431\u044b \u044f\u0432\u043d\u043e \u043d\u0435 \u0441\u0442\u043e\u0438\u0442 \u0432 \u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0445 \u0437\u0430\u0434\u0430\u0447\u0430\u0445. \u0418\u043d\u0430\u0447\u0435 \u044f \u043d\u0435 \u043c\u043e\u0433\u0443 \u043e\u0431\u044a\u044f\u0441\u043d\u0438\u0442\u044c 1) \u043d\u0435\u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u044b\u0439 \u0433\u0430\u0439\u0434, \u0441\u043b\u0435\u0434\u0443\u044f \u043b\u0438\u0448\u044c \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443, \u0443 \u0432\u0430\u0441 \u0432\u043e\u043e\u0431\u0449\u0435 \u043d\u0435 \u0441\u043e\u0431\u0435\u0440\u0435\u0442\u0441\u044f \u043f\u0440\u043e\u0435\u043a\u0442 \u0438\u0437-\u0437\u0430 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u044f \u0432\u0441\u0435\u0445 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0445 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u0438 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 build-\u0437\u0430\u0434\u0430\u0447 \u0434\u043b\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0441\u0431\u043e\u0440\u043a\u0438, \u0438 2) \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435 \u043d\u0435 hello-world \u043f\u043e\u0434\u043e\u0431\u043d\u044b\u0445 \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u0432 \u0432 CodeLabs, \u043a\u0440\u043e\u043c\u0435 \u043e\u0434\u043d\u043e\u0433\u043e, \u0438 \u0442\u043e, \u0437\u0430\u0442\u043e\u0447\u0435\u043d\u043d\u043e\u0433\u043e \u043d\u0435 \u043f\u043e\u0434 \u043f\u0440\u0438\u043c\u0435\u0440 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0441 \u043d\u0443\u043b\u044f, \u0430 \u043f\u043e\u0434 <a href=\"https:\/\/codelabs.developers.google.com\/codelabs\/android-proto-datastore\" rel=\"noopener noreferrer nofollow\">\u043c\u0438\u0433\u0440\u0430\u0446\u0438\u044e \u0441 SharedPreferences \u043d\u0430 Preferences DataStore<\/a>. \u0410\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e \u0432\u0441\u0435 \u0441\u0442\u0430\u0442\u044c\u0438 \u043d\u0430 Medium \u0431\u0443\u043a\u0432\u0430\u043b\u044c\u043d\u043e \u0438\u043b\u0438 \u0434\u0440\u0443\u0433\u0438\u043c\u0438 \u0441\u043b\u043e\u0432\u0430\u043c\u0438 \u043f\u043e\u0432\u0442\u043e\u0440\u044f\u044e\u0442 \u0432\u0441\u0435 \u0442\u043e \u0436\u0435, \u0447\u0442\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043e \u0432 \u0433\u0430\u0439\u0434\u0435 Google, \u043b\u0438\u0431\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 \u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0435 \u043f\u043e\u0434\u0445\u043e\u0434\u044b \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 DataStore, \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044f \u0437\u0430\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0442\u044c \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 io-\u043a\u043e\u0434 \u0432 runBlocking \u043f\u0440\u044f\u043c\u043e \u043d\u0430 ui-\u043f\u043e\u0442\u043e\u043a\u0435.<\/p>\n<p>\u0410 \u0435\u0449\u0435 \u043d\u0435\u043f\u043b\u043e\u0445\u043e \u0431\u044b \u0441\u043e\u0435\u0434\u0438\u043d\u0438\u0442\u044c &#171;\u0442\u044b\u043b&#187; \u0441 &#171;\u0444\u0440\u043e\u043d\u0442\u043e\u043c&#187;, \u0442\u0430\u043a \u0441\u043a\u0430\u0437\u0430\u0442\u044c: \u0443 Google \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 <a href=\"https:\/\/developer.android.com\/guide\/topics\/ui\/settings\" rel=\"noopener noreferrer nofollow\">AndroidX Preferences<\/a> \u0438\u0437 \u043e\u0431\u043e\u0439\u043c\u044b Jetpack, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0432 \u0434\u0432\u0430 \u043a\u043b\u0438\u043a\u0430 \u043d\u0430\u043a\u0438\u0434\u0430\u0442\u044c \u0433\u043e\u0442\u043e\u0432\u044b\u0439 material-design \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u043c\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438 \u0438\u0437\u043b\u044e\u0431\u043b\u0435\u043d\u043d\u044b\u043c \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u043c \u043a\u043e\u0434\u043e\u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u043e\u0441\u0432\u043e\u0431\u043e\u0434\u0438\u0442\u044c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u043e\u0442 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f boilerplate. \u041e\u0434\u043d\u0430\u043a\u043e \u044d\u0442\u0430 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430 \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0443\u0441\u0442\u0430\u0440\u0435\u0432\u0448\u0438\u0435 \u043d\u044b\u043d\u0447\u0435 SharedPreferences, \u0430 \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0433\u0430\u0439\u0434\u0430 \u043f\u043e \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044e \u0441 DataStore \u043d\u0435\u0442. \u0412 \u044d\u0442\u043e\u0439 \u0437\u0430\u043c\u0435\u0442\u043a\u0435 \u044f \u0445\u043e\u0442\u0435\u043b \u0431\u044b \u0441\u0432\u043e\u0438\u043c \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u043c \u0443\u0441\u0442\u0440\u0430\u043d\u0438\u0442\u044c \u0434\u0432\u0430 \u043e\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0445 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043a\u0430.<\/p>\n<h4>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043a\u0430\u0440\u043a\u0430\u0441\u0430 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 DataStore<\/h4>\n<p>\u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 DataStore \u0434\u0435\u043b\u0438\u0442\u0441\u044f \u043d\u0430 \u0434\u0432\u0435 \u0447\u0430\u0441\u0442\u0438: \u0430\u043d\u0430\u043b\u043e\u0433 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0439 \u043f\u043e\u0434 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c Preferences DataStore, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0445\u0440\u0430\u043d\u0438\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u0432 \u043f\u0430\u0440\u0430\u0445 \u043a\u043b\u044e\u0447-\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0438 \u043d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0442\u0438\u043f\u043e\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0439, \u0438 \u0432\u0442\u043e\u0440\u0430\u044f, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0445\u0440\u0430\u043d\u0438\u0442 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0432 \u0444\u0430\u0439\u043b\u0435 \u0444\u043e\u0440\u043c\u0430\u0442\u0430 Protocol buffers \u0438 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0442\u0438\u043f\u043e\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0439. \u041e\u043d\u0430 \u0431\u043e\u043b\u0435\u0435 \u0433\u0438\u0431\u043a\u0430\u044f \u0438 \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u0430\u044f, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u0432\u044b\u0431\u0440\u0430\u043b \u0435\u0435 \u0434\u043b\u044f \u0441\u0432\u043e\u0438\u0445 \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u043e\u0432. <\/p>\n<p>\u0414\u043b\u044f \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0441\u0445\u0435\u043c\u044b \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u043d\u0443\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0444\u0430\u0439\u043b \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435. \u0412\u043e-\u043f\u0435\u0440\u0432\u044b\u0445, \u043d\u0430\u0434\u043e \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043f\u0440\u043e\u0432\u043e\u0434\u043d\u0438\u043a \u0441\u0442\u0443\u0434\u0438\u0438 \u0438\u043b\u0438 \u0438\u0434\u0435\u0438 \u0432 \u0440\u0435\u0436\u0438\u043c Project, \u0447\u0442\u043e\u0431\u044b \u0431\u044b\u043b\u0430 \u0432\u0438\u0434\u043d\u0430 \u0432\u0441\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0430\u043f\u043e\u043a, \u0438 \u043f\u043e\u0442\u043e\u043c \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0432 \u043f\u0430\u043f\u043a\u0435 app\/src\/main\/proto\/ \u0444\u0430\u0439\u043b \u0441 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435\u043c <strong>*.proto<\/strong> (\u0430 \u043d\u0435 pb, \u043a\u0430\u043a \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u0442 Google &#8212; \u0441 \u043d\u0438\u043c \u043d\u0438 \u043f\u043b\u0430\u0433\u0438\u043d \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441\u0430, \u0430\u0432\u0442\u043e\u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0438 \u0442.\u043f., \u043d\u0438 build-\u0437\u0430\u0434\u0430\u0447\u0430, \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u044e\u0449\u0430\u044f \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u043a\u043b\u0430\u0441\u0441, \u043d\u0435 \u0441\u0442\u0430\u043d\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c).<\/p>\n<p>\u0421\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441 Protocol buffer <a href=\"https:\/\/developers.google.com\/protocol-buffers\/docs\/proto3\" rel=\"noopener noreferrer nofollow\">\u043e\u0447\u0435\u043d\u044c \u0445\u043e\u0440\u043e\u0448\u043e \u043e\u043f\u0438\u0441\u0430\u043d \u0441\u0430\u043c\u0438\u043c Google<\/a>, \u043d\u0435 \u0438\u043c\u0435\u0435\u0442 \u0441\u043c\u044b\u0441\u043b\u0430 \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c. \u041f\u0440\u0438\u0432\u0435\u0434\u0443 \u0442\u0435\u043a\u0441\u0442 \u0444\u0430\u0439\u043b\u0430, \u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u0431\u0443\u0434\u0443 \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435:<\/p>\n<pre><code>syntax = \"proto3\";  option java_package = \"\u043f\u043e\u043b\u043d\u043e\u0435.\u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435.\u0432\u0430\u0448\u0435\u0433\u043e.\u043f\u0430\u043a\u0435\u0442\u0430\"; option java_multiple_files = true;  message ProtoSettings {   bool translate_to_ru = 1;   map&lt;string, int64&gt; last_sync = 2;   int32 refresh_interval = 3; }<\/code><\/pre>\n<p>\u0412 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u0445 \u0431\u0443\u0434\u0443\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u044c\u0441\u044f \u0431\u0443\u043b\u0435\u0432\u044b\u0439 \u0444\u043b\u0430\u0433 \u0434\u043b\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0430 \u0442\u0435\u043a\u0441\u0442\u0430 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438, \u0446\u0435\u043b\u043e\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435, \u0437\u0430\u0434\u0430\u044e\u0449\u0435\u0435 \u043f\u0435\u0440\u0438\u043e\u0434 \u0434\u043b\u044f \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c, \u0438 \u0441\u043b\u043e\u0432\u0430\u0440\u044c \u0441 \u043a\u043b\u044e\u0447\u043e\u043c-\u0441\u0442\u0440\u043e\u043a\u043e\u0439 \u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c-long Kotlin, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c\u0441\u044f unix-\u0432\u0440\u0435\u043c\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0439 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 (\u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u0435\u043b\u044f\u0442c\u044f \u043d\u0430 data \u043a\u043b\u0430\u0441\u0441\u044b, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432 \u043a\u043b\u044e\u0447\u0435 \u043c\u043e\u0436\u043d\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c simple name \u044d\u0442\u043e\u0433\u043e \u043a\u043b\u0430\u0441\u0441\u0430).<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0443\u043a\u0430\u0436\u0435\u043c \u0432\u0441\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0438 \u0437\u0430\u0434\u0430\u0447\u0438 \u0434\u043b\u044f build.gradle-\u0444\u0430\u0439\u043b\u0430 \u043c\u043e\u0434\u0443\u043b\u044f:<\/p>\n<pre><code>plugins {     ...     id \"com.google.protobuf\" version \"0.8.12\" } ... dependencies { \t  ...     \/\/DataStore     implementation \"androidx.datastore:datastore:1.0.0-beta01\"     implementation \"com.google.protobuf:protobuf-javalite:3.11.0\"     implementation \"androidx.preference:preference-ktx:1.1.1\" }  protobuf {     protoc {         artifact = \"com.google.protobuf:protoc:3.11.0\"     }      generateProtoTasks {         all().each { task -&gt;             task.builtins {                 java {                     option 'lite'                 }             }         }     } } <\/code><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u0438\u0445 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f proto-\u0444\u0430\u0439\u043b\u0430 \u0432 \u043d\u0443\u0436\u043d\u043e\u043c \u043c\u0435\u0441\u0442\u0435 \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u043f\u0435\u0440\u0435\u0441\u043e\u0431\u0440\u0430\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442, \u0447\u0442\u043e\u0431\u044b \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043b\u0441\u044f java \u043a\u043b\u0430\u0441\u0441 \u0434\u043b\u044f DataStore \u043f\u043e \u0441\u0445\u0435\u043c\u0435 \u0438\u0437 proto. <\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0441\u043a\u0430\u0436\u0443 \u043e\u0431 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0438 \u0432\u0430\u0436\u043d\u043e\u0439 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438 DataStore: \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 \u0444\u043e\u043d\u043e\u0432\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u0434\u043b\u044f \u0437\u0430\u043f\u0438\u0441\u0438\/\u0447\u0442\u0435\u043d\u0438\u044f \u0438\u0437 \u0444\u0430\u0439\u043b\u043e\u0432\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b, \u0430 \u0441\u0430\u043c\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043f\u043e\u0441\u043b\u0435 \u0447\u0442\u0435\u043d\u0438\u044f \u0438\u0437 \u0444\u0430\u0439\u043b\u0430 \u0432\u044b\u0434\u0430\u044e\u0442\u0441\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Flow. \u0417\u0430\u043f\u0438\u0441\u044c \u0436\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 set-\u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0438 \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u0430 builder. \u041e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u0441 Flow \u0437\u0430\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442 \u043e\u0447\u0435\u043d\u044c \u0441\u0438\u043b\u044c\u043d\u043e \u043c\u0435\u043d\u044f\u0442\u044c \u043f\u043e\u0434\u0445\u043e\u0434 \u043a \u0442\u0430\u043a\u043e\u0439 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0448\u0442\u0443\u043a\u0435, \u043a\u0430\u043a \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0432\u0435\u0434\u044c \u0438\u043d\u0430\u0447\u0435, \u043a\u0430\u043a \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0432\u044b\u0437\u043e\u0432\u0430 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0445 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u0432 collect &amp; Co \u0438\u0445 \u0442\u0435\u043f\u0435\u0440\u044c \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0448\u044c.<\/p>\n<blockquote>\n<p>\u0412\u0430\u0436\u043d\u043e! \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 deprecated-\u043c\u0435\u0442\u043e\u0434\u044b Flow toList \u0438\u043b\u0438 toSet, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043e\u043d\u0438 \u043f\u043e\u0432\u0435\u0441\u044f\u0442 \u0432\u0430\u0448 \u043c\u0435\u0442\u043e\u0434 \u043d\u0430\u0432\u0441\u0435\u0433\u0434\u0430 (<em>flow never completes, so this terminal operation never completes<\/em>). <\/p>\n<\/blockquote>\n<p>\u0414\u043b\u044f \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u0439 \u0440\u0430\u0431\u043e\u0442\u044b \u043d\u0443\u0436\u043d\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0435\u0449\u0435 \u043d\u0435\u043c\u043d\u043e\u0433\u043e boilerplate \u043a\u043e\u0434\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u043e\u043b\u0436\u0435\u043d \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u043a\u043b\u0430\u0441\u0441\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0435\u0441\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u0438\u043d \u0441\u043f\u043e\u0441\u043e\u0431, \u0438 \u043f\u043e\u0447\u0435\u043c\u0443 Google \u043d\u0435 \u0437\u0430\u0432\u0435\u0440\u043d\u0443\u043b \u0435\u0433\u043e \u0432 \u043a\u043e\u0434\u043e\u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044e, \u0443\u043c\u0430 \u043d\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0443: <\/p>\n<pre><code class=\"kotlin\">@Suppress(\"BlockingMethodInNonBlockingContext\") object SettingsSerializer : Serializer&lt;ProtoSettings&gt; {     override val defaultValue: ProtoSettings = ProtoSettings.getDefaultInstance()      override suspend fun readFrom(input: InputStream): ProtoSettings {         try {             return ProtoSettings.parseFrom(input)         } catch (exception: InvalidProtocolBufferException) {             throw CorruptionException(\"Cannot read proto.\", exception)         }     }      override suspend fun writeTo(t: ProtoSettings, output: OutputStream) = t.writeTo(output) }<\/code><\/pre>\n<p>\u042d\u0442\u043e\u0442 \u043e\u0431\u044a\u0435\u043a\u0442 Serializer \u0434\u043e\u043b\u0436\u0435\u043d \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c\u0441\u044f \u043a\u0430\u043a \u0441\u0438\u043d\u0433\u043b\u0442\u043e\u043d \u043f\u0440\u0438 \u043d\u0430\u0447\u0430\u043b\u0435 \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f (\u0434\u043e \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u043a \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u043c \u0432 \u043e\u0431\u0449\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435) \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<p>\u0418 \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u043a\u043b\u0430\u0441\u0441-\u043e\u0431\u0435\u0440\u0442\u043a\u0443 \u0434\u043b\u044f \u0447\u0442\u0435\u043d\u0438\u044f \u0438 \u0437\u0430\u043f\u0438\u0441\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430 \u043f\u0435\u0440\u0432\u044b\u0439 \u0432\u0437\u0433\u043b\u044f\u0434 \u0431\u0443\u0434\u0435\u0442 \u0438\u0437\u0431\u044b\u0442\u043e\u0447\u043d\u044b\u043c: \u0432\u043e-\u043f\u0435\u0440\u0432\u044b\u0445, \u043e\u043d \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u0437\u0430\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043c\u0435\u0442\u043e\u0434\u044b \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u0432 \u043d\u0443\u0436\u043d\u044b\u0435 \u0431\u0438\u043b\u0434\u0435\u0440\u044b, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u043f\u043b\u043e\u0434\u0438\u0442\u044c \u0438\u0445 \u043f\u043e \u0432\u0441\u0435\u043c\u0443 \u043f\u0440\u043e\u0435\u043a\u0442\u0443, \u0432\u043e-\u0432\u0442\u043e\u0440\u044b\u0445, \u0432 \u043a\u043b\u0430\u0441\u0441\u0435 \u043c\u043e\u0436\u043d\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0434\u0440\u0443\u0433\u0443\u044e \u0442\u0435\u043a\u0443\u0449\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e, \u0446\u0435\u043d\u043d\u0443\u044e \u043b\u0438\u0448\u044c \u043d\u0430 \u0432\u0440\u0435\u043c\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0438-\u043a\u043e\u043d\u0432\u0435\u0440\u0442\u043e\u0440\u044b, \u043d\u0443 \u0438 \u043f\u043b\u044e\u0441 \u044d\u0442\u043e\u0442 \u043a\u043b\u0430\u0441\u0441 \u0431\u0443\u0434\u0435\u0442 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Hilt \u043b\u0435\u0433\u043a\u043e \u0432\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438:<\/p>\n<pre><code class=\"kotlin\">class SettingsRepository @Inject constructor(val settings: DataStore&lt;ProtoSettings&gt;) {      val saved get() = settings.data.take(1)          suspend fun translateToRu(value: Boolean) = settings.updateData {         it.toBuilder().setTranslateToRu(value).build()     }      suspend fun saveLastSync(cls: String) = settings.updateData {         it.toBuilder().putLastSync(cls, System.currentTimeMillis()).build()     }      suspend fun refreshInterval(hours: Int) = settings.updateData {         it.toBuilder().setRefreshInterval(hours * HOUR_TO_MILLIS).build()     }      fun checkNeedSync(cls: String) = saved.map {         it.lastSyncMap[cls]?.run {             System.currentTimeMillis() - this &gt; saved.refreshInterval         } ?: true     } }  @Module @InstallIn(SingletonComponent::class) class SettingsModule {      @Provides     @Singleton     fun provideSettingsRepository(@ApplicationContext context: Context) = SettingsRepository(context.dataStore)      private val Context.dataStore: DataStore&lt;ProtoSettings&gt; by dataStore(         fileName = \"settings.proto\",         serializer = SettingsSerializer     ) }<\/code><\/pre>\n<p>\u0418\u0437 \u043a\u043e\u0434\u0430 \u0432\u0438\u0434\u043d\u043e, \u0447\u0442\u043e \u0441\u0430\u043c \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u043c \u044f \u0438\u043d\u043a\u0430\u043f\u0441\u0443\u043b\u0438\u0440\u043e\u0432\u0430\u043b \u0432 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u043c \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0435 saved, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0447\u0438\u0442\u0430\u0435\u0442 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0438\u0437 flow \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u0430 take(1). \u041f\u043e\u0441\u043b\u0435 \u0440\u0430\u0437\u043d\u044b\u0445 \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u043e\u0432 \u044d\u0442\u043e\u0442 \u0441\u043f\u043e\u0441\u043e\u0431 \u043c\u043d\u0435 \u043f\u043e\u043a\u0430\u0437\u0430\u043b\u0441\u044f \u0441\u0430\u043c\u044b\u043c \u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u043c \u0434\u043b\u044f \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u0438, \u043a\u043e\u0433\u0434\u0430 \u0432 \u043e\u0434\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0438 \u0447\u0438\u0442\u0430\u044e\u0442\u0441\u044f, \u0438 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0442\u0441\u044f. \u0415\u0441\u043b\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u043e collect, \u0442\u043e \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437, \u043a\u043e\u0433\u0434\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438, \u0441\u0442\u0430\u043d\u0435\u0442 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u044c emit \u043d\u043e\u0432\u043e\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0438 \u0437\u0430\u043d\u043e\u0432\u043e \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u044d\u0442\u0430 \u0436\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u044f. \u0415\u0441\u043b\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c first(), \u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0432\u0437\u044f\u0442\u043e \u043b\u0438\u0448\u044c \u043f\u0435\u0440\u0432\u043e\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u0438 flow \u0437\u0430\u043a\u0440\u043e\u0435\u0442\u0441\u044f. \u0415\u0441\u043b\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c last(), \u0442\u043e \u044d\u0442\u043e\u0442 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440 \u0431\u0443\u0434\u0435\u0442 \u0441\u043f\u043e\u0441\u043e\u0431\u0435\u043d \u043f\u043e\u0432\u0435\u0441\u0438\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e, \u0442.\u043a. \u043e\u043d \u043d\u0435 \u0437\u0430\u043a\u0440\u044b\u0432\u0430\u0435\u0442 flow.<\/p>\n<h4>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u0438\u0437 DataStore<\/h4>\n<p>\u041e\u043f\u0438\u0448\u0443 \u0432 \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u043c \u043f\u043b\u0430\u043d\u0435 \u044d\u0442\u0443 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044e. \u041f\u0440\u0435\u0434\u043f\u043e\u043b\u043e\u0436\u0438\u043c, \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435. \u0415\u0433\u043e \u0432 Kotlin \u043e\u0431\u0449\u0435\u043f\u0440\u0438\u043d\u044f\u0442\u043e \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u0430\u043b\u0433\u0435\u0431\u0440\u0430\u0438\u0447\u0435\u0441\u043a\u0438\u043c \u0442\u0438\u043f\u043e\u043c \u0434\u0430\u043d\u043d\u044b\u0445, \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u043c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e sealed \u043a\u043b\u0430\u0441\u0441\u0430:<\/p>\n<pre><code class=\"kotlin\">sealed class Result     data class Success&lt;out T&gt;(val data: T): Result()     data class Error(val msg: String, val error: ErrorType): Result()     object Loading : Result()<\/code><\/pre>\n<p>\u0412\u043e\u0442 \u043a\u0430\u043a \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0449\u0430\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043f\u0440\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u0434\u0430\u043d\u043d\u044b\u0445:<\/p>\n<pre><code class=\"kotlin\">fun &lt;T&gt; fetchItems(         itemsType: String,         remoteApiCallback: suspend () -&gt; Response&lt;ApiResponse&lt;T&gt;&gt;,         localApiCallback: suspend () -&gt; List&lt;T&gt;,         saveApiCallback: suspend (List&lt;T&gt;) -&gt; Unit,     ): Flow&lt;Result&gt; = settings.checkNeedSync(itemsType).transform { needSync -&gt;         var remoteFailed = true         emit(Loading)         localApiCallback().let { local -&gt;             if (needSync || local.isEmpty()) {                 if (networkHelper.isNetworkConnected()) {                     remoteApiCallback().apply {                         if (isSuccessful) body()?.docs?.let { remote -&gt;                             settings.saveLastSync(itemsType)                             remoteFailed = false                             emit(Success(remote))                             saveApiCallback(remote)                         }                         else emit(Error(errorBody().toString(), ErrorType.REMOTE_API_ERROR))                     }                 } else emit(Error(\"No internet connection!\", ErrorType.NO_INTERNET_CONNECTION))             }              if (remoteFailed)                 emit(if (local.isNotEmpty()) Success(local) else Error(\"No local saved data\", ErrorType.NO_SAVED_DATA))         }     }         .flowOn(Dispatchers.IO)         .catch { e -&gt;             ...         }<\/code><\/pre>\n<p>\u042d\u0442\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0432 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u0445 \u0441\u0442\u0440\u043e\u043a\u0443 \u0441 \u0442\u0438\u043f\u043e\u043c \u0434\u0430\u043d\u043d\u044b\u0445 (\u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043d\u0443\u0436\u043d\u0430 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0439 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u044d\u0442\u043e\u0433\u043e \u0442\u0438\u043f\u0430 \u0434\u0430\u043d\u043d\u044b\u0445) \u0438 \u0442\u0440\u0438 \u043a\u043e\u043b\u043b\u0431\u044d\u043a\u0430: \u0434\u043b\u044f \u0447\u0442\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u0430, \u0434\u043b\u044f \u0447\u0442\u0435\u043d\u0438\u044f \u0438\u0437 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043a\u044d\u0448\u0430 \u0438 \u0434\u043b\u044f \u0437\u0430\u043f\u0438\u0441\u0438 \u0432 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u043a\u044d\u0448. \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0441 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u043c \u0442\u0438\u043f\u043e\u043c \u0434\u0430\u043d\u043d\u044b\u0445 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a:<\/p>\n<pre><code>fun getSomething() = fetchItems&lt;Something&gt;(\"Something\", remoteApi::getSomething, localApi::getSomething, localApi::saveSomething) fun getSmthOther() = fetchItems&lt;Other&gt;(\"Other\", remoteApi::getSmthOther, localApi::getSmthOther, localApi::saveSmthOther)     <\/code><\/pre>\n<blockquote>\n<p>\u0415\u0441\u043b\u0438 \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443 \u0441 \u0442\u0438\u043f\u043e\u043c \u043a\u0430\u043a \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440, \u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0432\u043e\u043b\u0448\u0435\u0431\u043d\u043e\u0433\u043e \u0441\u043b\u043e\u0432\u0430 reified \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u0432\u043d\u0443\u0442\u0440\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043c\u0435\u0442\u0430\u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0442\u0438\u043f\u0430, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, T::class.simpleName, \u043e\u0434\u043d\u0430\u043a\u043e \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u0434\u0435\u043b\u0430\u0442\u044c inline, \u0430 \u043a\u043e\u043b\u043b\u0431\u0435\u043a\u0438 crossinline\/noinline, \u043d\u043e \u0442\u043e\u0433\u0434\u0430 \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u043e\u0446\u0435\u043d\u0438\u0432\u0430\u0442\u044c \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430 \u0442\u0430\u043a\u043e\u0433\u043e \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f. \u0418\u043c\u0435\u043d\u043d\u043e \u0437\u0434\u0435\u0441\u044c inline \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043d\u0435 \u0434\u0430\u0441\u0442 \u043d\u0438\u043a\u0430\u043a\u0438\u0445 \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432, \u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0441\u0442 \u0438\u0437\u0431\u044b\u0442\u043e\u0447\u043d\u044b\u0439 \u043a\u043e\u0434, \u043e \u0447\u0435\u043c \u043d\u0435\u043f\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u043f\u043e\u0434\u0441\u043a\u0430\u0436\u0435\u0442 \u0441\u0442\u0443\u0434\u0438\u044f\/\u0438\u0434\u0435\u044f, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043b\u0443\u0447\u0448\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u043e\u0432\u044b\u0439 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440.<\/p>\n<\/blockquote>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f checkNeedSync \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0442\u043e\u0436\u0435 flow, \u043a\u0430\u043a \u0432\u0438\u0434\u043d\u043e \u0438\u0437 \u043a\u043e\u0434\u0430 \u043a\u043b\u0430\u0441\u0441\u0430 SettingsRepository, \u0430 \u0447\u0442\u043e\u0431\u044b \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0432\u0435\u0440\u043d\u0443\u043b \u0443\u0436\u0435 \u0441\u0432\u043e\u0439 flow \u0442\u0438\u043f\u0430 Result \u043b\u0443\u0447\u0448\u0435 \u0432\u0441\u0435\u0433\u043e \u043f\u043e\u0434\u043e\u0439\u0434\u0435\u0442 <a href=\"https:\/\/kotlinlang.org\/docs\/flow.html#transform-operator\" rel=\"noopener noreferrer nofollow\">\u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440 transform<\/a>. \u041e\u0431\u0449\u0438\u0439 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0442\u0430\u043a\u043e\u0439: \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442\u0441\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 Loading (\u0447\u0442\u043e\u0431\u044b \u043d\u0430 ui \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u043d\u0430\u0447\u0430\u0442\u044c \u043a\u0430\u043a\u0443\u044e-\u0442\u043e \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044e \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438), \u0437\u0430\u0442\u0435\u043c \u0447\u0438\u0442\u0430\u044e\u0442\u0441\u044f \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435. \u0415\u0441\u043b\u0438 \u043e\u043d\u0438 \u0443\u0441\u0442\u0430\u0440\u0435\u0432\u0448\u0438\u0435 \u0438\u043b\u0438 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u044e\u0442, \u0434\u0430\u043d\u043d\u044b\u0435 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u044e\u0442\u0441\u044f \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u0430, \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e, \u0430 \u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u0445 \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0432\u0440\u0435\u043c\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u044d\u0442\u043e\u0433\u043e \u0442\u0438\u043f\u0430. \u0412 \u0442\u0435\u043e\u0440\u0438\u0438, \u0442\u0430\u043a \u043a\u0430\u043a \u0432\u043d\u0443\u0442\u0440\u0438  checkNeedSync \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0447\u0438\u0442\u0430\u044e\u0442\u0441\u044f \u043e\u0434\u0438\u043d \u0440\u0430\u0437 (<em>take (1)<\/em>), emit \u043d\u043e\u0432\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u0438\u0437-\u0437\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u043d\u0435 \u0437\u0430\u0441\u0442\u0430\u0432\u0438\u0442 checkNeedSync \u043f\u0435\u0440\u0435\u0447\u0438\u0442\u044b\u0432\u0430\u0442\u044c \u0438\u0445 \u0438 \u0432\u044b\u0434\u0430\u0432\u0430\u0442\u044c \u043d\u043e\u0432\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u0438 fetchItems. \u0412 \u043f\u0440\u043e\u0442\u0438\u0432\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0431\u044b \u043f\u0435\u0440\u0435\u0434\u0430\u043b\u0438\u0441\u044c \u043c\u0438\u043d\u0438\u043c\u0443\u043c \u0434\u0432\u0430\u0436\u0434\u044b &#8212; \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0442\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043d\u044b \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u0430, \u0430 \u043f\u043e\u0442\u043e\u043c \u043e\u043d\u0438 \u0436\u0435, \u043d\u043e \u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043d\u043d\u044b\u0435 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e \u043f\u0440\u0438 \u0434\u0443\u0431\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438. \u0415\u0441\u043b\u0438 \u0431\u044b \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u043e \u0441\u043d\u043e\u0432\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a, \u0442\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0437\u0430\u0446\u0438\u043a\u043b\u0438\u043b\u0430\u0441\u044c \u0438 \u043f\u043e\u0432\u0435\u0441\u0438\u043b\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435. <\/p>\n<h4>\u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442 \u0434\u043b\u044f \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a<\/h4>\n<p>\u0414\u0430\u043b\u044c\u0448\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 androidX \u0434\u043b\u044f \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u0438 \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u0438. \u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 AndroidX Preference \u0440\u0430\u0441\u043f\u043e\u043b\u0430\u0433\u0430\u0435\u0442\u0441\u044f <a href=\"https:\/\/developer.android.com\/guide\/topics\/ui\/settings\" rel=\"noopener noreferrer nofollow\">\u0432 \u0440\u0430\u0437\u0434\u0435\u043b\u0435 User interface\/Settings<\/a>, \u0432\u0438\u0434\u0438\u043c\u043e \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0441\u043c\u0435\u0448\u0438\u0432\u0430\u0442\u044c \u0441 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u043e\u0439 SharedPreferences (\u043f\u0440\u0438 \u044d\u0442\u043e\u043c Google \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u0434\u0440\u0443\u0433\u0443\u044e \u043f\u0443\u0442\u0430\u043d\u0438\u0446\u0443 \u043c\u0435\u0436\u0434\u0443 \u043d\u0430\u0448\u0438\u043c DataStore \u0438 \u0441\u0432\u043e\u0438\u043c \u043e\u0447\u0435\u0440\u0435\u0434\u043d\u044b\u043c \u0441\u043b\u043e\u0435\u043c \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0446\u0438\u0438 PreferenceDataStore). <\/p>\n<details class=\"spoiler\">\n<summary>\u0424\u0430\u0439\u043b \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0438 preferences.xml<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"xml\">&lt;?xml version=\"1.0\" encoding=\"utf-8\"?&gt; &lt;PreferenceScreen xmlns:app=\"http:\/\/schemas.android.com\/apk\/res-auto\"     xmlns:android=\"http:\/\/schemas.android.com\/apk\/res\/android\"&gt;      &lt;PreferenceCategory android:title=\"@string\/experimentalTitle\"&gt;          &lt;SwitchPreferenceCompat             android:defaultValue=\"false\"             android:key=\"translate_to_ru\"             android:summaryOff=\"@string\/aiTranslateOffText\"             android:summaryOn=\"@string\/aiTranslateOnText\"             android:title=\"@string\/aiTranslateTitle\" \/&gt;     &lt;\/PreferenceCategory&gt;     &lt;PreferenceCategory android:title=\"@string\/synchronizeTitle\"&gt;          &lt;SeekBarPreference             android:defaultValue=\"2\"             android:key=\"refresh_interval\"             android:title=\"@string\/refreshIntervalTitle\"             android:summary=\"@string\/refreshSummary\"             android:max=\"24\"             app:min=\"0\"             app:seekBarIncrement=\"1\"             app:showSeekBarValue=\"true\" \/&gt;     &lt;\/PreferenceCategory&gt; &lt;\/PreferenceScreen&gt;<\/code><\/pre>\n<\/div>\n<\/details>\n<p>\u0412\u043d\u0435\u0448\u043d\u0438\u0439 \u0432\u0438\u0434 \u044d\u043a\u0440\u0430\u043d\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u0441 \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0439 \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u043e\u0439:<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/6de\/7a2\/f67\/6de7a2f67b6bd267a6e24f7fa0a086be.png\" width=\"231\" height=\"500\"><figcaption><\/figcaption><\/figure>\n<p>\u0421\u043e\u0437\u0434\u0430\u0432\u0430\u0435\u043c\u044b\u0439 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u044d\u043a\u0440\u0430\u043d \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 material design \u0441\u0442\u0438\u043b\u044c \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u0441\u0432\u043e\u0438\u0445 \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u044b\u0445 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432, \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0435 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 <a href=\"https:\/\/developer.android.com\/guide\/topics\/ui\/settings\/components-and-attributes\" rel=\"noopener noreferrer nofollow\">\u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u043c \u0440\u0430\u0437\u0434\u0435\u043b\u0435 guides<\/a>. \u041e\u0442\u043c\u0435\u0447\u0443, \u0447\u0442\u043e \u0432\u0441\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u043c\u043e\u0433\u0443\u0442 \u0438\u043c\u0435\u0442\u044c \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u043d\u044b\u0435 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b \u0432\u0440\u043e\u0434\u0435 summaryOff\/summaryOn &#8212; \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0442\u0435\u043a\u0441\u0442 \u043f\u043e\u0434 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u043c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438, \u043c\u0435\u043d\u044f\u044e\u0449\u0438\u0439\u0441\u044f \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0435\u0451 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f, \u0447\u0442\u043e \u0445\u043e\u0440\u043e\u0448\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u0434\u043b\u044f \u0447\u0435\u043a\u0431\u043e\u043a\u0441\u043e\u0432 \u0438 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u0442\u0435\u043b\u0435\u0439. \u0422\u0430\u043a\u0436\u0435 \u0438\u043c\u0435\u0435\u0442\u0441\u044f default value. \u041e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u043c \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u043e\u043c \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f key, \u0438\u043c\u0435\u043d\u043d\u043e \u043f\u043e \u0435\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044e \u043d\u0443\u0436\u043d\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0432 \u043a\u043e\u0434\u0435.<\/p>\n<p>\u0421 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 Navigation \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442 \u0441 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u043c\u0438 \u043b\u0435\u0433\u043a\u043e \u0432\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0432 \u043d\u0443\u0436\u043d\u043e\u0435 \u043c\u0435\u0441\u0442\u043e. \u042f, \u043a \u043f\u0440\u0438\u043c\u0435\u0440\u0443, \u0432\u044b\u0437\u044b\u0432\u0430\u044e \u0435\u0433\u043e \u0438\u0437 \u043c\u0435\u043d\u044e \u0433\u043b\u0430\u0432\u043d\u043e\u0433\u043e \u044d\u043a\u0440\u0430\u043d\u0430:<\/p>\n<pre><code class=\"kotlin\">override fun onOptionsItemSelected(item: MenuItem): Boolean {         when (item.itemId) {             ...             R.id.preferences -&gt; findNavController().navigate(MainFragmentDirections.actionShowPreferences())         }         return super.onOptionsItemSelected(item)     }<\/code><\/pre>\n<p>\u0410 \u0447\u0442\u043e\u0431\u044b \u0438\u043c\u0435\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0438\u0437 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u0440\u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0442\u0435 (\u043a \u043f\u0440\u0438\u043c\u0435\u0440\u0443, \u0444\u043b\u0430\u0433 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0438\u0437\u043c\u0435\u043d\u0438\u043b\u0438\u0441\u044c), \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c\u044e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 Navigation \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0447\u0435\u0440\u0435\u0437 SavedStateHandle, \u0434\u043b\u044f \u0447\u0435\u0433\u043e \u0432 \u043c\u0435\u0442\u043e\u0434\u0435 onCreateView \u0433\u043b\u0430\u0432\u043d\u043e\u0433\u043e \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u0430 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 observer \u0434\u043b\u044f BackStack&#8217;\u0430:<\/p>\n<pre><code class=\"kotlin\">findNavController().currentBackStackEntry?.let {             it.savedStateHandle.getLiveData&lt;Boolean&gt;(\"preferences_changed\").observe(viewLifecycleOwner) { isChanged -&gt;                 if (isChanged) {                     viewModel.armRefresh()                     it.savedStateHandle.remove&lt;Boolean&gt;(\"preferences_changed\")                 }             }         }<\/code><\/pre>\n<p>\u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u043e\u0441\u043b\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u0442\u043e\u0433\u043e \u0436\u0435 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u0430 \u043d\u0435 \u0432\u044b\u0437\u0432\u0430\u043b\u0441\u044f \u0441\u043d\u043e\u0432\u0430 \u044d\u0442\u043e\u0442 \u043a\u043e\u043b\u043b\u0431\u044d\u043a, \u0442.\u043a. \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u044d\u0442\u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u044e\u0442\u0441\u044f \u043a\u0430\u043a LiveData, \u0430 \u0437\u043d\u0430\u0447\u0438\u0442, \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c\u0441\u044f \u043a\u0430\u0436\u0434\u043e\u043c\u0443 \u043d\u043e\u0432\u043e\u043c\u0443 \u043f\u043e\u0434\u043f\u0438\u0441\u0447\u0438\u043a\u0443. <\/p>\n<p>\u0412 \u0441\u0430\u043c\u043e\u043c \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u043d\u0435 \u0437\u0430\u0431\u0443\u0434\u0435\u043c \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043a\u043e\u0434, \u0438\u0437\u043c\u0435\u043d\u044f\u044e\u0449\u0438\u0439 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u0432 DataStore \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u044e\u0449\u0438\u0439 \u0444\u043b\u0430\u0433 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 savedStateHandle \u0434\u043b\u044f \u0432\u044b\u0437\u044b\u0432\u0430\u044e\u0449\u0435\u0433\u043e \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u0430. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u043c\u0435\u0442\u043e\u0434 findPreference, \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u044b\u0439 findViewById, \u0438 \u043a\u043e\u043b\u043b\u0431\u044d\u043a setOnPreferenceChangeListener:<\/p>\n<pre><code class=\"kotlin\">override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {         setPreferencesFromResource(R.xml.preferences, rootKey)         requireActivity().title = getString(R.string.preferencesTitle)          settings.saved.collectOnFragment(this) {              findPreference&lt;SwitchPreferenceCompat&gt;(\"translate_to_ru\")?.apply {                 isChecked = it.translateToRu                 setOnPreferenceChangeListener { _, value -&gt;                     lifecycleScope.launch { settings.translateToRu(value as Boolean) }                     findNavController().previousBackStackEntry?.let {                         it.savedStateHandle[\"preferences_changed\"] = true                     }                     true                 }             }              findPreference&lt;SeekBarPreference&gt;(\"refresh_interval\")?.apply {                 value = it.refreshInterval \/ HOUR_TO_MILLIS                 setOnPreferenceChangeListener { _, value -&gt;                     lifecycleScope.launch { settings.refreshInterval(value as Int) }                     findNavController().previousBackStackEntry?.let {                         it.savedStateHandle[\"preferences_changed\"] = true                     }                     true                 }             }         }     }<\/code><\/pre>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f collectOnFragment \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u043e\u0447\u0438\u0442\u0430\u0435\u043c\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 flow<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"kotlin\">fun &lt;T&gt; Flow&lt;T&gt;.collectOnFragment(     fragment: Fragment,     state: Lifecycle.State = Lifecycle.State.RESUMED,     block: (T) -&gt; Unit ) {     fragment.lifecycleScope.launch {         flowWithLifecycle(fragment.lifecycle, state)             .collect {                 block(it)             }     } }<\/code><\/pre>\n<\/div>\n<\/details>\n<p>\u041e\u0442\u043c\u0435\u0447\u0443, \u0447\u0442\u043e \u043a\u043e\u043b\u043b\u0431\u044d\u043a setOnPreferenceChangeListener \u043d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0442\u0438\u043f\u043e\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u044b\u043c \u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442 value \u0441 \u0442\u0438\u043f\u043e\u043c Any, \u0442\u0430\u043a \u0447\u0442\u043e \u043d\u0435\u0438\u0437\u0431\u0435\u0436\u043d\u044b \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u0442\u0438\u043f\u043e\u0432 \u043d\u0430\u043f\u043e\u0434\u043e\u0431\u0438\u0435 value as Boolean \u0438\u043b\u0438 value as Int, \u043e \u0447\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u043f\u043e\u043c\u043d\u0438\u0442\u044c \u0438 \u0431\u044b\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u043c.<\/p>\n<p>\u041d\u0430 \u044d\u0442\u043e\u043c \u0432\u0441\u0435. \u041c\u044b \u0432\u044b\u044f\u0441\u043d\u0438\u043b\u0438, \u043a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0432 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u043c \u0441\u0442\u0438\u043b\u0435 \u043d\u0430 Kotlin \u0441 DataStore, \u0430 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u0430\u043a \u0437\u0430\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0442\u044c \u0447\u0442\u0435\u043d\u0438\u0435 \u0438 \u0437\u0430\u043f\u0438\u0441\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u0432 runBlocking \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u0447\u0442\u043e \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e\u0442 \u043f\u0438\u0441\u0430\u0442\u0435\u043b\u0438 <em>4-min-to-read-<\/em>\u0437\u0430\u043c\u0435\u0442\u043e\u043a \u043d\u0430 \u043c\u0435\u0434\u0438\u0443\u043c\u0435 (\u0438 \u0434\u0430\u0436\u0435 \u0441\u0430\u043c Google, \u0445\u043e\u0442\u044c \u0438 \u0432\u044b\u0434\u0435\u043b\u044f\u0435\u0442 \u044d\u0442\u043e \u043c\u0435\u0441\u0442\u043e \u043a\u0440\u0430\u0441\u043d\u044b\u043c \u043f\u0440\u0435\u0434\u0443\u043f\u0440\u0435\u0436\u0434\u0430\u044e\u0449\u0438\u043c \u0446\u0432\u0435\u0442\u043e\u043c). <\/p>\n<p>\u0422\u0430\u043a\u0436\u0435 \u0443\u0431\u0435\u0434\u0438\u043b\u0438\u0441\u044c, \u043d\u0430\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043b\u0435\u0433\u043a\u043e \u0438 \u0431\u044b\u0441\u0442\u0440\u043e Jetpack-\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0442 \u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u043c\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0432 \u0440\u0430\u0431\u043e\u0447\u0438\u0439 ui c \u0433\u043e\u0442\u043e\u0432\u044b\u043c material design \u0441\u0442\u0438\u043b\u0435\u043c. <\/p>\n<p>\u0412 \u0443\u0447\u0430\u0441\u0442\u043a\u0430\u0445 \u043a\u043e\u0434\u0430 \u0435\u0441\u0442\u044c \u043c\u0435\u0441\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u044f \u043d\u0435 \u0441\u0442\u0430\u043b \u043e\u0431\u044a\u044f\u0441\u043d\u044f\u0442\u044c \u0438\u043b\u0438 \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442\u044c \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0432 \u0441\u0438\u043b\u0443 \u043d\u0435\u0432\u0430\u0436\u043d\u043e\u0441\u0442\u0438 \u0438\u043b\u0438 \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u043e\u0441\u0442\u0438 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u044b HOUR_TO_MILLIS), \u0435\u0441\u043b\u0438 \u0436\u0435 \u0443 \u0432\u0430\u0441 \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0441\u044f \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442 \u043f\u043e \u043c\u043e\u0435\u043c\u0443 \u0440\u0435\u0446\u0435\u043f\u0442\u0443, \u043f\u0438\u0448\u0438\u0442\u0435 \u0432 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u0445, \u044f \u043f\u043e\u0441\u0442\u0430\u0440\u0430\u044e\u0441\u044c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0432\u0441\u0435 \u043d\u0435\u044f\u0441\u043d\u044b\u0435 \u043c\u0435\u0441\u0442\u0430. \u041e\u0442\u043c\u0435\u0447\u0443, \u0447\u0442\u043e \u0432\u0441\u0435 \u0443\u0447\u0430\u0441\u0442\u043a\u0438 \u043a\u043e\u0434\u0430 \u044f \u0432\u0437\u044f\u043b \u0438\u0437 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0440\u0430\u0431\u043e\u0447\u0435\u0433\u043e \u0438 \u043f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u0442\u0430\u043a \u0447\u0442\u043e \u0437\u0430 \u0435\u0433\u043e \u0440\u0430\u0431\u043e\u0442\u043e\u0441\u043f\u043e\u0441\u043e\u0431\u043d\u043e\u0441\u0442\u044c \u043d\u0435 \u0441\u0442\u043e\u0438\u0442 \u0432\u043e\u043b\u043d\u043e\u0432\u0430\u0442\u044c\u0441\u044f.<\/p>\n<p>\u0421\u043f\u0430\u0441\u0438\u0431\u043e \u0437\u0430 \u0447\u0442\u0435\u043d\u0438\u0435.<\/p>\n<\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/post\/560272\/\"> https:\/\/habr.com\/ru\/post\/560272\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"\n<div class=\"post__text post__text_v2\" id=\"post-content-body\">\n<p>\u0421 \u0442\u0435\u0445 \u043f\u043e\u0440, \u043a\u0430\u043a \u043a\u043e\u043c\u0430\u043d\u0434\u0430 Google AndroidX \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u043b\u0430 \u043d\u0430 \u0437\u0430\u043c\u0435\u043d\u0443 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 SharedPreferences <a href=\"https:\/\/developer.android.com\/topic\/libraries\/architecture\/datastore\" rel=\"noopener noreferrer nofollow\">\u043d\u043e\u0432\u0443\u044e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 DataStore<\/a>, \u043f\u0440\u043e\u0448\u0435\u043b \u043f\u043e\u0447\u0442\u0438 \u0433\u043e\u0434, \u043e\u0434\u043d\u0430\u043a\u043e \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u0438\u0437\u0430\u0446\u0438\u044f \u043d\u043e\u0432\u043e\u0439 \u043b\u0438\u0431\u044b \u044f\u0432\u043d\u043e \u043d\u0435 \u0441\u0442\u043e\u0438\u0442 \u0432 \u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0445 \u0437\u0430\u0434\u0430\u0447\u0430\u0445. \u0418\u043d\u0430\u0447\u0435 \u044f \u043d\u0435 \u043c\u043e\u0433\u0443 \u043e\u0431\u044a\u044f\u0441\u043d\u0438\u0442\u044c 1) \u043d\u0435\u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u044b\u0439 \u0433\u0430\u0439\u0434, \u0441\u043b\u0435\u0434\u0443\u044f \u043b\u0438\u0448\u044c \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443, \u0443 \u0432\u0430\u0441 \u0432\u043e\u043e\u0431\u0449\u0435 \u043d\u0435 \u0441\u043e\u0431\u0435\u0440\u0435\u0442\u0441\u044f \u043f\u0440\u043e\u0435\u043a\u0442 \u0438\u0437-\u0437\u0430 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u044f \u0432\u0441\u0435\u0445 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0445 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u0438 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 build-\u0437\u0430\u0434\u0430\u0447 \u0434\u043b\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0441\u0431\u043e\u0440\u043a\u0438, \u0438 2) \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435 \u043d\u0435 hello-world \u043f\u043e\u0434\u043e\u0431\u043d\u044b\u0445 \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u0432 \u0432 CodeLabs, \u043a\u0440\u043e\u043c\u0435 \u043e\u0434\u043d\u043e\u0433\u043e, \u0438 \u0442\u043e, \u0437\u0430\u0442\u043e\u0447\u0435\u043d\u043d\u043e\u0433\u043e \u043d\u0435 \u043f\u043e\u0434 \u043f\u0440\u0438\u043c\u0435\u0440 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0441 \u043d\u0443\u043b\u044f, \u0430 \u043f\u043e\u0434 <a href=\"https:\/\/codelabs.developers.google.com\/codelabs\/android-proto-datastore\" rel=\"noopener noreferrer nofollow\">\u043c\u0438\u0433\u0440\u0430\u0446\u0438\u044e \u0441 SharedPreferences \u043d\u0430 Preferences DataStore<\/a>. \u0410\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e \u0432\u0441\u0435 \u0441\u0442\u0430\u0442\u044c\u0438 \u043d\u0430 Medium \u0431\u0443\u043a\u0432\u0430\u043b\u044c\u043d\u043e \u0438\u043b\u0438 \u0434\u0440\u0443\u0433\u0438\u043c\u0438 \u0441\u043b\u043e\u0432\u0430\u043c\u0438 \u043f\u043e\u0432\u0442\u043e\u0440\u044f\u044e\u0442 \u0432\u0441\u0435 \u0442\u043e \u0436\u0435, \u0447\u0442\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043e \u0432 \u0433\u0430\u0439\u0434\u0435 Google, \u043b\u0438\u0431\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 \u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0435 \u043f\u043e\u0434\u0445\u043e\u0434\u044b \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 DataStore, \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044f \u0437\u0430\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0442\u044c \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 io-\u043a\u043e\u0434 \u0432 runBlocking \u043f\u0440\u044f\u043c\u043e \u043d\u0430 ui-\u043f\u043e\u0442\u043e\u043a\u0435.<\/p>\n<p>\u0410 \u0435\u0449\u0435 \u043d\u0435\u043f\u043b\u043e\u0445\u043e \u0431\u044b \u0441\u043e\u0435\u0434\u0438\u043d\u0438\u0442\u044c &#171;\u0442\u044b\u043b&#187; \u0441 &#171;\u0444\u0440\u043e\u043d\u0442\u043e\u043c&#187;, \u0442\u0430\u043a \u0441\u043a\u0430\u0437\u0430\u0442\u044c: \u0443 Google \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 <a href=\"https:\/\/developer.android.com\/guide\/topics\/ui\/settings\" rel=\"noopener noreferrer nofollow\">AndroidX Preferences<\/a> \u0438\u0437 \u043e\u0431\u043e\u0439\u043c\u044b Jetpack, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0432 \u0434\u0432\u0430 \u043a\u043b\u0438\u043a\u0430 \u043d\u0430\u043a\u0438\u0434\u0430\u0442\u044c \u0433\u043e\u0442\u043e\u0432\u044b\u0439 material-design \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u043c\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438 \u0438\u0437\u043b\u044e\u0431\u043b\u0435\u043d\u043d\u044b\u043c \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u043c \u043a\u043e\u0434\u043e\u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u043e\u0441\u0432\u043e\u0431\u043e\u0434\u0438\u0442\u044c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u043e\u0442 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f boilerplate. \u041e\u0434\u043d\u0430\u043a\u043e \u044d\u0442\u0430 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430 \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0443\u0441\u0442\u0430\u0440\u0435\u0432\u0448\u0438\u0435 \u043d\u044b\u043d\u0447\u0435 SharedPreferences, \u0430 \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0433\u0430\u0439\u0434\u0430 \u043f\u043e \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044e \u0441 DataStore \u043d\u0435\u0442. \u0412 \u044d\u0442\u043e\u0439 \u0437\u0430\u043c\u0435\u0442\u043a\u0435 \u044f \u0445\u043e\u0442\u0435\u043b \u0431\u044b \u0441\u0432\u043e\u0438\u043c \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u043c \u0443\u0441\u0442\u0440\u0430\u043d\u0438\u0442\u044c \u0434\u0432\u0430 \u043e\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0445 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043a\u0430.<\/p>\n<h4>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043a\u0430\u0440\u043a\u0430\u0441\u0430 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 DataStore<\/h4>\n<p>\u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 DataStore \u0434\u0435\u043b\u0438\u0442\u0441\u044f \u043d\u0430 \u0434\u0432\u0435 \u0447\u0430\u0441\u0442\u0438: \u0430\u043d\u0430\u043b\u043e\u0433 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0439 \u043f\u043e\u0434 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c Preferences DataStore, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0445\u0440\u0430\u043d\u0438\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u0432 \u043f\u0430\u0440\u0430\u0445 \u043a\u043b\u044e\u0447-\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0438 \u043d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0442\u0438\u043f\u043e\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0439, \u0438 \u0432\u0442\u043e\u0440\u0430\u044f, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0445\u0440\u0430\u043d\u0438\u0442 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0432 \u0444\u0430\u0439\u043b\u0435 \u0444\u043e\u0440\u043c\u0430\u0442\u0430 Protocol buffers \u0438 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0442\u0438\u043f\u043e\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0439. \u041e\u043d\u0430 \u0431\u043e\u043b\u0435\u0435 \u0433\u0438\u0431\u043a\u0430\u044f \u0438 \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u0430\u044f, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u0432\u044b\u0431\u0440\u0430\u043b \u0435\u0435 \u0434\u043b\u044f \u0441\u0432\u043e\u0438\u0445 \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u043e\u0432. <\/p>\n<p>\u0414\u043b\u044f \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0441\u0445\u0435\u043c\u044b \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u043d\u0443\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0444\u0430\u0439\u043b \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435. \u0412\u043e-\u043f\u0435\u0440\u0432\u044b\u0445, \u043d\u0430\u0434\u043e \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043f\u0440\u043e\u0432\u043e\u0434\u043d\u0438\u043a \u0441\u0442\u0443\u0434\u0438\u0438 \u0438\u043b\u0438 \u0438\u0434\u0435\u0438 \u0432 \u0440\u0435\u0436\u0438\u043c Project, \u0447\u0442\u043e\u0431\u044b \u0431\u044b\u043b\u0430 \u0432\u0438\u0434\u043d\u0430 \u0432\u0441\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0430\u043f\u043e\u043a, \u0438 \u043f\u043e\u0442\u043e\u043c \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0432 \u043f\u0430\u043f\u043a\u0435 app\/src\/main\/proto\/ \u0444\u0430\u0439\u043b \u0441 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435\u043c <strong>*.proto<\/strong> (\u0430 \u043d\u0435 pb, \u043a\u0430\u043a \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u0442 Google &#8212; \u0441 \u043d\u0438\u043c \u043d\u0438 \u043f\u043b\u0430\u0433\u0438\u043d \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441\u0430, \u0430\u0432\u0442\u043e\u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0438 \u0442.\u043f., \u043d\u0438 build-\u0437\u0430\u0434\u0430\u0447\u0430, \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u044e\u0449\u0430\u044f \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u043a\u043b\u0430\u0441\u0441, \u043d\u0435 \u0441\u0442\u0430\u043d\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c).<\/p>\n<p>\u0421\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441 Protocol buffer <a href=\"https:\/\/developers.google.com\/protocol-buffers\/docs\/proto3\" rel=\"noopener noreferrer nofollow\">\u043e\u0447\u0435\u043d\u044c \u0445\u043e\u0440\u043e\u0448\u043e \u043e\u043f\u0438\u0441\u0430\u043d \u0441\u0430\u043c\u0438\u043c Google<\/a>, \u043d\u0435 \u0438\u043c\u0435\u0435\u0442 \u0441\u043c\u044b\u0441\u043b\u0430 \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c. \u041f\u0440\u0438\u0432\u0435\u0434\u0443 \u0442\u0435\u043a\u0441\u0442 \u0444\u0430\u0439\u043b\u0430, \u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u0431\u0443\u0434\u0443 \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435:<\/p>\n<pre><code>syntax = \"proto3\";  option java_package = \"\u043f\u043e\u043b\u043d\u043e\u0435.\u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435.\u0432\u0430\u0448\u0435\u0433\u043e.\u043f\u0430\u043a\u0435\u0442\u0430\"; option java_multiple_files = true;  message ProtoSettings {   bool translate_to_ru = 1;   map&lt;string, int64&gt; last_sync = 2;   int32 refresh_interval = 3; }<\/code><\/pre>\n<p>\u0412 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u0445 \u0431\u0443\u0434\u0443\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u044c\u0441\u044f \u0431\u0443\u043b\u0435\u0432\u044b\u0439 \u0444\u043b\u0430\u0433 \u0434\u043b\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0430 \u0442\u0435\u043a\u0441\u0442\u0430 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438, \u0446\u0435\u043b\u043e\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435, \u0437\u0430\u0434\u0430\u044e\u0449\u0435\u0435 \u043f\u0435\u0440\u0438\u043e\u0434 \u0434\u043b\u044f \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c, \u0438 \u0441\u043b\u043e\u0432\u0430\u0440\u044c \u0441 \u043a\u043b\u044e\u0447\u043e\u043c-\u0441\u0442\u0440\u043e\u043a\u043e\u0439 \u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c-long Kotlin, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c\u0441\u044f unix-\u0432\u0440\u0435\u043c\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0439 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 (\u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u0435\u043b\u044f\u0442c\u044f \u043d\u0430 data \u043a\u043b\u0430\u0441\u0441\u044b, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432 \u043a\u043b\u044e\u0447\u0435 \u043c\u043e\u0436\u043d\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c simple name \u044d\u0442\u043e\u0433\u043e \u043a\u043b\u0430\u0441\u0441\u0430).<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0443\u043a\u0430\u0436\u0435\u043c \u0432\u0441\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0438 \u0437\u0430\u0434\u0430\u0447\u0438 \u0434\u043b\u044f build.gradle-\u0444\u0430\u0439\u043b\u0430 \u043c\u043e\u0434\u0443\u043b\u044f:<\/p>\n<pre><code>plugins {     ...     id \"com.google.protobuf\" version \"0.8.12\" } ... dependencies { \t  ...     \/\/DataStore     implementation \"androidx.datastore:datastore:1.0.0-beta01\"     implementation \"com.google.protobuf:protobuf-javalite:3.11.0\"     implementation \"androidx.preference:preference-ktx:1.1.1\" }  protobuf {     protoc {         artifact = \"com.google.protobuf:protoc:3.11.0\"     }      generateProtoTasks {         all().each { task -&gt;             task.builtins {                 java {                     option 'lite'                 }             }         }     } } <\/code><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u0438\u0445 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f proto-\u0444\u0430\u0439\u043b\u0430 \u0432 \u043d\u0443\u0436\u043d\u043e\u043c \u043c\u0435\u0441\u0442\u0435 \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u043f\u0435\u0440\u0435\u0441\u043e\u0431\u0440\u0430\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442, \u0447\u0442\u043e\u0431\u044b \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043b\u0441\u044f java \u043a\u043b\u0430\u0441\u0441 \u0434\u043b\u044f DataStore \u043f\u043e \u0441\u0445\u0435\u043c\u0435 \u0438\u0437 proto. <\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0441\u043a\u0430\u0436\u0443 \u043e\u0431 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0438 \u0432\u0430\u0436\u043d\u043e\u0439 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438 DataStore: \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 \u0444\u043e\u043d\u043e\u0432\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u0434\u043b\u044f \u0437\u0430\u043f\u0438\u0441\u0438\/\u0447\u0442\u0435\u043d\u0438\u044f \u0438\u0437 \u0444\u0430\u0439\u043b\u043e\u0432\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b, \u0430 \u0441\u0430\u043c\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043f\u043e\u0441\u043b\u0435 \u0447\u0442\u0435\u043d\u0438\u044f \u0438\u0437 \u0444\u0430\u0439\u043b\u0430 \u0432\u044b\u0434\u0430\u044e\u0442\u0441\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Flow. \u0417\u0430\u043f\u0438\u0441\u044c \u0436\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 set-\u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0438 \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u0430 builder. \u041e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u0441 Flow \u0437\u0430\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442 \u043e\u0447\u0435\u043d\u044c \u0441\u0438\u043b\u044c\u043d\u043e \u043c\u0435\u043d\u044f\u0442\u044c \u043f\u043e\u0434\u0445\u043e\u0434 \u043a \u0442\u0430\u043a\u043e\u0439 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0448\u0442\u0443\u043a\u0435, \u043a\u0430\u043a \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0432\u0435\u0434\u044c \u0438\u043d\u0430\u0447\u0435, \u043a\u0430\u043a \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0432\u044b\u0437\u043e\u0432\u0430 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0445 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u0432 collect &amp; Co \u0438\u0445 \u0442\u0435\u043f\u0435\u0440\u044c \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0448\u044c.<\/p>\n<blockquote>\n<p>\u0412\u0430\u0436\u043d\u043e! \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 deprecated-\u043c\u0435\u0442\u043e\u0434\u044b Flow toList \u0438\u043b\u0438 toSet, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043e\u043d\u0438 \u043f\u043e\u0432\u0435\u0441\u044f\u0442 \u0432\u0430\u0448 \u043c\u0435\u0442\u043e\u0434 \u043d\u0430\u0432\u0441\u0435\u0433\u0434\u0430 (<em>flow never completes, so this terminal operation never completes<\/em>). <\/p>\n<\/blockquote>\n<p>\u0414\u043b\u044f \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u0439 \u0440\u0430\u0431\u043e\u0442\u044b \u043d\u0443\u0436\u043d\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0435\u0449\u0435 \u043d\u0435\u043c\u043d\u043e\u0433\u043e boilerplate \u043a\u043e\u0434\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u043e\u043b\u0436\u0435\u043d \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u043a\u043b\u0430\u0441\u0441\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0435\u0441\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u0438\u043d \u0441\u043f\u043e\u0441\u043e\u0431, \u0438 \u043f\u043e\u0447\u0435\u043c\u0443 Google \u043d\u0435 \u0437\u0430\u0432\u0435\u0440\u043d\u0443\u043b \u0435\u0433\u043e \u0432 \u043a\u043e\u0434\u043e\u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044e, \u0443\u043c\u0430 \u043d\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0443: <\/p>\n<pre><code class=\"kotlin\">@Suppress(\"BlockingMethodInNonBlockingContext\") object SettingsSerializer : Serializer&lt;ProtoSettings&gt; {     override val defaultValue: ProtoSettings = ProtoSettings.getDefaultInstance()      override suspend fun readFrom(input: InputStream): ProtoSettings {         try {             return ProtoSettings.parseFrom(input)         } catch (exception: InvalidProtocolBufferException) {             throw CorruptionException(\"Cannot read proto.\", exception)         }     }      override suspend fun writeTo(t: ProtoSettings, output: OutputStream) = t.writeTo(output) }<\/code><\/pre>\n<p>\u042d\u0442\u043e\u0442 \u043e\u0431\u044a\u0435\u043a\u0442 Serializer \u0434\u043e\u043b\u0436\u0435\u043d \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c\u0441\u044f \u043a\u0430\u043a \u0441\u0438\u043d\u0433\u043b\u0442\u043e\u043d \u043f\u0440\u0438 \u043d\u0430\u0447\u0430\u043b\u0435 \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f (\u0434\u043e \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u043a \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u043c \u0432 \u043e\u0431\u0449\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435) \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<p>\u0418 \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u043a\u043b\u0430\u0441\u0441-\u043e\u0431\u0435\u0440\u0442\u043a\u0443 \u0434\u043b\u044f \u0447\u0442\u0435\u043d\u0438\u044f \u0438 \u0437\u0430\u043f\u0438\u0441\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430 \u043f\u0435\u0440\u0432\u044b\u0439 \u0432\u0437\u0433\u043b\u044f\u0434 \u0431\u0443\u0434\u0435\u0442 \u0438\u0437\u0431\u044b\u0442\u043e\u0447\u043d\u044b\u043c: \u0432\u043e-\u043f\u0435\u0440\u0432\u044b\u0445, \u043e\u043d \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u0437\u0430\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043c\u0435\u0442\u043e\u0434\u044b \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u0432 \u043d\u0443\u0436\u043d\u044b\u0435 \u0431\u0438\u043b\u0434\u0435\u0440\u044b, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u043f\u043b\u043e\u0434\u0438\u0442\u044c \u0438\u0445 \u043f\u043e \u0432\u0441\u0435\u043c\u0443 \u043f\u0440\u043e\u0435\u043a\u0442\u0443, \u0432\u043e-\u0432\u0442\u043e\u0440\u044b\u0445, \u0432 \u043a\u043b\u0430\u0441\u0441\u0435 \u043c\u043e\u0436\u043d\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0434\u0440\u0443\u0433\u0443\u044e \u0442\u0435\u043a\u0443\u0449\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e, \u0446\u0435\u043d\u043d\u0443\u044e \u043b\u0438\u0448\u044c \u043d\u0430 \u0432\u0440\u0435\u043c\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0438-\u043a\u043e\u043d\u0432\u0435\u0440\u0442\u043e\u0440\u044b, \u043d\u0443 \u0438 \u043f\u043b\u044e\u0441 \u044d\u0442\u043e\u0442 \u043a\u043b\u0430\u0441\u0441 \u0431\u0443\u0434\u0435\u0442 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Hilt \u043b\u0435\u0433\u043a\u043e \u0432\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438:<\/p>\n<pre><code class=\"kotlin\">class SettingsRepository @Inject constructor(val settings: DataStore&lt;ProtoSettings&gt;) {      val saved get() = settings.data.take(1)          suspend fun translateToRu(value: Boolean) = settings.updateData {         it.toBuilder().setTranslateToRu(value).build()     }      suspend fun saveLastSync(cls: String) = settings.updateData {         it.toBuilder().putLastSync(cls, System.currentTimeMillis()).build()     }      suspend fun refreshInterval(hours: Int) = settings.updateData {         it.toBuilder().setRefreshInterval(hours * HOUR_TO_MILLIS).build()     }      fun checkNeedSync(cls: String) = saved.map {         it.lastSyncMap[cls]?.run {             System.currentTimeMillis() - this &gt; saved.refreshInterval         } ?: true     } }  @Module @InstallIn(SingletonComponent::class) class SettingsModule {      @Provides     @Singleton     fun provideSettingsRepository(@ApplicationContext context: Context) = SettingsRepository(context.dataStore)      private val Context.dataStore: DataStore&lt;ProtoSettings&gt; by dataStore(         fileName = \"settings.proto\",         serializer = SettingsSerializer     ) }<\/code><\/pre>\n<p>\u0418\u0437 \u043a\u043e\u0434\u0430 \u0432\u0438\u0434\u043d\u043e, \u0447\u0442\u043e \u0441\u0430\u043c \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u043c \u044f \u0438\u043d\u043a\u0430\u043f\u0441\u0443\u043b\u0438\u0440\u043e\u0432\u0430\u043b \u0432 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u043c \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0435 saved, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0447\u0438\u0442\u0430\u0435\u0442 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0438\u0437 flow \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u0430 take(1). \u041f\u043e\u0441\u043b\u0435 \u0440\u0430\u0437\u043d\u044b\u0445 \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u043e\u0432 \u044d\u0442\u043e\u0442 \u0441\u043f\u043e\u0441\u043e\u0431 \u043c\u043d\u0435 \u043f\u043e\u043a\u0430\u0437\u0430\u043b\u0441\u044f \u0441\u0430\u043c\u044b\u043c \u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u043c \u0434\u043b\u044f \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u0438, \u043a\u043e\u0433\u0434\u0430 \u0432 \u043e\u0434\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0438 \u0447\u0438\u0442\u0430\u044e\u0442\u0441\u044f, \u0438 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0442\u0441\u044f. \u0415\u0441\u043b\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u043e collect, \u0442\u043e \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437, \u043a\u043e\u0433\u0434\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438, \u0441\u0442\u0430\u043d\u0435\u0442 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u044c emit \u043d\u043e\u0432\u043e\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0438 \u0437\u0430\u043d\u043e\u0432\u043e \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u044d\u0442\u0430 \u0436\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u044f. \u0415\u0441\u043b\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c first(), \u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0432\u0437\u044f\u0442\u043e \u043b\u0438\u0448\u044c \u043f\u0435\u0440\u0432\u043e\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u0438 flow \u0437\u0430\u043a\u0440\u043e\u0435\u0442\u0441\u044f. \u0415\u0441\u043b\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c last(), \u0442\u043e \u044d\u0442\u043e\u0442 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440 \u0431\u0443\u0434\u0435\u0442 \u0441\u043f\u043e\u0441\u043e\u0431\u0435\u043d \u043f\u043e\u0432\u0435\u0441\u0438\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e, \u0442.\u043a. \u043e\u043d \u043d\u0435 \u0437\u0430\u043a\u0440\u044b\u0432\u0430\u0435\u0442 flow.<\/p>\n<h4>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u0438\u0437 DataStore<\/h4>\n<p>\u041e\u043f\u0438\u0448\u0443 \u0432 \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u043c \u043f\u043b\u0430\u043d\u0435 \u044d\u0442\u0443 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044e. \u041f\u0440\u0435\u0434\u043f\u043e\u043b\u043e\u0436\u0438\u043c, \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435. \u0415\u0433\u043e \u0432 Kotlin \u043e\u0431\u0449\u0435\u043f\u0440\u0438\u043d\u044f\u0442\u043e \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u0430\u043b\u0433\u0435\u0431\u0440\u0430\u0438\u0447\u0435\u0441\u043a\u0438\u043c \u0442\u0438\u043f\u043e\u043c \u0434\u0430\u043d\u043d\u044b\u0445, \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u043c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e sealed \u043a\u043b\u0430\u0441\u0441\u0430:<\/p>\n<pre><code class=\"kotlin\">sealed class Result     data class Success&lt;out T&gt;(val data: T): Result()     data class Error(val msg: String, val error: ErrorType): Result()     object Loading : Result()<\/code><\/pre>\n<p>\u0412\u043e\u0442 \u043a\u0430\u043a \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0449\u0430\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043f\u0440\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u0434\u0430\u043d\u043d\u044b\u0445:<\/p>\n<pre><code class=\"kotlin\">fun &lt;T&gt; fetchItems(         itemsType: String,         remoteApiCallback: suspend () -&gt; Response&lt;ApiResponse&lt;T&gt;&gt;,         localApiCallback: suspend () -&gt; List&lt;T&gt;,         saveApiCallback: suspend (List&lt;T&gt;) -&gt; Unit,     ): Flow&lt;Result&gt; = settings.checkNeedSync(itemsType).transform { needSync -&gt;         var remoteFailed = true         emit(Loading)         localApiCallback().let { local -&gt;             if (needSync || local.isEmpty()) {                 if (networkHelper.isNetworkConnected()) {                     remoteApiCallback().apply {                         if (isSuccessful) body()?.docs?.let { remote -&gt;                             settings.saveLastSync(itemsType)                             remoteFailed = false                             emit(Success(remote))                             saveApiCallback(remote)                         }                         else emit(Error(errorBody().toString(), ErrorType.REMOTE_API_ERROR))                     }                 } else emit(Error(\"No internet connection!\", ErrorType.NO_INTERNET_CONNECTION))             }              if (remoteFailed)                 emit(if (local.isNotEmpty()) Success(local) else Error(\"No local saved data\", ErrorType.NO_SAVED_DATA))         }     }         .flowOn(Dispatchers.IO)         .catch { e -&gt;             ...         }<\/code><\/pre>\n<p>\u042d\u0442\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0432 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u0445 \u0441\u0442\u0440\u043e\u043a\u0443 \u0441 \u0442\u0438\u043f\u043e\u043c \u0434\u0430\u043d\u043d\u044b\u0445 (\u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043d\u0443\u0436\u043d\u0430 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0439 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u044d\u0442\u043e\u0433\u043e \u0442\u0438\u043f\u0430 \u0434\u0430\u043d\u043d\u044b\u0445) \u0438 \u0442\u0440\u0438 \u043a\u043e\u043b\u043b\u0431\u044d\u043a\u0430: \u0434\u043b\u044f \u0447\u0442\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u0430, \u0434\u043b\u044f \u0447\u0442\u0435\u043d\u0438\u044f \u0438\u0437 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043a\u044d\u0448\u0430 \u0438 \u0434\u043b\u044f \u0437\u0430\u043f\u0438\u0441\u0438 \u0432 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u043a\u044d\u0448. \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0441 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u043c \u0442\u0438\u043f\u043e\u043c \u0434\u0430\u043d\u043d\u044b\u0445 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a:<\/p>\n<pre><code>fun getSomething() = fetchItems&lt;Something&gt;(\"Something\", remoteApi::getSomething, localApi::getSomething, localApi::saveSomething) <\/code><\/pre>\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-324141","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/324141","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=324141"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/324141\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=324141"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=324141"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=324141"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}