рдХреЛрдЯрд▓рд┐рди рдкрд░ рдЖрдзреБрдирд┐рдХ Android рд╡рд┐рдХрд╛рд╕ред рднрд╛рдЧ реи

рдирдорд╕реНрдХрд╛рд░, рд╣реЗрдмреНрд░! рдореИрдВ рдЖрдкрдХреЗ рд▓рд┐рдП " рдореЙрдбрд░реНрди рдПрдВрдбреНрд░реЙрдЗрдб рдбреЗрд╡рд▓рдкрдореЗрдВрдЯ рд╡рд┐рдж рдХреЛрдЯрд▓рд┐рди (рдкрд╛рд░реНрдЯ 2) " рд▓реЗрдЦ рдХрд╛ рдЕрдиреБрд╡рд╛рдж рдореНрд▓рд╛рдбреЗрди рд░рдХреЛрдирдЬреИрдХ рдкреНрд░рд╕реНрддреБрдд рдХрд░рддрд╛ рд╣реВрдВред

рдиреЛрдЯред рдпрд╣ рд▓реЗрдЦ рдореНрд▓рд╛рдбреЗрди рд░рдХреЛрдирдЬреИрдХ рдХреЗ рд▓реЗрдЦреЛрдВ рдХреА рд╢реНрд░реГрдВрдЦрд▓рд╛ рдХрд╛ рдЕрдиреБрд╡рд╛рдж рд╣реИ, рд▓реЗрдЦ рддрд┐рдерд┐: 09/23/2017 ред GitHub ред рд╕реЗрдореНрдкрд░рдкреЗрд░рд┐рдЯрд╕ рдХреЗ рдкрд╣рд▓реЗ рднрд╛рдЧ рдХреЛ рдкрдврд╝рдирд╛ рд╢реБрд░реВ рдХрд░рддреЗ рд╣реБрдП, рдореБрдЭреЗ рдкрддрд╛ рдЪрд▓рд╛ рдХрд┐ рд╢реЗрд╖ рднрд╛рдЧ рдХрд╛ рдХрд┐рд╕реА рдХрд╛рд░рдг рд╕реЗ рдЕрдиреБрд╡рд╛рдж рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ред рдЗрд╕рд▓рд┐рдП, рдореИрдВ рдЖрдкрдХреЗ рдзреНрдпрд╛рди рдореЗрдВ рджреВрд╕рд░рд╛ рднрд╛рдЧ рд▓рд╛рддрд╛ рд╣реВрдВред рд▓реЗрдЦ рд╕реНрд╡реИрдЪреНрдЫрд┐рдХ рдирд┐рдХрд▓рд╛ред

рдЫрд╡рд┐

"рдПрдВрдбреНрд░реЙрдЗрдб рд╕реНрдЯреВрдбрд┐рдпреЛ 3.0 рдореЗрдВ рдПрдВрдбреНрд░реЙрдЗрдб рдХреЗ рд▓рд┐рдП рд╡рд┐рдХрд╛рд╕ рдореЗрдВ рдирдпрд╛ рд╕рдм рдХреБрдЫ рдХрд╡рд░ рдХрд░рдиреЗ рд╡рд╛рд▓рд╛ рдПрдХ рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдвреВрдВрдврдирд╛ рдмрд╣реБрдд рдореБрд╢реНрдХрд┐рд▓ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдореИрдВрдиреЗ рдЗрд╕реЗ рд▓рд┐рдЦрдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛ред"

рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ, рд╣рдо рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдХрд╛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд░реЗрдВрдЧреЗ:

  1. рдПрдВрдбреНрд░реЙрдЗрдб рд╕реНрдЯреВрдбрд┐рдпреЛ 3 рдмреАрдЯрд╛ 1 рдкрд╛рд░реНрдЯ 1
  2. рдХреЛрдЯрд▓рд┐рди рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рд▓реИрдВрдЧреНрд╡реЗрдЬ рдкрд╛рд░реНрдЯ 1
  3. рд╡рд┐рдХрд▓реНрдк 1 рдХрд╛ рдирд┐рд░реНрдорд╛рдг рдХрд░реЗрдВ
  4. рдмрд╛рдзрд╛ рдбрд╛рд▓рдирд╛
  5. рдбрд╛рдЯрд╛ рдмрд╛рдЗрдВрдбрд┐рдВрдЧ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рднрд╛рдЧ 1
  6. MVVM рдЖрд░реНрдХрд┐рдЯреЗрдХреНрдЪрд░ + рд░рд┐рдкреЛрдЬрд┐рдЯрд░реА + рдПрдВрдбреНрд░реЙрдЗрдб рдореИрдиреЗрдЬрд░ рд░реИрдкрд░реНрд╕ рдкреИрдЯрд░реНрди
  7. RxJava2 рдФрд░ рдпрд╣ рднрд╛рдЧ 3 рд╡рд╛рд╕реНрддреБрдХрд▓рд╛ рдореЗрдВ рд╣рдорд╛рд░реА рдорджрдж рдХреИрд╕реЗ рдХрд░рддрд╛ рд╣реИ
  8. рдбреИрдЧрд░ 2.11, рдирд┐рд░реНрднрд░рддрд╛ рдЗрдВрдЬреЗрдХреНрд╢рди рдХреНрдпрд╛ рд╣реИ, рдЖрдкрдХреЛ рдЗрд╕ рднрд╛рдЧ 4 рдХрд╛ рдЙрдкрдпреЛрдЧ рдХреНрдпреЛрдВ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП
  9. рд░реЗрдЯреНрд░реЛрдлрд┐рдЯ (рдЖрд░рдПрдХреНрд╕ рдЬрд╛рд╡рд╛ 2 рдХреЗ рд╕рд╛рде)
  10. рдХрдорд░рд╛ (рдЖрд░рдПрдХреНрд╕ рдЬрд╛рд╡рд╛ 2 рдХреЗ рд╕рд╛рде)

MVVM рдЖрд░реНрдХрд┐рдЯреЗрдХреНрдЪрд░ + рд░рд┐рдкреЛрдЬрд┐рдЯрд░реА + рдПрдВрдбреНрд░реЙрдЗрдб рдореИрдиреЗрдЬрд░ рд░реИрдкрд░реНрд╕ рдкреИрдЯрд░реНрди


Android рджреБрдирд┐рдпрд╛ рдореЗрдВ рдЖрд░реНрдХрд┐рдЯреЗрдХреНрдЪрд░ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХреБрдЫ рд╢рдмреНрдж


рдХрд╛рдлреА рд╕рдордп рд╕реЗ, рдПрдВрдбреНрд░реЙрдЗрдб рдбреЗрд╡рд▓рдкрд░реНрд╕ рдиреЗ рдЕрдкрдиреА рдкрд░рд┐рдпреЛрдЬрдирд╛рдУрдВ рдореЗрдВ рдХрд┐рд╕реА рднреА рд╡рд╛рд╕реНрддреБрдХрд▓рд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд┐рдпрд╛ рд╣реИред рдкрд┐рдЫрд▓реЗ рддреАрди рд╡рд░реНрд╖реЛрдВ рдореЗрдВ, рдПрдВрдбреНрд░реЙрдЗрдб рдбреЗрд╡рд▓рдкрд░реНрд╕ рдХреЗ рд╕рдореБрджрд╛рдп рдореЗрдВ рдЙрд╕рдХреЗ рдЖрд╕рдкрд╛рд╕ рдмрд╣реБрдд рдЕрдзрд┐рдХ рдкреНрд░рдЪрд╛рд░ рд╣реБрдЖ рд╣реИред рдЧреЙрдб рдПрдХреНрдЯрд┐рд╡рд┐рдЯреА рдХрд╛ рд╕рдордп рдмреАрдд рдЪреБрдХрд╛ рд╣реИ рдФрд░ Google рдиреЗ рд╡рд┐рднрд┐рдиреНрди рдЖрд░реНрдХрд┐рдЯреЗрдХреНрдЪрд░рд▓ рджреГрд╖реНрдЯрд┐рдХреЛрдгреЛрдВ рдкрд░ рдХрдИ рдЙрджрд╛рд╣рд░рдгреЛрдВ рдФрд░ рдирд┐рд░реНрджреЗрд╢реЛрдВ рдХреЗ рд╕рд╛рде Android рдЖрд░реНрдХрд┐рдЯреЗрдХреНрдЪрд░ рдмреНрд▓реВрдкреНрд░рд┐рдВрдЯ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдкреНрд░рдХрд╛рд╢рд┐рдд рдХреА рд╣реИ ред рдЕрдВрдд рдореЗрдВ, Google IO '17 рдкрд░, рдЙрдиреНрд╣реЛрдВрдиреЗ рдПрдВрдбреНрд░реЙрдЗрдб рдЖрд░реНрдХрд┐рдЯреЗрдХреНрдЪрд░ рдХрдВрдкреЛрдиреЗрдВрдЯреНрд╕ , рдХреНрд▓реАрдирд░реНрд╕ рдХреЛрдб рдмрдирд╛рдиреЗ рдФрд░ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ рдмреЗрд╣рддрд░ рдмрдирд╛рдиреЗ рдореЗрдВ рд╣рдорд╛рд░реА рдорджрдж рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдбрд┐рдЬрд╝рд╛рдЗрди рдХрд┐рдП рдЧрдП рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ рдХрд╛ рдПрдХ рд╕рдВрдЧреНрд░рд╣ рдкреЗрд╢ рдХрд┐рдпрд╛ред рдШрдЯрдХ рдХрд╣рддреЗ рд╣реИрдВ рдХрд┐ рдЖрдк рдЙрди рд╕рднреА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдпрд╛ рдЙрдирдореЗрдВ рд╕реЗ рд╕рд┐рд░реНрдл рдПрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рд╣рд╛рд▓рд╛рдВрдХрд┐, рдореИрдВрдиреЗ рдЙрди рд╕рднреА рдХреЛ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдЙрдкрдпреЛрдЧреА рдкрд╛рдпрд╛ред рдкрд╛рда рдореЗрдВ рдФрд░ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рднрд╛рдЧреЛрдВ рдореЗрдВ рд╣рдо рдЙрдирдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗред рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рдореИрдВ рдХреЛрдб рдореЗрдВ рд╕рдорд╕реНрдпрд╛ рдХреЛ рдкреНрд░рд╛рдкреНрдд рдХрд░реВрдВрдЧрд╛, рдФрд░ рдлрд┐рд░ рдореИрдВ рдЗрди рдШрдЯрдХреЛрдВ рдФрд░ рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд░рд┐рдлреНрд▓реЗрдХреНрдЯрд░ рдХрд░реВрдВрдЧрд╛ рдХрд┐ рд╡реЗ рдХреНрдпрд╛ рд╕рдорд╕реНрдпрд╛рдПрдБ рд╣рд▓ рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рд╣реИрдВред

рджреЛ рдореБрдЦреНрдп рд╡рд╛рд╕реНрддреБ рдкреИрдЯрд░реНрди рд╣реИрдВ рдЬреЛ GUI рдХреЛрдб рд╕рд╛рдЭрд╛ рдХрд░рддреЗ рд╣реИрдВ:

  • рдПрдорд╡реАрдкреА
  • MVVM

рдпрд╣ рдХрд╣рдирд╛ рдореБрд╢реНрдХрд┐рд▓ рд╣реИ рдХрд┐ рдХреМрди рдмреЗрд╣рддрд░ рд╣реИред рдЖрдкрдХреЛ рджреЛрдиреЛрдВ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдПред рдореИрдВ рдЬреАрд╡рди рдЪрдХреНрд░-рдЬрд╛рдЧрд░реВрдХ рдШрдЯрдХреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ MVVM рдкрд╕рдВрдж рдХрд░рддрд╛ рд╣реВрдВ рдФрд░ рдореИрдВ рдЗрд╕рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд▓рд┐рдЦреВрдВрдЧрд╛ред рдпрджрд┐ рдЖрдкрдиреЗ рдХрднреА рднреА рдПрдорд╡реАрдкреА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдирд╣реАрдВ рдХреА рд╣реИ, рддреЛ рдЗрд╕ рдмрд╛рд░реЗ рдореЗрдВ рдордзреНрдпрдо рдкрд░ рдХрдИ рдЕрдЪреНрдЫреЗ рд▓реЗрдЦ рд╣реИрдВред

MVVM рдкреИрдЯрд░реНрди рдХреНрдпрд╛ рд╣реИ?


MVVM рдПрдХ рдЖрд░реНрдХрд┐рдЯреЗрдХреНрдЪрд░рд▓ рдкреИрдЯрд░реНрди рд╣реИ рдЬреЛ рдореЙрдбрд▓-рд╡реНрдпреВ-рд╡реНрдпреВ-рдореЙрдореЗрд▓ рдХреЗ рд░реВрдк рдореЗрдВ рдлреИрд▓рддрд╛ рд╣реИред рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдирд╛рдо рдбреЗрд╡рд▓рдкрд░реНрд╕ рдХреЛ рднреНрд░рдорд┐рдд рдХрд░рддрд╛ рд╣реИред рдпрджрд┐ рдореИрдВ рдЙрдирдХреЗ рдирд╛рдо рдХреЗ рд╕рд╛рде рдЖрддрд╛ рдерд╛, рддреЛ рдореИрдВ рдЗрд╕реЗ View-ViewModel-Model рдХрд╣реВрдВрдЧрд╛, рдХреНрдпреЛрдВрдХрд┐ ViewModel рдмреАрдЪ рдореЗрдВ рд╣реИ, рд╡реНрдпреВ рдФрд░ рдореЙрдбрд▓ рдХреЛ рдЬреЛрдбрд╝рддрд╛ рд╣реИред

рджреГрд╢реНрдп рдЧрддрд┐рд╡рд┐рдзрд┐ , рдлрд╝реНрд░реИрдЧрдореЗрдВрдЯ рдпрд╛ рдХрд┐рд╕реА рдЕрдиреНрдп рдХрд╕реНрдЯрдо рджреГрд╢реНрдп ( Android рдХрд╕реНрдЯрдо рджреГрд╢реНрдп ) рдХреЗ рд▓рд┐рдП рдПрдХ рдЕрдореВрд░реНрддрддрд╛ рд╣реИред рдХреГрдкрдпрд╛ рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рдЗрд╕ рджреГрд╢реНрдп рдХреЛ Android рджреГрд╢реНрдп рдХреЗ рд╕рд╛рде рднреНрд░рдорд┐рдд рдирд╣реАрдВ рдХрд░рдирд╛ рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИред рджреГрд╢реНрдп рдЧреВрдВрдЧрд╛ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП, рд╣рдореЗрдВ рдЗрд╕рдХреЗ рд▓рд┐рдП рдХреЛрдИ рддрд░реНрдХ рдирд╣реАрдВ рд▓рд┐рдЦрдирд╛ рдЪрд╛рд╣рд┐рдПред рджреГрд╢реНрдп рдореЗрдВ рдбреЗрдЯрд╛ рдирд╣реАрдВ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред рдпрд╣ ViewModel рдЙрджрд╛рд╣рд░рдг рдФрд░ рд╕рднреА рдбреЗрдЯрд╛ рдЬрд┐рд╕реЗ рд╡реНрдпреВ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рд╡рд╣рд╛рдВ рд╕реЗ рдПрдХ рд╕рдВрджрд░реНрдн рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдПред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рд╡реНрдпреВ рдХреЛ рдЗрд╕ рдбреЗрдЯрд╛ рдХрд╛ рдирд┐рд░реАрдХреНрд╖рдг рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП рдФрд░ рдЬрдм рд╡реНрдпреВрдореЙрдбрд▓ рд╕реЗ рдбреЗрдЯрд╛ рдмрджрд▓рддрд╛ рд╣реИ рддреЛ рд▓реЗрдЖрдЙрдЯ рдХреЛ рдмрджрд▓рдирд╛ рдЪрд╛рд╣рд┐рдПред рд╕рдВрдХреНрд╖реЗрдк рдореЗрдВ, рджреЗрдЦреЗрдВ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реИ: рд╡рд┐рднрд┐рдиреНрди рдбреЗрдЯрд╛ рдФрд░ рд░рд╛рдЬреНрдпреЛрдВ рдХреЗ рд▓рд┐рдП рд▓реЗрдЖрдЙрдЯ рджреГрд╢реНрдпред

ViewModel рдбреЗрдЯрд╛ рдФрд░ рд▓реЙрдЬрд┐рдХ рд╡рд╛рд▓реЗ рд╡рд░реНрдЧ рдХреЗ рд▓рд┐рдП рдПрдХ рд╕рд╛рд░ рдирд╛рдо рд╣реИ, рдЬрдм рдпрд╣ рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП рдФрд░ рдЬрдм рджрд┐рдЦрд╛рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред ViewModel рд╡рд░реНрддрдорд╛рди рд╕реНрдерд┐рддрд┐ рдХреЛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рддрд╛ рд╣реИ ред ViewModel рдПрдХ рдпрд╛ рдПрдХ рд╕реЗ рдЕрдзрд┐рдХ рдореЙрдбрд▓ рдХреЗ рд▓рд┐рдВрдХ рдХреЛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рддрд╛ рд╣реИ рдФрд░ рдЙрдирд╕реЗ рд╕рднреА рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рддрд╛ рд╣реИред рдЙрд╕реЗ рдкрддрд╛ рдирд╣реАрдВ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдбреЗрдЯрд╛ рдХрд╣рд╛рдБ рд╕реЗ рдЖрдпрд╛, рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗ рдпрд╛ рд╕рд░реНрд╡рд░ рд╕реЗред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, ViewModel рдХреЛ View рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХреБрдЫ рднреА рдЬрд╛рдирдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, ViewModel рдХреЛ рдПрдВрдбреНрд░реЙрдЗрдб рдлреНрд░реЗрдорд╡рд░реНрдХ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХреБрдЫ рднреА рдирд╣реАрдВ рдкрддрд╛ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред

рдореЙрдбрд▓ рдЙрд╕ рдкрд░рдд рдХреЗ рд▓рд┐рдП рд╕рд╛рд░ рдирд╛рдо рд╣реИ рдЬреЛ ViewModel рдХреЗ рд▓рд┐рдП рдбреЗрдЯрд╛ рддреИрдпрд╛рд░ рдХрд░рддрд╛ рд╣реИред рдпрд╣ рд╡рд╣ рд╡рд░реНрдЧ рд╣реИ рдЬрд┐рд╕рдореЗрдВ рд╣рдо рд╕рд░реНрд╡рд░ рд╕реЗ рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВрдЧреЗ рдФрд░ рдЗрд╕реЗ рдХреИрд╢ рдХрд░реЗрдВрдЧреЗ, рдпрд╛ рдЗрд╕реЗ рд╕реНрдерд╛рдиреАрдп рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░реЗрдВрдЧреЗред рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рдпреЗ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛, рдХрд╛рд░, рд╕реНрдХреНрд╡рд╛рдпрд░, рдЕрдиреНрдп рдореЙрдбрд▓ рдХрдХреНрд╖рд╛рдУрдВ рдХреЗ рд╕рдорд╛рди рд╡рд░реНрдЧ рдирд╣реАрдВ рд╣реИрдВ рдЬреЛ рдХреЗрд╡рд▓ рдбреЗрдЯрд╛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рддреЗ рд╣реИрдВред рдПрдХ рдирд┐рдпрдо рдХреЗ рд░реВрдк рдореЗрдВ, рдпрд╣ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдЯреЗрдореНрдкрд▓реЗрдЯ рдХрд╛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╣реИ, рдЬрд┐рд╕реЗ рд╣рдо рдмрд╛рдж рдореЗрдВ рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВрдЧреЗред рдореЙрдбрд▓ рдХреЛ ViewModel рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХреБрдЫ рднреА рдкрддрд╛ рдирд╣реАрдВ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред

MVVM , рдпрджрд┐ рд╕рд╣реА рддрд░реАрдХреЗ рд╕реЗ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рддреЛ рдЖрдкрдХреЗ рдХреЛрдб рдХреЛ рддреЛрдбрд╝рдиреЗ рдФрд░ рдЗрд╕реЗ рдЕрдзрд┐рдХ рдкрд░реАрдХреНрд╖рдг рдпреЛрдЧреНрдп рдмрдирд╛рдиреЗ рдХрд╛ рдПрдХ рд╢рд╛рдирджрд╛рд░ рддрд░реАрдХрд╛ рд╣реИред рдпрд╣ рд╣рдореЗрдВ SOLID рд╕рд┐рджреНрдзрд╛рдВрддреЛрдВ рдХрд╛ рдкрд╛рд▓рди рдХрд░рдиреЗ рдореЗрдВ рдорджрдж рдХрд░рддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рд╣рдорд╛рд░рд╛ рдХреЛрдб рдмрдирд╛рдП рд░рдЦрдирд╛ рдЖрд╕рд╛рди рд╣реИред

рдХреЛрдб рдЙрджрд╛рд╣рд░рдг


рдЕрдм рдореИрдВ рдПрдХ рд╕рд░рд▓ рдЙрджрд╛рд╣рд░рдг рд▓рд┐рдЦреВрдВрдЧрд╛ рдХрд┐ рдпрд╣ рдХреИрд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред

рдЖрд░рдВрдн рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдЗрдП рдПрдХ рд╕рд░рд▓ рдореЙрдбрд▓ рдмрдирд╛рдПрдБ рдЬреЛ рдПрдХ рдкрдВрдХреНрддрд┐ рд▓реМрдЯрд╛рддрд╛ рд╣реИ:

RepoModel.kt
class RepoModel { fun refreshData() : String { return "Some new data" } } 


рдЖрдорддреМрд░ рдкрд░, рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рдПрдХ рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рдХреЙрд▓ рд╣реИ, рдЗрд╕рд▓рд┐рдП рд╣рдореЗрдВ рдЗрд╕рдХрд╛ рдЗрдВрддрдЬрд╛рд░ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдПред рдЗрд╕реЗ рдЕрдиреБрдХрд░рдг рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ рдХрдХреНрд╖рд╛ рдХреЛ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдореЗрдВ рдмрджрд▓ рджрд┐рдпрд╛:

RepoModel.kt
 class RepoModel { fun refreshData(onDataReadyCallback: OnDataReadyCallback) { Handler().postDelayed({ onDataReadyCallback.onDataReady("new data") },2000) } } interface OnDataReadyCallback { fun onDataReady(data : String) } 


рдореИрдВрдиреЗ OnDataReadyCallback рд╡рд┐рдзрд┐ рдХреЗ рд╕рд╛рде OnDataReadyCallback рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдмрдирд╛рдпрд╛ред рдФрд░ рдЕрдм refreshData рдкрджреНрдзрддрд┐ рд▓рд╛рдЧреВ рд╣реЛрддреА рд╣реИ (рд▓рд╛рдЧреВ рд╣реЛрддреА рд╣реИ) OnDataReadyCallback ред рдкреНрд░рддреАрдХреНрд╖рд╛ рдХреЛ рдЕрдиреБрдХрд░рдг рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВ Handler рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реВрдВред onDataReady 2 рд╕реЗрдХрдВрдб рдореЗрдВ рдПрдХ рдмрд╛рд░, onDataReady рд╡рд┐рдзрд┐ рдХреЛ рдЙрди рдХрдХреНрд╖рд╛рдУрдВ рдкрд░ рдмреБрд▓рд╛рдпрд╛ рдЬрд╛рдПрдЧрд╛ рдЬреЛ OnDataReadyCallback рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рд▓рд╛рдЧреВ рдХрд░рддреЗ рд╣реИрдВред

рдЖрдЗрдП рдПрдХ ViewModel рдмрдирд╛рдПрдВ:

MainViewModel.kt
 class MainViewModel { var repoModel: RepoModel = RepoModel() var text: String = "" var isLoading: Boolean = false } 


рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ, RepoModel , text рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рд╣реИ, рдЬреЛ рджрд┐рдЦрд╛рдпрд╛ рдЬрд╛рдПрдЧрд╛, рдФрд░ рдЪрд░ isLoading , рдЬреЛ рд╡рд░реНрддрдорд╛рди рд╕реНрдерд┐рддрд┐ рдХреЛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рддрд╛ рд╣реИред рдЖрдЗрдП рдПрдХ refresh рд╡рд┐рдзрд┐ рдмрдирд╛рдПрдВ рдЬреЛ рдбреЗрдЯрд╛ рдкреБрдирд░реНрдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЬрд╝рд┐рдореНрдореЗрджрд╛рд░ рд╣реИ:

MainViewModel.kt
 class MainViewModel { ... val onDataReadyCallback = object : OnDataReadyCallback { override fun onDataReady(data: String) { isLoading.set(false) text.set(data) } } fun refresh(){ isLoading.set(true) repoModel.refreshData(onDataReadyCallback) } } 


refresh рд╡рд┐рдзрд┐, refreshData рдкрд░ refreshData рдХреЛ рдХреЙрд▓ refreshData , рдЬреЛ рддрд░реНрдХреЛрдВ рдореЗрдВ рдПрдХ OnDataReadyCallback рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд▓реЗрддрд╛ рд╣реИред рдареАрдХ рд╣реИ, рд▓реЗрдХрд┐рди рдПрдХ object рдХреНрдпрд╛ рд╣реИ? рдЬрдм рднреА рдЖрдк рдПрдХ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рд▓рд╛рдЧреВ рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ рдпрд╛ рд╕рдмрдХреНрд▓рд╛рд╕рд┐рдВрдЧ рдХреЗ рдмрд┐рдирд╛ рдПрдХ рд╡рд┐рд╕реНрддрд╛рд░ рд╡рд░реНрдЧ рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рддреЛ рдЖрдк рдПрдХ рд╡рд╕реНрддреБ рдШреЛрд╖рдгрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗред рдФрд░ рдЕрдЧрд░ рдЖрдк рдЗрд╕реЗ рдПрдХ рдЕрдирд╛рдо рд╡рд░реНрдЧ рдХреЗ рд░реВрдк рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ? рдЗрд╕ рд╕реНрдерд┐рддрд┐ рдореЗрдВ, рдЖрдк рдСрдмреНрдЬреЗрдХреНрдЯ рдПрдХреНрд╕рдкреНрд░реЗрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣реЗ рд╣реИрдВ:

MainViewModel.kt
 class MainViewModel { var repoModel: RepoModel = RepoModel() var text: String = "" var isLoading: Boolean = false fun refresh() { repoModel.refreshData( object : OnDataReadyCallback { override fun onDataReady(data: String) { text = data }) } } 


рдЬрдм рд╣рдо refresh рдХрд╣рддреЗ рд╣реИрдВ, рддреЛ рд╣рдореЗрдВ рджреГрд╢реНрдп рдХреЛ рд▓реЛрдбрд┐рдВрдЧ рд╕реНрдерд┐рддрд┐ рдореЗрдВ рдмрджрд▓рдирд╛ рдЪрд╛рд╣рд┐рдП рдФрд░ рдЬрдм рдбреЗрдЯрд╛ рдЖрддрд╛ рд╣реИ, рддреЛ рд╕реЗрдЯ рдХреЛ false ред

рд╣рдореЗрдВ text рдХреЛ рднреА рдмрджрд▓рдирд╛ рд╣реЛрдЧрд╛
 ObservableField<String> 
, рдФрд░ рдкрд░ isLoading рд░рд╣рд╛ рд╣реИ
 ObservableField<Boolean> 
ред ObservableField рдбреЗрдЯрд╛ рдмрд╛рдЗрдВрдбрд┐рдВрдЧ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рд╕реЗ рдПрдХ рд╡рд░реНрдЧ рд╣реИ рдЬрд┐рд╕реЗ рд╣рдо рдСрдмреНрдЬрд░реНрд╡реЗрдмрд▓ рдСрдмреНрдЬреЗрдХреНрдЯ рдмрдирд╛рдиреЗ рдХреЗ рдмрдЬрд╛рдп рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдпрд╣ рдЙрд╕ рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЛ рд▓рдкреЗрдЯрддрд╛ рд╣реИ рдЬрд┐рд╕реЗ рд╣рдо рдирд┐рд░реАрдХреНрд╖рдг рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВред

MainViewModel.kt
 class MainViewModel { var repoModel: RepoModel = RepoModel() val text = ObservableField<String>() val isLoading = ObservableField<Boolean>() fun refresh(){ isLoading.set(true) repoModel.refreshData(object : OnDataReadyCallback { override fun onDataReady(data: String) { isLoading.set(false) text.set(data) } }) } } 


рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рдореИрдВ var рдХреЗ рдмрдЬрд╛рдп рд╡реИрд▓ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реВрдВ, рдХреНрдпреЛрдВрдХрд┐ рд╣рдо рдХреЗрд╡рд▓ рдлрд╝реАрд▓реНрдб рдореЗрдВ рдорд╛рди рдмрджрд▓реЗрдВрдЧреЗ, рд▓реЗрдХрд┐рди рдлрд╝реАрд▓реНрдб рд╕реНрд╡рдпрдВ рдирд╣реАрдВред рдФрд░ рдЕрдЧрд░ рдЖрдк рдЗрд╕реЗ рд╢реБрд░реВ рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рддреЛ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ:

initobserv.kt
 val text = ObservableField("old data") val isLoading = ObservableField(false) 



рдЖрдЗрдП рдЕрдкрдирд╛ рд▓реЗрдЖрдЙрдЯ рдмрджрд▓реЗрдВ рддрд╛рдХрд┐ рдпрд╣ рдкрд╛рда рдФрд░ isLading рдХрд╛ рдирд┐рд░реАрдХреНрд╖рдг рдХрд░ рд╕рдХреЗ ред рдЖрд░рдВрдн рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдХреЗ рдмрдЬрд╛рдп MainViewModel рдХреЛ рдмрд╛рдВрдзреЗрдВ :

activity_main.xml
 <data> <variable name="viewModel" type="me.mladenrakonjac.modernandroidapp.MainViewModel" /> </data> 


рддреЛ:

  • MainViewModel рд╕реЗ рдкрд╛рда рджреЗрдЦрдиреЗ рдХреЗ рд▓рд┐рдП TextView рдмрджрд▓реЗрдВ
  • рдПрдХ ProgressBar рдЬреЛрдбрд╝реЗрдВ, рдЬреЛ рдХреЗрд╡рд▓ рддрднреА рджрд┐рдЦрд╛рдИ рджреЗрдЧрд╛, рдЬрдм рдпрд╣ рд╕рдЪ рд╣реИ
  • рдмрдЯрди рдЬреЛрдбрд╝реЗрдВ, рдЬреЛ рдХреНрд▓рд┐рдХ рдХрд░рдиреЗ рдкрд░, MainViewModel рд╕реЗ рд░рд┐рдлреНрд░реЗрд╢ рд╡рд┐рдзрд┐ рдХреЛ рдХреЙрд▓ рдХрд░реЗрдЧрд╛ рдФрд░ рдХреЗрд╡рд▓ рддрднреА рдХреНрд▓рд┐рдХ рдХрд░рдиреЗ рдпреЛрдЧреНрдп рд╣реЛрдЧрд╛, рдЬрдм рдЖрдЗрд▓реЙрдбрд┐рдВрдЧ рдЧрд▓рдд рд╣реИ

main_activity.xml
 ... <TextView android:id="@+id/repository_name" android:text="@{viewModel.text}" ... /> ... <ProgressBar android:id="@+id/loading" android:visibility="@{viewModel.isLoading ? View.VISIBLE : View.GONE}" ... /> <Button android:id="@+id/refresh_button" android:onClick="@{() -> viewModel.refresh()}" android:clickable="@{viewModel.isLoading ? false : true}" /> ... 


рдпрджрд┐ рдЖрдк рдЕрднреА рдЪрд▓рд╛рддреЗ рд╣реИрдВ, рддреЛ рдЖрдкрдХреЛ View.VISIBLE and View.GONE cannot be used if View is not imported рдкреНрд░рд╛рдкреНрдд рд╣реЛрдЧреА, View.VISIBLE and View.GONE cannot be used if View is not imported ред рдареАрдХ рд╣реИ, рдЪрд▓реЛ рдЖрдпрд╛рдд рдХрд░рддреЗ рд╣реИрдВ:

main_activity.xml
 <data> <import type="android.view.View"/> <variable name="viewModel" type="me.fleka.modernandroidapp.MainViewModel" /> </data> 


рдареАрдХ рд╣реИ, рд▓реЗрдЖрдЙрдЯ рдХреЗ рд╕рд╛рде рдХрд┐рдпрд╛ред рдЕрдм рдмрдВрдзрди рдХреЗ рд╕рд╛рде рд╕рдорд╛рдкреНрдд рдХрд░реЗрдВред рдЬреИрд╕рд╛ рдХрд┐ рдореИрдВрдиреЗ рдХрд╣рд╛, View рдореЗрдВ ViewModel рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП:

MainActivity.kt
 class MainActivity : AppCompatActivity() { lateinit var binding: ActivityMainBinding var mainViewModel = MainViewModel() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = DataBindingUtil.setContentView(this, R.layout.activity_main) binding.viewModel = mainViewModel binding.executePendingBindings() } } 


рдЕрдВрдд рдореЗрдВ, рд╣рдо рдЪрд▓рд╛ рд╕рдХрддреЗ рд╣реИрдВ


рдЖрдк рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рдкреБрд░рд╛рдиреЗ рдбреЗрдЯрд╛ рдХреЛ рдирдП рдбреЗрдЯрд╛ рд╕реЗ рдмрджрд▓ рджрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред

рдпрд╣ рдПрдХ рд╕рд░рд▓ MVVM рдЙрджрд╛рд╣рд░рдг рдерд╛ред

рд▓реЗрдХрд┐рди рдПрдХ рд╕рдорд╕реНрдпрд╛ рд╣реИ, рдЪрд▓реЛ рд╕реНрдХреНрд░реАрди рдХреЛ рдЪрд╛рд▓реВ рдХрд░реЗрдВ


рдкреБрд░рд╛рдиреЗ рдбреЗрдЯрд╛ рдХреА рдЬрдЧрд╣ рдирдпрд╛ рдбреЗрдЯрд╛ рд▓реЗ рд▓рд┐рдпрд╛ ред рдпрд╣ рдХреИрд╕реЗ рд╕рдВрднрд╡ рд╣реИ? рдЧрддрд┐рд╡рд┐рдзрд┐ рдЬреАрд╡рдирдЪрдХреНрд░ рдкрд░ рдПрдХ рдирдЬрд╝рд░ рдбрд╛рд▓реЗрдВ:

рдЧрддрд┐рд╡рд┐рдзрд┐ рдЬреАрд╡рдирдЪрдХреНрд░
рдЫрд╡рд┐

рдЬрдм рдЖрдкрдиреЗ рдлреЛрди рдХреЛ рдЪрд╛рд▓реВ рдХрд┐рдпрд╛, рддреЛ рдЧрддрд┐рд╡рд┐рдзрд┐ рдХрд╛ рдПрдХ рдирдпрд╛ рдЙрджрд╛рд╣рд░рдг рдмрдирд╛рдпрд╛ рдЧрдпрд╛ рдерд╛ рдФрд░ onCreate() рд╡рд┐рдзрд┐ рдХреЛ рдмреБрд▓рд╛рдпрд╛ рдЧрдпрд╛ рдерд╛ред рд╣рдорд╛рд░реА рдЧрддрд┐рд╡рд┐рдзрд┐ рдкрд░ рдПрдХ рдирдЬрд╝рд░ рдбрд╛рд▓реЗрдВ:

MainActivity.kt
 class MainActivity : AppCompatActivity() { lateinit var binding: ActivityMainBinding var mainViewModel = MainViewModel() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = DataBindingUtil.setContentView(this, R.layout.activity_main) binding.viewModel = mainViewModel binding.executePendingBindings() } } 


рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ, рдЬрдм рдПрдХ рдЧрддрд┐рд╡рд┐рдзрд┐ рдЙрджрд╛рд╣рд░рдг рдмрдирд╛рдпрд╛ рдЧрдпрд╛ рдерд╛, рдПрдХ MainViewModel рдЙрджрд╛рд╣рд░рдг рднреА рдмрдирд╛рдпрд╛ рдЧрдпрд╛ рдерд╛ ред рдХреНрдпрд╛ рдпрд╣ рдЕрдЪреНрдЫрд╛ рд╣реИ рдЕрдЧрд░ рдХрд┐рд╕реА рддрд░рд╣ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдкреНрд░рддреНрдпреЗрдХ рдмрдирд╛рдП рдЧрдП MainActivity рдХреЗ рд▓рд┐рдП MainViewModel рдХрд╛ рдПрдХ рд╣реА рдЙрджрд╛рд╣рд░рдг рд╣реИ?

рдЬреАрд╡рдирдЪрдХреНрд░ рдХреЗ рдкреНрд░рддрд┐ рдЬрд╛рдЧрд░реВрдХ рдШрдЯрдХреЛрдВ рдХрд╛ рдкрд░рд┐рдЪрдп


рдХреНрдпреЛрдВрдХрд┐ рдХрдИ рдбреЗрд╡рд▓рдкрд░реНрд╕ рдХреЛ рдЗрд╕ рд╕рдорд╕реНрдпрд╛ рдХрд╛ рд╕рд╛рдордирд╛ рдХрд░рдирд╛ рдкрдбрд╝ рд░рд╣рд╛ рд╣реИ, рдПрдВрдбреНрд░реЙрдЗрдб рдлреНрд░реЗрдорд╡рд░реНрдХ рдЯреАрдо рдХреЗ рдбреЗрд╡рд▓рдкрд░реНрд╕ рдиреЗ рдЗрд╕реЗ рд╣рд▓ рдХрд░рдиреЗ рдореЗрдВ рдорджрдж рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдбрд┐рдЬрд╝рд╛рдЗрди рдХрд┐рдпрд╛ рдЧрдпрд╛ рдПрдХ рдкреБрд╕реНрддрдХрд╛рд▓рдп рдмрдирд╛рдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛ред ViewModel рд╡рд░реНрдЧ рдЙрдирдореЗрдВ рд╕реЗ рдПрдХ рд╣реИред рдпрд╣ рд╡рд╣ рд╡рд░реНрдЧ рд╣реИ рдЬрд┐рд╕реЗ рд╣рдорд╛рд░реЗ рд╕рднреА ViewModel рдХреЛ рд╡рд┐рд░рд╛рд╕рдд рдореЗрдВ рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдПред

рдЪрд▓реЛ рдЬреАрд╡рдирдЪрдХреНрд░ рдХреЗ рдкреНрд░рддрд┐ рдЬрд╛рдЧрд░реВрдХ рдШрдЯрдХреЛрдВ рд╕реЗ ViewModel рд╕реЗ MainViewModel рд╡рд┐рд░рд╛рд╕рдд рдореЗрдВ рдорд┐рд▓рд╛ рд╣реИред рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ рд╣рдореЗрдВ рдЕрдкрдиреА build.gradle рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рдЬреАрд╡рдирдЪрдХреНрд░ рдХреЗ рдкреНрд░рддрд┐ рдЬрд╛рдЧрд░реВрдХ рдШрдЯрдХреЛрдВ рдХреЛ рдЬреЛрдбрд╝рдирд╛ рд╣реЛрдЧрд╛:

build.gradle
 dependencies { ... implementation "android.arch.lifecycle:runtime:1.0.0-alpha9" implementation "android.arch.lifecycle:extensions:1.0.0-alpha9" kapt "android.arch.lifecycle:compiler:1.0.0-alpha9" 


MainViewModel рдХреЛ ViewModel рдХрд╛ рдЙрддреНрддрд░рд╛рдзрд┐рдХрд╛рд░реА рдмрдирд╛рдПрдВ:

MainViewModel.kt
 package me.mladenrakonjac.modernandroidapp import android.arch.lifecycle.ViewModel class MainViewModel : ViewModel() { ... } 


рд╣рдорд╛рд░реА MainActivity рдХреА рдСрдирдХреНрд░рд┐рдПрдЯ () рд╡рд┐рдзрд┐ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрд╛рдИ рджреЗрдЧреА:

MainActivity.kt
 class MainActivity : AppCompatActivity() { lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = DataBindingUtil.setContentView(this, R.layout.activity_main) binding.viewModel = ViewModelProviders.of(this).get(MainViewModel::class.java) binding.executePendingBindings() } } 


рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рд╣рдордиреЗ MainViewModel рдХрд╛ рдПрдХ рдирдпрд╛ рдЙрджрд╛рд╣рд░рдг рдирд╣реАрдВ рдмрдирд╛рдпрд╛ рд╣реИред рд╣рдо рдЗрд╕реЗ ViewModelProviders рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВрдЧреЗред ViewModelProviders рдПрдХ рдЙрдкрдпреЛрдЧрд┐рддрд╛ рд╡рд░реНрдЧ рд╣реИ рдЬрд┐рд╕рдореЗрдВ ViewModelProvider рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреА рдПрдХ рд╡рд┐рдзрд┐ рд╣реИред рдпрд╣ рд╕рдм рдЧреБрдВрдЬрд╛рдЗрд╢ рдХреА рдмрд╛рдд рд╣реИ ред рдпрджрд┐ рдЖрдк рдХрд┐рд╕реА рдЧрддрд┐рд╡рд┐рдзрд┐ рдореЗрдВ ViewModelProviders.of (рдпрд╣) рдХрд╣рддреЗ рд╣реИрдВ, рддреЛ рдЖрдкрдХрд╛ ViewModel рддрдм рддрдХ рдЬреАрд╡рд┐рдд рд░рд╣реЗрдЧрд╛, рдЬрдм рддрдХ рдпрд╣ рдЧрддрд┐рд╡рд┐рдзрд┐ рдЬреАрд╡рд┐рдд рд╣реИ (рдЬрдм рддрдХ рдХрд┐ рдпрд╣ рдкреБрди: рдирд┐рд░реНрдорд╛рдг рдХрд┐рдП рдмрд┐рдирд╛ рдирд╖реНрдЯ рди рд╣реЛ рдЬрд╛рдП)ред рдЗрд╕рд▓рд┐рдП, рдпрджрд┐ рдЖрдк рдЗрд╕реЗ рдПрдХ рдЦрдВрдб рдореЗрдВ рдХрд╣рддреЗ рд╣реИрдВ, рддреЛ рдЖрдкрдХрд╛ ViewModel рдЬреАрд╡рд┐рдд рд░рд╣реЗрдЧрд╛ рдЬрдмрдХрд┐ Fragment рдЬреАрд╡рд┐рдд рд╣реИ, рдЖрджрд┐ред рдЪрд┐рддреНрд░ рдкрд░ рдПрдХ рдирдЬрд╝рд░ рдбрд╛рд▓реЗрдВ:

рд╕реНрдХреЛрдк рдЬреАрд╡рдирдЪрдХреНрд░
рдЫрд╡рд┐

ViewModelProvider рдкрд╣рд▓реА рдХреЙрд▓ рдореЗрдВ рдПрдХ рдирдпрд╛ рдЙрджрд╛рд╣рд░рдг рдмрдирд╛рдиреЗ рдпрд╛ рдкреБрд░рд╛рдиреЗ рдХреЛ рд╡рд╛рдкрд╕ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЬрд╝рд┐рдореНрдореЗрджрд╛рд░ рд╣реИ рдпрджрд┐ рдЖрдкрдХреА рдЧрддрд┐рд╡рд┐рдзрд┐ рдпрд╛ рдлрд╝реНрд░реИрдЧрдореЗрдВрдЯ рдХреЛ рдлрд┐рд░ рд╕реЗ рдмрдирд╛рдпрд╛ рдЧрдпрд╛ рд╣реИред

рднреНрд░рдорд┐рдд рдордд рд╣реЛ

 MainViewModel::class.java 

рдХреЛрдЯрд▓рд┐рди рдореЗрдВ, рдпрджрд┐ рдЖрдк рдЕрдиреБрд╕рд░рдг рдХрд░рддреЗ рд╣реИрдВ

 MainViewModel::class 

рдпрд╣ рдЖрдкрдХреЛ рдХреНрд▓реЗрд╕реНрд╕ рд▓реМрдЯрд╛рдПрдЧрд╛ , рдЬреЛ рдХрд┐ рдЬрд╛рд╡рд╛ рд╕реЗ рдХреНрд▓рд╛рд╕ рдЬреИрд╕рд╛ рдирд╣реАрдВ рд╣реИред рдЗрд╕рд▓рд┐рдП рдпрджрд┐ рд╣рдо .java рд▓рд┐рдЦрддреЗ рд╣реИрдВ, рддреЛ рджрд╕реНрддрд╛рд╡реЗрдЬ рдХреЗ рдЕрдиреБрд╕рд╛рд░ рдпрд╣ рд╣реИ:
KClass рдХреЗ рдЗрд╕ рдЙрджрд╛рд╣рд░рдг рдХреЗ рдЕрдиреБрд░реВрдк рдХреНрд▓рд╛рд╕ рдЬрд╛рд╡рд╛ рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рд▓реМрдЯрд╛рдПрдЧрд╛
рдЖрдЗрдП рджреЗрдЦреЗрдВ рдХрд┐ рдЬрдм рдЖрдк рд╕реНрдХреНрд░реАрди рдХреЛ рдШреБрдорд╛рддреЗ рд╣реИрдВ рддреЛ рдХреНрдпрд╛ рд╣реЛрддрд╛ рд╣реИ


рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рд╕реНрдХреНрд░реАрди рд░реЛрдЯреЗрд╢рди рд╕реЗ рдкрд╣рд▓реЗ рдЬреИрд╕рд╛ рдбреЗрдЯрд╛ рд╣реИред

рдкрд┐рдЫрд▓реЗ рд▓реЗрдЦ рдореЗрдВ, рдореИрдВрдиреЗ рдХрд╣рд╛ рдерд╛ рдХрд┐ рд╣рдорд╛рд░реЗ рдЖрд╡реЗрджрди рдореЗрдВ рдЬреАрдердм рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдХреА рд╕реВрдЪреА рдорд┐рд▓реЗрдЧреА рдФрд░ рдЙрдиреНрд╣реЗрдВ рджрд┐рдЦрд╛рдпрд╛ рдЬрд╛рдПрдЧрд╛ред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ getRepositories рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдЬреЛрдбрд╝рдирд╛ рд╣реЛрдЧрд╛, рдЬреЛ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдХреА рдПрдХ рдирдХрд▓реА рд╕реВрдЪреА рд▓реМрдЯрд╛рдПрдЧрд╛:

RepoModel.kt
 class RepoModel { fun refreshData(onDataReadyCallback: OnDataReadyCallback) { Handler().postDelayed({ onDataReadyCallback.onDataReady("new data") },2000) } fun getRepositories(onRepositoryReadyCallback: OnRepositoryReadyCallback) { var arrayList = ArrayList<Repository>() arrayList.add(Repository("First", "Owner 1", 100 , false)) arrayList.add(Repository("Second", "Owner 2", 30 , true)) arrayList.add(Repository("Third", "Owner 3", 430 , false)) Handler().postDelayed({ onRepositoryReadyCallback.onDataReady(arrayList) },2000) } } interface OnDataReadyCallback { fun onDataReady(data : String) } interface OnRepositoryReadyCallback { fun onDataReady(data : ArrayList<Repository>) } 


рд╣рдореЗрдВ MainViewModel рдореЗрдВ рдПрдХ рд╡рд┐рдзрд┐ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ рдЬреЛ RepoModel рд╕реЗ getRepositories рдХреЛ рдХреЙрд▓ рдХрд░рддреА рд╣реИ:

MainViewModel.kt
 class MainViewModel : ViewModel() { ... var repositories = ArrayList<Repository>() fun refresh(){ ... } fun loadRepositories(){ isLoading.set(true) repoModel.getRepositories(object : OnRepositoryReadyCallback{ override fun onDataReady(data: ArrayList<Repository>) { isLoading.set(false) repositories = data } }) } } 


рдФрд░ рдЕрдВрдд рдореЗрдВ, рд╣рдореЗрдВ RecyclerView рдореЗрдВ рдЗрди рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдХреЛ рджрд┐рдЦрд╛рдирд╛ рд╣реЛрдЧрд╛ред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ рдЪрд╛рд╣рд┐рдП:

  • рд▓реЗрдЖрдЙрдЯ rv_item_repository.xml рдмрдирд╛рдПрдВ
  • RecyclerView рдХреЛ рд▓реЗрдЖрдЙрдЯ рдЧрддрд┐рд╡рд┐рдзрд┐_main.xml рдореЗрдВ рдЬреЛрдбрд╝реЗрдВ
  • RepositoryRecyclerViewAdapter рдмрдирд╛рдПрдБ
  • рдПрдбрд╛рдкреНрдЯрд░ рдХреЛ recyclerview рдкрд░ рд╕реНрдерд╛рдкрд┐рдд рдХрд░реЗрдВ

Rv_item_repository.xml рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП , рдореИрдВрдиреЗ CardView рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛, рдЗрд╕рд▓рд┐рдП рд╣рдореЗрдВ рдЗрд╕реЗ build.gradle (рдРрдк) рдореЗрдВ рдЬреЛрдбрд╝рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ:

 implementation 'com.android.support:cardview-v7:26.0.1' 

рдпрд╣рд╛рдБ рдпрд╣ рдХреИрд╕рд╛ рджрд┐рдЦрддрд╛ рд╣реИ:

rv_item_repository.xml
 <?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools"> <data> <import type="android.view.View" /> <variable name="repository" type="me.mladenrakonjac.modernandroidapp.uimodels.Repository" /> </data> <android.support.v7.widget.CardView android:layout_width="match_parent" android:layout_height="96dp" android:layout_margin="8dp"> <android.support.constraint.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/repository_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="16dp" android:layout_marginStart="16dp" android:text="@{repository.repositoryName}" android:textSize="20sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintHorizontal_bias="0.0" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.083" tools:text="Modern Android App" /> <TextView android:id="@+id/repository_has_issues" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="16dp" android:layout_marginStart="16dp" android:layout_marginTop="8dp" android:text="@string/has_issues" android:textStyle="bold" android:visibility="@{repository.hasIssues ? View.VISIBLE : View.GONE}" app:layout_constraintBottom_toBottomOf="@+id/repository_name" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="1.0" app:layout_constraintStart_toEndOf="@+id/repository_name" app:layout_constraintTop_toTopOf="@+id/repository_name" app:layout_constraintVertical_bias="1.0" /> <TextView android:id="@+id/repository_owner" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginBottom="8dp" android:layout_marginEnd="16dp" android:layout_marginStart="16dp" android:text="@{repository.repositoryOwner}" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/repository_name" app:layout_constraintVertical_bias="0.0" tools:text="Mladen Rakonjac" /> <TextView android:id="@+id/number_of_starts" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="8dp" android:layout_marginEnd="16dp" android:layout_marginStart="16dp" android:layout_marginTop="8dp" android:text="@{String.valueOf(repository.numberOfStars)}" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="1" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/repository_owner" app:layout_constraintVertical_bias="0.0" tools:text="0 stars" /> </android.support.constraint.ConstraintLayout> </android.support.v7.widget.CardView> </layout> 


рдЕрдЧрд▓рд╛ рдХрджрдо рдЧрддрд┐рд╡рд┐рдзрд┐_main.xml рдореЗрдВ RecyclerView рдЬреЛрдбрд╝ рд░рд╣рд╛ рд╣реИ ред рдРрд╕рд╛ рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ, RecyclerView рдкреБрд╕реНрддрдХрд╛рд▓рдп рдЬреЛрдбрд╝рдирд╛ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░реЗрдВ:

 implementation 'com.android.support:recyclerview-v7:26.0.1' 

activity_main.xml
 <?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools"> <data> <import type="android.view.View"/> <variable name="viewModel" type="me.fleka.modernandroidapp.MainViewModel" /> </data> <android.support.constraint.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent" tools:context="me.fleka.modernandroidapp.MainActivity"> <ProgressBar android:id="@+id/loading" android:layout_width="48dp" android:layout_height="48dp" android:indeterminate="true" android:visibility="@{viewModel.isLoading ? View.VISIBLE : View.GONE}" app:layout_constraintBottom_toTopOf="@+id/refresh_button" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <android.support.v7.widget.RecyclerView android:id="@+id/repository_rv" android:layout_width="0dp" android:layout_height="0dp" android:indeterminate="true" android:visibility="@{viewModel.isLoading ? View.GONE : View.VISIBLE}" app:layout_constraintBottom_toTopOf="@+id/refresh_button" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" tools:listitem="@layout/rv_item_repository" /> <Button android:id="@+id/refresh_button" android:layout_width="160dp" android:layout_height="40dp" android:layout_marginBottom="8dp" android:layout_marginEnd="8dp" android:layout_marginStart="8dp" android:layout_marginTop="8dp" android:onClick="@{() -> viewModel.loadRepositories()}" android:clickable="@{viewModel.isLoading ? false : true}" android:text="Refresh" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="1.0" /> </android.support.constraint.ConstraintLayout> </layout> 



рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рд╣рдордиреЗ рдХреБрдЫ TextView рддрддреНрд╡ рдирд┐рдХрд╛рд▓реЗ рд╣реИрдВ рдФрд░ рдЕрдм рдмрдЯрди рд░рд┐рдлреНрд░реЗрд╢ рдХреЗ рдмрдЬрд╛рдп рд▓реЛрдб-рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рд▓реЙрдиреНрдЪ рдХрд░рддрд╛ рд╣реИ :

button.xml
 <Button android:id="@+id/refresh_button" android:onClick="@{() -> viewModel.loadRepositories()}" ... /> 


рдЪрд▓рд┐рдП MainViewModel рд╕реЗ рд░рд┐рдлреНрд░реЗрд╢ рд╡рд┐рдзрд┐ рдХреЛ рд╣рдЯрд╛рддреЗ рд╣реИрдВ рдФрд░ RepoModel рд╕реЗ рд░рд┐рдлреНрд░реЗрд╢рдбреИрдЯрд╛ рдХреЛ рдЕрдирд╛рд╡рд╢реНрдпрдХ рдХреЗ рд░реВрдк рдореЗрдВ рд╣рдЯрд╛рддреЗ рд╣реИрдВред

рдЕрдм рдЖрдкрдХреЛ RecyclerView рдХреЗ рд▓рд┐рдП рдПрдХ рдПрдбреЗрдкреНрдЯрд░ рдмрдирд╛рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ:

RepositoryRecyclerViewAdapter.kt
 class RepositoryRecyclerViewAdapter(private var items: ArrayList<Repository>, private var listener: OnItemClickListener) : RecyclerView.Adapter<RepositoryRecyclerViewAdapter.ViewHolder>() { override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolder { val layoutInflater = LayoutInflater.from(parent?.context) val binding = RvItemRepositoryBinding.inflate(layoutInflater, parent, false) return ViewHolder(binding) } override fun onBindViewHolder(holder: ViewHolder, position: Int) = holder.bind(items[position], listener) override fun getItemCount(): Int = items.size interface OnItemClickListener { fun onItemClick(position: Int) } class ViewHolder(private var binding: RvItemRepositoryBinding) : RecyclerView.ViewHolder(binding.root) { fun bind(repo: Repository, listener: OnItemClickListener?) { binding.repository = repo if (listener != null) { binding.root.setOnClickListener({ _ -> listener.onItemClick(layoutPosition) }) } binding.executePendingBindings() } } } 


рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ ViewHolder View рдХреЗ рдмрдЬрд╛рдп RvItemRepositoryBinding рдХреЗ рдкреНрд░рдХрд╛рд░ рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рд▓реЗрддрд╛ рд╣реИ, рддрд╛рдХрд┐ рд╣рдо рдкреНрд░рддреНрдпреЗрдХ рддрддреНрд╡ рдХреЗ рд▓рд┐рдП ViewHolder рдореЗрдВ рдбреЗрдЯрд╛ рдмрд╛рдЗрдВрдбрд┐рдВрдЧ рдХреЛ рд▓рд╛рдЧреВ рдХрд░ рд╕рдХреЗрдВред рд╕рд┐рдВрдЧрд▓ рд▓рд╛рдЗрди рдлрд╝рдВрдХреНрд╢рди (рдСрдирд▓рд╛рдЗрди) рд╕реЗ рд╢рд░реНрдорд┐рдВрджрд╛ рди рд╣реЛрдВ:

 override fun onBindViewHolder(holder: ViewHolder, position: Int) = holder.bind(items[position], listener) 

рдпрд╣ рдХреЗрд╡рд▓ рдПрдХ рдЫреЛрдЯреА рдкреНрд░рд╡рд┐рд╖реНрдЯрд┐ рд╣реИ:

 override fun onBindViewHolder(holder: ViewHolder, position: Int){ return holder.bind(items[position], listener) } 

рдФрд░ рдЖрдЗрдЯрдо [рд╕реНрдерд┐рддрд┐] рд╕реВрдЪрдХрд╛рдВрдХ рдСрдкрд░реЗрдЯрд░ рдХреЗ рд▓рд┐рдП рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╣реИред рдпрд╣ рдЖрдЗрдЯрдореНрд╕ (рд╕реНрдерд┐рддрд┐) рдХреЗ рд╕рдорд╛рди рд╣реИред

рдПрдХ рдФрд░ рд▓рд╛рдЗрди рдЬреЛ рдЖрдкрдХреЛ рднреНрд░рдорд┐рдд рдХрд░ рд╕рдХрддреА рд╣реИ:

 binding.root.setOnClickListener({ _ -> listener.onItemClick(layoutPosition) }) 

рдпрджрд┐ рдЖрдк рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░ рд░рд╣реЗ рд╣реИрдВ рддреЛ рдЖрдк рдкреИрд░рд╛рдореАрдЯрд░ рдХреЛ _ рд╕реЗ рдмрджрд▓ рд╕рдХрддреЗ рд╣реИрдВред рдЕрдЪреНрдЫрд╛ рд▓рдЧрд╛ рдирд╛?

рд╣рдордиреЗ рдПрдбреЙрдкреНрдЯрд░ рдмрдирд╛рдпрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдлрд┐рд░ рднреА рдЗрд╕реЗ рдореЗрдирдПрдХреНрдЯрд┐рд╡рд┐рдЯреА рдореЗрдВ recyclerView рдкрд░ рд▓рд╛рдЧреВ рдирд╣реАрдВ рдХрд┐рдпрд╛ рд╣реИ:

MainActivity.kt
 class MainActivity : AppCompatActivity(), RepositoryRecyclerViewAdapter.OnItemClickListener { lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = DataBindingUtil.setContentView(this, R.layout.activity_main) val viewModel = ViewModelProviders.of(this).get(MainViewModel::class.java) binding.viewModel = viewModel binding.executePendingBindings() binding.repositoryRv.layoutManager = LinearLayoutManager(this) binding.repositoryRv.adapter = RepositoryRecyclerViewAdapter(viewModel.repositories, this) } override fun onItemClick(position: Int) { TODO("not implemented") //To change body of created functions use File | Settings | File Templates. } } 


рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдЪрд▓рд╛рдПрдБ


рдпрд╣ рдЕрдЬреАрдм рд╣реИред рдХреНрдпрд╛ рд╣реБрдЖ рдерд╛?

  • рдЧрддрд┐рд╡рд┐рдзрд┐ рдмрдирд╛рдИ рдЧрдИ рдереА, рдЗрд╕рд▓рд┐рдП рдПрдХ рдирдпрд╛ рдПрдбреЙрдкреНрдЯрд░ рднреА рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдХреЗ рд╕рд╛рде рдмрдирд╛рдпрд╛ рдЧрдпрд╛ рдерд╛ рдЬреЛ рд▓рдЧрднрдЧ рдЦрд╛рд▓реА рд╣реИрдВ
  • рд╣рдо рдмрдЯрди рдХреЛ рдзрдХреНрдХрд╛ рджреЗрддреЗ рд╣реИрдВ
  • рдкреНрд░рдЧрддрд┐ рджрд┐рдЦрд╛рддреЗ рд╣реБрдП рд▓реЛрдбрд░рдкреНрд░реЛрд╕реЗрд╕рд░реАрдЬрд╝ рдХрд╣рддреЗ рд╣реИрдВ
  • 2 рд╕реЗрдХрдВрдб рдХреЗ рдмрд╛рдж, рд╣рдо рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдкреНрд░рд╛рдкреНрдд рдХрд░рддреЗ рд╣реИрдВ, рдкреНрд░рдЧрддрд┐ рдЫрд┐рдкреА рд╣реБрдИ рд╣реИ, рд▓реЗрдХрд┐рди рд╡реЗ рджрд┐рдЦрд╛рдИ рдирд╣реАрдВ рджреЗрддреЗ рд╣реИрдВред рдРрд╕рд╛ рдЗрд╕рд▓рд┐рдП рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рдПрдбреЙрдкреНрдЯрд░ рдореЗрдВ NotDataSetChanged рдХреЛ рдирд╣реАрдВ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ
  • рдЬрдм рд╣рдо рд╕реНрдХреНрд░реАрди рдХреЛ рдШреБрдорд╛рддреЗ рд╣реИрдВ, рддреЛ рдПрдХ рдирдИ рдЧрддрд┐рд╡рд┐рдзрд┐ рдмрдирд╛рдИ рдЬрд╛рддреА рд╣реИ, рдЗрд╕рд▓рд┐рдП рдХреБрдЫ рдбреЗрдЯрд╛ рдХреЗ рд╕рд╛рде рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдкреИрд░рд╛рдореАрдЯрд░ рдХреЗ рд╕рд╛рде рдПрдХ рдирдпрд╛ рдПрдбрд╛рдкреНрдЯрд░ рдмрдирд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ

рдЗрд╕рд▓рд┐рдП, рдЬреИрд╕рд╛ рдХрд┐ MainViewModel рдХреЛ рдирдИ рд╡рд╕реНрддреБрдУрдВ рдХреА MainActivity рдХреЛ рд╕реВрдЪрд┐рдд рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП, рдХреНрдпрд╛ рд╣рдо InformDataSetChanged рдХреЛ рдХреЙрд▓ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ?

рд╣рдо рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗ

рдпрд╣ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИ, MainViewModel рдХреЛ MainActivity рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмрд┐рд▓реНрдХреБрд▓ рднреА рдирд╣реАрдВ рдЬрд╛рдирдирд╛ рдЪрд╛рд╣рд┐рдПред

MainActivity рд╡рд╣ рд╣реИ рдЬрд┐рд╕рдХреЗ рдкрд╛рд╕ MainViewModel рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рд╣реИ, рдЗрд╕рд▓рд┐рдП рдЗрд╕реЗ рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ рдХреЗ рд▓рд┐рдП рд╕реБрдирдирд╛ рдЪрд╛рд╣рд┐рдП рдФрд░ рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ рдХреЗ рдПрдбрд╛рдкреНрдЯрд░ рдХреЛ рд╕реВрдЪрд┐рдд рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдПред

рд▓реЗрдХрд┐рди рдпрд╣ рдХреИрд╕реЗ рдХрд░реЗрдВ?

рд╣рдо рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдХрд╛ рдирд┐рд░реАрдХреНрд╖рдг рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП рдбреЗрдЯрд╛ рдмрджрд▓рдиреЗ рдХреЗ рдмрд╛рдж, рд╣рдо рдЕрдкрдиреЗ рдПрдбреЗрдкреНрдЯрд░ рдХреЛ рдмрджрд▓ рд╕рдХрддреЗ рд╣реИрдВред

рдЗрд╕ рдлреИрд╕рд▓реЗ рдореЗрдВ рдХреНрдпрд╛ рдЧрд▓рдд рд╣реИ?

рдЖрдЗрдП рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдорд╛рдорд▓реЗ рдХреЛ рджреЗрдЦреЗрдВ:

  • MainActivity рдореЗрдВ, рд╣рдо рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдХрд╛ рдирд┐рд░реАрдХреНрд╖рдг рдХрд░рддреЗ рд╣реИрдВ: рдЬрдм рдХреЛрдИ рдкрд░рд┐рд╡рд░реНрддрди рд╣реЛрддрд╛ рд╣реИ, рддреЛ рд╣рдо InformDataSetChanged рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рддреЗ рд╣реИрдВ
  • рд╣рдо рдмрдЯрди рдХреЛ рдзрдХреНрдХрд╛ рджреЗрддреЗ рд╣реИрдВ
  • рдЬрдм рд╣рдо рдбреЗрдЯрд╛ рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ рдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░ рд░рд╣реЗ рд╣реИрдВ, рддреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ рдХреЗ рдХрд╛рд░рдг MainActivity рдХреЛ рдлрд┐рд░ рд╕реЗ рдмрдирд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ ред
  • рд╣рдорд╛рд░рд╛ MainViewModel рдЕрднреА рднреА рдЬреАрд╡рд┐рдд рд╣реИ
  • 2 рд╕реЗрдХрдВрдб рдХреЗ рдмрд╛рдж, рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдлрд╝реАрд▓реНрдб рдирдП рдЖрдЗрдЯрдо рдкреНрд░рд╛рдкреНрдд рдХрд░рддрд╛ рд╣реИ рдФрд░ рдкрд░реНрдпрд╡реЗрдХреНрд╖рдХ рдХреЛ рд╕реВрдЪрд┐рдд рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдбреЗрдЯрд╛ рдмрджрд▓ рдЧрдпрд╛ рд╣реИ
  • рдкреНрд░реЗрдХреНрд╖рдХ рдПрдбреЙрдкреНрдЯрд░ рдкрд░ NotDataSetChanged рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░рддрд╛ рд╣реИ, рдЬреЛ рдЕрдм рдореМрдЬреВрдж рдирд╣реАрдВ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ MainActivity рдХреЛ рдлрд┐рд░ рд╕реЗ рдмрдирд╛рдпрд╛ рдЧрдпрд╛ рд╣реИ

рд╡реИрд╕реЗ, рд╣рдорд╛рд░рд╛ рдлреИрд╕рд▓рд╛ рдХрд╛рдлреА рдЕрдЪреНрдЫрд╛ рдирд╣реАрдВ рд╣реИред

LiveData рдХрд╛ рдкрд░рд┐рдЪрдп


LiveData рдПрдХ рдЕрдиреНрдп рдЬреАрд╡рдирдЪрдХреНрд░-рдЬрд╛рдЧрд░реВрдХ рдШрдЯрдХ рд╣реИред рдпрд╣ рдПрдХ рдЕрд╡рд▓реЛрдХрди рдпреЛрдЧреНрдп рд╣реИ рдЬреЛ рджреГрд╢реНрдп рдЬреАрд╡рди рдЪрдХреНрд░ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирддрд╛ рд╣реИред рдЗрд╕рд▓рд┐рдП рдЬрдм рдХреЛрдИ рдЧрддрд┐рд╡рд┐рдзрд┐ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдкрд░рд┐рд╡рд░реНрддрди рдХреЗ рдХрд╛рд░рдг рдирд╖реНрдЯ рд╣реЛ рдЬрд╛рддреА рд╣реИ , рддреЛ LiveData рдХреЛ рдЗрд╕рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдкрддрд╛ рд╣реЛрддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдпрд╣ рдкрд░реНрдпрд╡реЗрдХреНрд╖рдХ рдХреЛ рдирд╖реНрдЯ рдЧрддрд┐рд╡рд┐рдзрд┐ рд╕реЗ рднреА рд╣рдЯрд╛ рджреЗрддрд╛ рд╣реИред

рд╣рдо MainViewModel рдореЗрдВ рд▓рд╛рдЧреВ рд╣реЛрддреЗ рд╣реИрдВ :

MainViewModel.kt
 class MainViewModel : ViewModel() { var repoModel: RepoModel = RepoModel() val text = ObservableField("old data") val isLoading = ObservableField(false) var repositories = MutableLiveData<ArrayList<Repository>>() fun loadRepositories() { isLoading.set(true) repoModel.getRepositories(object : OnRepositoryReadyCallback { override fun onDataReady(data: ArrayList<Repository>) { isLoading.set(false) repositories.value = data } }) } } 


рдФрд░ MainActivity рдХрд╛ рдЕрд╡рд▓реЛрдХрди рдХрд░рдирд╛ рд╢реБрд░реВ рдХрд░реЗрдВ:

MainActivity.kt
 class MainActivity : LifecycleActivity(), RepositoryRecyclerViewAdapter.OnItemClickListener { private lateinit var binding: ActivityMainBinding private val repositoryRecyclerViewAdapter = RepositoryRecyclerViewAdapter(arrayListOf(), this) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = DataBindingUtil.setContentView(this, R.layout.activity_main) val viewModel = ViewModelProviders.of(this).get(MainViewModel::class.java) binding.viewModel = viewModel binding.executePendingBindings() binding.repositoryRv.layoutManager = LinearLayoutManager(this) binding.repositoryRv.adapter = repositoryRecyclerViewAdapter viewModel.repositories.observe(this, Observer<ArrayList<Repository>> { it?.let{ repositoryRecyclerViewAdapter.replaceData(it)} }) } override fun onItemClick(position: Int) { TODO("not implemented") //To change body of created functions use File | Settings | File Templates. } } 


рдЗрд╕ рд╢рдмреНрдж рдХрд╛ рдХреНрдпрд╛ рдЕрд░реНрде рд╣реИ? рдпрджрд┐ рдХрд┐рд╕реА рдлрд╝рдВрдХреНрд╢рди рдореЗрдВ рдХреЗрд╡рд▓ рдПрдХ рдкреИрд░рд╛рдореАрдЯрд░ рд╣реИ, рддреЛ рдЗрд╕ рдХреАрд╡рд░реНрдб рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЗрд╕ рдкреИрд░рд╛рдореАрдЯрд░ рддрдХ рдкрд╣реБрдВрдЪ рдкреНрд░рд╛рдкреНрдд рдХреА рдЬрд╛ рд╕рдХрддреА рд╣реИред рддреЛ, рдорд╛рди рд▓реЗрдВ рдХрд┐ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ 2 рд╕реЗ рдЧреБрдгрд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рд▓рдВрдмреЛрджрд░ рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ рд╣реИ:

 ((a) -> 2 * a) 

рдирд┐рдореНрдирд╛рдиреБрд╕рд╛рд░ рдмрджрд▓рд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ:

 (it * 2) 

рдпрджрд┐ рдЖрдк рдЕрднреА рдЖрд╡реЗрджрди рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдЖрдк рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рд╕рдм рдХреБрдЫ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ


...

рдореИрдВ MVV рдкрд░ MVVM рдХреЛ рдХреНрдпреЛрдВ рдкрд╕рдВрдж рдХрд░рддрд╛ рд╣реВрдВ?



  • рд╡реНрдпреВ рдХреЗ рд▓рд┐рдП рдХреЛрдИ рдЙрдмрд╛рдК рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдирд╣реАрдВ рд╣реИ, рдЬреИрд╕рд╛ рдХрд┐ ViewModel рдореЗрдВ View рдХрд╛ рдХреЛрдИ рд╕рдВрджрд░реНрдн рдирд╣реАрдВ рд╣реИ
  • рдкреНрд░рд╕реНрддреБрддрдХрд░реНрддрд╛ рдХреЗ рд▓рд┐рдП рдХреЛрдИ рдЙрдмрд╛рдК рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдирд╣реАрдВ рд╣реИ, рдФрд░ рдпрд╣ рдЖрд╡рд╢реНрдпрдХ рдирд╣реАрдВ рд╣реИ
  • рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ рдХреЛ рд╕рдВрднрд╛рд▓рдиреЗ рдХреЗ рд▓рд┐рдП рдмрд╣реБрдд рдЖрд╕рд╛рди рд╣реИ
  • MVVM рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдЧрддрд┐рд╡рд┐рдзрд┐, рдЯреБрдХрдбрд╝реЗ рдЖрджрд┐ рдХреЗ рд▓рд┐рдП рдХрдо рдХреЛрдб рд╣реИред

...

рд░рд┐рдкреЛрдЬрд┐рдЯрд░реА рдкреИрдЯрд░реНрди


рдпреЛрдЬрдирд╛
рдЫрд╡рд┐

рдЬреИрд╕рд╛ рдХрд┐ рдореИрдВрдиреЗ рдкрд╣рд▓реЗ рдХрд╣рд╛, рдореЙрдбрд▓ рдЙрд╕ рдкрд░рдд рдХреЗ рд▓рд┐рдП рд╕рд┐рд░реНрдл рдПрдХ рд╕рд╛рд░ рдирд╛рдо рд╣реИ рдЬрд╣рд╛рдВ рд╣рдо рдбреЗрдЯрд╛ рддреИрдпрд╛рд░ рдХрд░ рд░рд╣реЗ рд╣реИрдВред рдЗрд╕рдореЗрдВ рдЖрдорддреМрд░ рдкрд░ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдФрд░ рдбреЗрдЯрд╛ рдХреНрд▓рд╛рд╕ рд╢рд╛рдорд┐рд▓ рд╣реИрдВред рдкреНрд░рддреНрдпреЗрдХ рдЗрдХрд╛рдИ (рдбреЗрдЯрд╛) рд╡рд░реНрдЧ рдореЗрдВ рдПрдХ рд╣реА рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рд╡рд░реНрдЧ рд╣реЛрддрд╛ рд╣реИред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдпрджрд┐ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдЙрдкрдпреЛрдХреНрддрд╛ рдФрд░ рдкреЛрд╕реНрдЯ рд╣реИрдВ , рддреЛ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдЙрдкрдпреЛрдХреНрддрд╛ рдФрд░ рдкреЛрд╕реНрдЯ - рднрдВрдбрд╛рд░ рднреА рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред рд╕рд╛рд░рд╛ рдбреЗрдЯрд╛ рд╡рд╣реАрдВ рд╕реЗ рдЖрддрд╛ рд╣реИред рд╣рдореЗрдВ рдХрднреА рднреА View рдпрд╛ ViewModel рд╕реЗ рд╕рд╛рдЭрд╛ рдкреНрд░рд╛рдердорд┐рдХрддрд╛рдПрдВ рдпрд╛ DB рдХрд╛ рдЙрджрд╛рд╣рд░рдг рдирд╣реАрдВ рдмреБрд▓рд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред

рдЗрд╕рд▓рд┐рдП рд╣рдо рдЕрдкрдиреЗ рд░реЗрдкреЛрдореЙрдбрд▓ рдХрд╛ рдирд╛рдо рдмрджрд▓рдХрд░ GitRepoRepository рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдЬрд╣рд╛рдВ GitRepo Github рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рд╕реЗ рдЖрдПрдЧрд╛ рдФрд░ рд░рд┐рдкреЛрдЬрд┐рдЯрд░реА рд░рд┐рдкреЛрдЬрд┐рдЯрд░реА рдкреИрдЯрд░реНрди рд╕реЗ рдЖрдПрдЧрд╛ред

RepoRepositories.kt
 class GitRepoRepository { fun getGitRepositories(onRepositoryReadyCallback: OnRepositoryReadyCallback) { var arrayList = ArrayList<Repository>() arrayList.add(Repository("First", "Owner 1", 100, false)) arrayList.add(Repository("Second", "Owner 2", 30, true)) arrayList.add(Repository("Third", "Owner 3", 430, false)) Handler().postDelayed({ onRepositoryReadyCallback.onDataReady(arrayList) }, 2000) } } interface OnRepositoryReadyCallback { fun onDataReady(data: ArrayList<Repository>) } 


рдареАрдХ рд╣реИ, MainViewModel GitRepoRepsitories рд╕реЗ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдХреА Github рд╕реВрдЪреА рдкреНрд░рд╛рдкреНрдд рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди GitRepoRepositories рдХрд╣рд╛рдБ рд╕реЗ рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВ?

рдЖрдк рдЙрджрд╛рд╣рд░рдг рд╕реЗ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдкрд░ рд╕реАрдзреЗ рдХреНрд▓рд╛рдЗрдВрдЯ рдпрд╛ DB рдХреЛ рдХреЙрд▓ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдпрд╣ рдЕрднреА рднреА рд╕рдмрд╕реЗ рдЕрдЪреНрдЫрд╛ рдЕрднреНрдпрд╛рд╕ рдирд╣реАрдВ рд╣реИред рдЖрдкрдХрд╛ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдЬрд┐рддрдирд╛ рд╕рдВрднрд╡ рд╣реЛ рдЙрддрдирд╛ рдореЙрдбреНрдпреВрд▓рд░ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред рдХреНрдпрд╛ рд╣реЛрдЧрд╛ рдЕрдЧрд░ рдЖрдк рд╡реЙрд▓реА рдХреЛ рд░рд┐рдЯреНрд░реЛрдлрд┐рдЯ рд╕реЗ рдмрджрд▓рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрд▓рдЧ-рдЕрд▓рдЧ рдХреНрд▓рд╛рдЗрдВрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХрд╛ рдирд┐рд░реНрдгрдп рд▓реЗрддреЗ рд╣реИрдВ? рдпрджрд┐ рдЖрдкрдХреЗ рдЕрдВрджрд░ рдХрд┐рд╕реА рддрд░рд╣ рдХрд╛ рддрд░реНрдХ рд╣реИ, рддреЛ рд░рд┐рдлреИрдХреНрдЯрд░рд┐рдВрдЧ рдХрд░рдирд╛ рдореБрд╢реНрдХрд┐рд▓ рд╣реЛрдЧрд╛ред рдЖрдкрдХреЗ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдХреЛ рдпрд╣ рдЬрд╛рдирдиреЗ рдХреА рдЬрд░реВрд░рдд рдирд╣реАрдВ рд╣реИ рдХрд┐ рд░рд┐рдореЛрдЯ рдбреЗрдЯрд╛ рдХреЛ рдкреБрдирдГ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрдк рдХрд┐рд╕ рдХреНрд▓рд╛рдЗрдВрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣реЗ рд╣реИрдВред

  • рдХреЗрд╡рд▓ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдХреЛ рдЬрд╛рдирдиреЗ рдХреА рдЬрд░реВрд░рдд рд╣реИ рдХрд┐ рдбреЗрдЯрд╛ рджреВрд░рд╕реНрде рд░реВрдк рд╕реЗ рдпрд╛ рд╕реНрдерд╛рдиреАрдп рд░реВрдк рд╕реЗ рдЖрддрд╛ рд╣реИред рд╣рдореЗрдВ рдпрд╣ рдЬрд╛рдирдиреЗ рдХреА рдХреЛрдИ рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ рдХрд┐ рд╣рдореЗрдВ рдпрд╣ рд░рд┐рдореЛрдЯ рдпрд╛ рд╕реНрдерд╛рдиреАрдп рдбреЗрдЯрд╛ рдХреИрд╕реЗ рдорд┐рд▓рддрд╛ рд╣реИред
  • рдХреЗрд╡рд▓ рдЖрд╡рд╢реНрдпрдХ рджреГрд╢реНрдп рдбреЗрдЯрд╛ рд╣реИ
  • рдХреЗрд╡рд▓ рдПрдХ рдЪреАрдЬ рдЬрд┐рд╕реЗ рджреГрд╢реНрдп рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП, рд╡рд╣ рдпрд╣ рдбреЗрдЯрд╛ рджрд┐рдЦрд╛рддрд╛ рд╣реИред

рдЬрдм рдореИрдВрдиреЗ рд╕рд┐рд░реНрдл рдПрдВрдбреНрд░реЙрдЗрдб рдкрд░ рд╡рд┐рдХрд╛рд╕ рдХрд░рдирд╛ рд╢реБрд░реВ рдХрд┐рдпрд╛, рддреЛ рдореИрдВ рд╕реЛрдЪ рд░рд╣рд╛ рдерд╛ рдХрд┐ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдСрдлрд╝рд▓рд╛рдЗрди рдХреИрд╕реЗ рдХрд╛рдо рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рдбреЗрдЯрд╛ рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝реЗрд╢рди рдХреИрд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред рдПрдХ рдЕрдЪреНрдЫрд╛ рдЕрдиреБрдкреНрд░рдпреЛрдЧ рд╡рд╛рд╕реНрддреБрдХрд▓рд╛ рд╣рдореЗрдВ рдЖрд╕рд╛рдиреА рд╕реЗ рдРрд╕рд╛ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЬрдм ViewModel рдореЗрдВ loadRepositories рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ рдпрджрд┐ рдХреЛрдИ рдЗрдВрдЯрд░рдиреЗрдЯ рдХрдиреЗрдХреНрд╢рди рд╣реИ, рддреЛ GitRepoRepositories рджреВрд░рд╕реНрде рдбреЗрдЯрд╛ рд╕реНрд░реЛрдд рд╕реЗ рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░ рд╕рдХрддрд╛ рд╣реИ рдФрд░ рдЗрд╕реЗ рд╕реНрдерд╛рдиреАрдп рдбреЗрдЯрд╛ рд╕реНрд░реЛрдд рдореЗрдВ рд╕рд╣реЗрдЬ рд╕рдХрддрд╛ рд╣реИред рдЬрдм рдлрд╝реЛрди рдСрдлрд╝рд▓рд╛рдЗрди рд╣реЛрддрд╛ рд╣реИ, GitRepoRepository рд╕реНрдерд╛рдиреАрдп рд╕рдВрдЧреНрд░рд╣рдг рд╕реЗ рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░ рд╕рдХрддрд╛ рд╣реИред рдЗрд╕рд▓рд┐рдП, рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдореЗрдВ рд░рд┐рдореЛрдЯрдбреИрд╕ рд╕реЛрд░реНрд╕ рдФрд░ рд▓реЛрдХрд▓рдбреЙрдЯ рд╕реЛрд░реНрд╕ рдХреЗ рддрд░реНрдХ рдФрд░ рд▓реЙрдЬрд┐рдХ рдкреНрд░реЛрд╕реЗрд╕рд┐рдВрдЧ рд╣реЛрдиреА рдЪрд╛рд╣рд┐рдП рдЬрд╣рд╛рдВ рд╕реЗ рдпрд╣ рдбреЗрдЯрд╛ рдЖрдирд╛ рдЪрд╛рд╣рд┐рдПред

рд╕реНрдерд╛рдиреАрдп рдбреЗрдЯрд╛ рд╕реНрд░реЛрдд рдЬреЛрдбрд╝реЗрдВ:

GitRepoLocalDataSource.kt
 class GitRepoLocalDataSource { fun getRepositories(onRepositoryReadyCallback: OnRepoLocalReadyCallback) { var arrayList = ArrayList<Repository>() arrayList.add(Repository("First From Local", "Owner 1", 100, false)) arrayList.add(Repository("Second From Local", "Owner 2", 30, true)) arrayList.add(Repository("Third From Local", "Owner 3", 430, false)) Handler().postDelayed({ onRepositoryReadyCallback.onLocalDataReady(arrayList) }, 2000) } fun saveRepositories(arrayList: ArrayList<Repository>){ //todo save repositories in DB } } interface OnRepoLocalReadyCallback { fun onLocalDataReady(data: ArrayList<Repository>) } 


рдпрд╣рд╛рдВ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рджреЛ рд╡рд┐рдзрд┐рдпрд╛рдБ рд╣реИрдВ: рдкрд╣рд▓рд╛, рдЬреЛ рдирдХрд▓реА рд╕реНрдерд╛рдиреАрдп рдбреЗрдЯрд╛ рд▓реМрдЯрд╛рддрд╛ рд╣реИ, рдФрд░ рджреВрд╕рд░рд╛, рдХрд╛рд▓реНрдкрдирд┐рдХ рдбреЗрдЯрд╛ рд╕рдВрдЧреНрд░рд╣рдг рдХреЗ рд▓рд┐рдПред

рдПрдХ рджреВрд░рд╕реНрде рдбреЗрдЯрд╛ рд╕реНрд░реЛрдд рдЬреЛрдбрд╝реЗрдВ :

GitRepoRemoteDataSource.kt
 class GitRepoRemoteDataSource { fun getRepositories(onRepositoryReadyCallback: OnRepoRemoteReadyCallback) { var arrayList = ArrayList<Repository>() arrayList.add(Repository("First from remote", "Owner 1", 100, false)) arrayList.add(Repository("Second from remote", "Owner 2", 30, true)) arrayList.add(Repository("Third from remote", "Owner 3", 430, false)) Handler().postDelayed({ onRepositoryReadyCallback.onRemoteDataReady(arrayList) }, 2000) } } interface OnRepoRemoteReadyCallback { fun onRemoteDataReady(data: ArrayList<Repository>) } 


рдХреЗрд╡рд▓ рдПрдХ рд╣реА рддрд░реАрдХрд╛ рд╣реИ рдЬреЛ рдирдХрд▓реА рд░рд┐рдореЛрдЯ рдбреЗрдЯрд╛ рд▓реМрдЯрд╛рддрд╛ рд╣реИ ред

рдЕрдм рд╣рдо рдЕрдкрдиреЗ рднрдВрдбрд╛рд░ рдореЗрдВ рдХреБрдЫ рддрд░реНрдХ рдЬреЛрдбрд╝ рд╕рдХрддреЗ рд╣реИрдВ:

GitRepoRepository.kt
 class GitRepoRepository { val localDataSource = GitRepoLocalDataSource() val remoteDataSource = GitRepoRemoteDataSource() fun getRepositories(onRepositoryReadyCallback: OnRepositoryReadyCallback) { remoteDataSource.getRepositories( object : OnRepoRemoteReadyCallback { override fun onDataReady(data: ArrayList<Repository>) { localDataSource.saveRepositories(data) onRepositoryReadyCallback.onDataReady(data) } }) } } interface OnRepositoryReadyCallback { fun onDataReady(data: ArrayList<Repository>) } 


рдЗрд╕ рдкреНрд░рдХрд╛рд░, рд╕реНрд░реЛрддреЛрдВ рдХреЛ рд╕рд╛рдЭрд╛ рдХрд░рддреЗ рд╣реБрдП, рд╣рдо рдЖрд╕рд╛рдиреА рд╕реЗ рд╕реНрдерд╛рдиреАрдп рд╕реНрддрд░ рдкрд░ рдбреЗрдЯрд╛ рдХреЛ рдмрдЪрд╛рддреЗ рд╣реИрдВред

рдХреНрдпрд╛ рд╣реЛрдЧрд╛ рдпрджрд┐ рдЖрдкрдХреЛ рдХреЗрд╡рд▓ рдиреЗрдЯрд╡рд░реНрдХ рд╕реЗ рдбреЗрдЯрд╛ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдЖрдкрдХреЛ рдЕрднреА рднреА рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдЯреЗрдореНрдкрд▓реЗрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ? рд╣рд╛рдВред рдпрд╣ рдХреЛрдб рдкрд░реАрдХреНрд╖рдг рдХреЛ рдЖрд╕рд╛рди рдмрдирд╛рддрд╛ рд╣реИ, рдЕрдиреНрдп рдбреЗрд╡рд▓рдкрд░реНрд╕ рдЖрдкрдХреЗ рдХреЛрдб рдХреЛ рдмреЗрд╣рддрд░ рдврдВрдЧ рд╕реЗ рд╕рдордЭ рд╕рдХрддреЗ рд╣реИрдВ, рдФрд░ рдЖрдк рдЗрд╕реЗ рддреЗрдЬреА рд╕реЗ рд╕рдорд░реНрдерди рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ!

...

Android рдкреНрд░рдмрдВрдзрдХ рдЖрд╡рд░рдг


рдХреНрдпрд╛ рд╣реЛрдЧрд╛ рдпрджрд┐ рдЖрдк GitRepoRepository рдореЗрдВ рдЕрдкрдиреЗ рдЗрдВрдЯрд░рдиреЗрдЯ рдХрдиреЗрдХреНрд╢рди рдХреА рдЬрд╛рдВрдЪ рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рдпрд╣ рдЬрд╛рдирдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐ рдбреЗрдЯрд╛ рдХрд╣рд╛рдБ рд╕реЗ рдЕрдиреБрд░реЛрдз рдХрд░рдирд╛ рд╣реИ? рд╣рдордиреЗ рдкрд╣рд▓реЗ рд╣реА рдХрд╣рд╛ рдХрд┐ рд╣рдореЗрдВ ViewModel рдФрд░ Model рдореЗрдВ рдХреЛрдИ Android-рд╕рдВрдмрдВрдзрд┐рдд рдХреЛрдб рдирд╣реАрдВ рд░рдЦрдирд╛ рдЪрд╛рд╣рд┐рдП , рдЗрд╕рд▓рд┐рдП рдЗрд╕ рд╕рдорд╕реНрдпрд╛ рд╕реЗ рдХреИрд╕реЗ рдирд┐рдкрдЯреЗрдВ?

рдЖрдЗрдП рдПрдХ рдЗрдВрдЯрд░рдиреЗрдЯ рдХрдиреЗрдХреНрд╢рди рдХреЗ рд▓рд┐рдП рдПрдХ рдЖрд╡рд░рдг рд▓рд┐рдЦреЗрдВ:

NetManager.kt (рдПрдХ рд╕рдорд╛рди рд╕рдорд╛рдзрд╛рди рдЕрдиреНрдп рдкреНрд░рдмрдВрдзрдХреЛрдВ рдкрд░ рд▓рд╛рдЧреВ рд╣реЛрддрд╛ рд╣реИ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, NfcManager рдХреЗ рд▓рд┐рдП)
 class NetManager(private var applicationContext: Context) { private var status: Boolean? = false val isConnectedToInternet: Boolean? get() { val conManager = applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager val ni = conManager.activeNetworkInfo return ni != null && ni.isConnected } } 


рдпрд╣ рдХреЛрдб рддрднреА рдХрд╛рдо рдХрд░реЗрдЧрд╛ рдЬрдм рд╣рдо рдкреНрд░рдХрдЯ рд╣реЛрдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рдЬреЛрдбрд╝рддреЗ рд╣реИрдВ:

 <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> 

рд▓реЗрдХрд┐рди рдпрд╣ рдХреИрд╕реЗ рднрдВрдбрд╛рд░ рдореЗрдВ рдПрдХ рдЙрджрд╛рд╣рд░рдг рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП, рдЕрдЧрд░ рд╣рдо рд╕рдВрджрд░реНрдн (рдХреА рдЬрд░реВрд░рдд рдирд╣реАрдВ рд╣реИ рд╕рдВрджрд░реНрдн )? рд╣рдо рдЗрд╕реЗ рдирд┐рд░реНрдорд╛рддрд╛ рдореЗрдВ рдЕрдиреБрд░реЛрдз рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:

GitRepoRepository.kt
 class GitRepoRepository (context: Context){ val localDataSource = GitRepoLocalDataSource() val remoteDataSource = GitRepoRemoteDataSource() val netManager = NetManager(context) fun getRepositories(onRepositoryReadyCallback: OnRepositoryReadyCallback) { remoteDataSource.getRepositories(object : OnRepoRemoteReadyCallback { override fun onDataReady(data: ArrayList<Repository>) { localDataSource.saveRepositories(data) onRepositoryReadyCallback.onDataReady(data) } }) } } interface OnRepositoryReadyCallback { fun onDataReady(data: ArrayList<Repository>) } 


рд╣рдордиреЗ ViewModel рдореЗрдВ рдирдП GitRepoRepository рдЙрджрд╛рд╣рд░рдг рд╕реЗ рдкрд╣рд▓реЗ рдмрдирд╛рдпрд╛ рдерд╛ред рдЬрдм рд╣рдо NetManager рдХреЗ рд▓рд┐рдП рд╕рдВрджрд░реНрдн рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ, рддреЛ рдЕрдм ViewModel рдореЗрдВ NetManager рдХреИрд╕реЗ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ ? рдЖрдк AndroidecModel рдХрд╛ рдЙрдкрдпреЛрдЧ рд▓рд╛рдЗрдлрд╝рд╕рд╛рдЗрдХрд▓-рдЬрд╛рдЧрд░реВрдХ рдШрдЯрдХреЛрдВ рдХреА рд▓рд╛рдЗрдмреНрд░реЗрд░реА рд╕реЗ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдЬрд┐рд╕рдХрд╛ рдПрдХ рд╕рдВрджрд░реНрдн рд╣реИ ред рдпрд╣ рдЕрдиреБрдкреНрд░рдпреЛрдЧ рдХрд╛ рд╕рдВрджрд░реНрдн рд╣реИ, рди рдХрд┐ рдЧрддрд┐рд╡рд┐рдзрд┐ред

MainViewModel.kt
 class MainViewModel : AndroidViewModel { constructor(application: Application) : super(application) var gitRepoRepository: GitRepoRepository = GitRepoRepository(NetManager(getApplication())) val text = ObservableField("old data") val isLoading = ObservableField(false) var repositories = MutableLiveData<ArrayList<Repository>>() fun loadRepositories() { isLoading.set(true) gitRepoRepository.getRepositories(object : OnRepositoryReadyCallback { override fun onDataReady(data: ArrayList<Repository>) { isLoading.set(false) repositories.value = data } }) } } 


рдЗрд╕ рд▓рд╛рдЗрди рдореЗрдВ

 constructor(application: Application) : super(application) 

рд╣рдордиреЗ MainViewModel рдХреЗ рд▓рд┐рдП рдПрдХ рдХрдВрд╕реНрдЯреНрд░рдХреНрдЯрд░ рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд┐рдпрд╛ ред рдпрд╣ рдЖрд╡рд╢реНрдпрдХ рд╣реИ рдХреНрдпреЛрдВрдХрд┐ AndroidViewModel рдЕрдкрдиреЗ рдирд┐рд░реНрдорд╛рддрд╛ рдореЗрдВ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рдПрдХ рдЙрджрд╛рд╣рд░рдг рдХрд╛ рдЕрдиреБрд░реЛрдз рдХрд░рддрд╛ рд╣реИ ред рдЗрд╕рд▓рд┐рдП, рд╣рдорд╛рд░реЗ рдХрдВрд╕реНрдЯреНрд░рдХреНрдЯрд░ рдореЗрдВ, рд╣рдо рдЙрд╕ рд╕реБрдкрд░ рдореЗрдердб рдХреЛ рдХрд╣рддреЗ рд╣реИрдВ рдЬреЛ AndroidViewModel рдХрдВрд╕реНрдЯреНрд░рдХреНрдЯрд░ рдХреЛ рдХреЙрд▓ рдХрд░рддрд╛ рд╣реИ , рдЬрд╣рд╛рдБ рд╕реЗ рд╣рдореЗрдВ рд╡рд┐рд░рд╛рд╕рдд рдорд┐рд▓рддреА рд╣реИред

рдиреЛрдЯ: рдпрджрд┐ рд╣рдо рдХрд░рддреЗ рд╣реИрдВ рддреЛ рд╣рдо рдПрдХ рдкрдВрдХреНрддрд┐ рд╕реЗ рдЫреБрдЯрдХрд╛рд░рд╛ рдкрд╛ рд╕рдХрддреЗ рд╣реИрдВ:

 class MainViewModel(application: Application) : AndroidViewModel(application) { ... } 

рдФрд░ рдЕрдм рд╣рдорд╛рд░реЗ рдкрд╛рд╕ GitRepoRepository рдореЗрдВ NetManager рдЙрджрд╛рд╣рд░рдг рд╣реИ , рд╣рдо рдЗрдВрдЯрд░рдиреЗрдЯ рдХрдиреЗрдХреНрд╢рди рдХреА рдЬрд╛рдВрдЪ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:

GitRepoRepository.kt
 class GitRepoRepository(val netManager: NetManager) { val localDataSource = GitRepoLocalDataSource() val remoteDataSource = GitRepoRemoteDataSource() fun getRepositories(onRepositoryReadyCallback: OnRepositoryReadyCallback) { netManager.isConnectedToInternet?.let { if (it) { remoteDataSource.getRepositories(object : OnRepoRemoteReadyCallback { override fun onRemoteDataReady(data: ArrayList<Repository>) { localDataSource.saveRepositories(data) onRepositoryReadyCallback.onDataReady(data) } }) } else { localDataSource.getRepositories(object : OnRepoLocalReadyCallback { override fun onLocalDataReady(data: ArrayList<Repository>) { onRepositoryReadyCallback.onDataReady(data) } }) } } } } interface OnRepositoryReadyCallback { fun onDataReady(data: ArrayList<Repository>) } 


рдЗрд╕ рдкреНрд░рдХрд╛рд░, рдпрджрд┐ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдЗрдВрдЯрд░рдиреЗрдЯ рдХрдиреЗрдХреНрд╢рди рд╣реИ, рддреЛ рд╣рдо рд╣рдЯрд╛рдП рдЧрдП рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВрдЧреЗ рдФрд░ рдЗрд╕реЗ рд╕реНрдерд╛рдиреАрдп рд░реВрдк рд╕реЗ рд╕рд╣реЗрдЬреЗрдВрдЧреЗред рдпрджрд┐ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдЗрдВрдЯрд░рдиреЗрдЯ рдХрдиреЗрдХреНрд╢рди рдирд╣реАрдВ рд╣реИ, рддреЛ рд╣рдореЗрдВ рд╕реНрдерд╛рдиреАрдп рдбреЗрдЯрд╛ рдорд┐рд▓реЗрдЧрд╛ред

рдХреЛрдЯрд▓рд┐рди рдиреЛрдЯ : рд▓реЗрдЯ рд╕реНрдЯреЗрдЯрдореЗрдВрдЯ рдирд▓ рдХреЗ рд▓рд┐рдП рдЬрд╛рдБрдЪ рдХрд░рддрд╛ рд╣реИ рдФрд░ рдЗрд╕рдХреЗ рдЕрдВрджрд░ рдПрдХ рд╡реИрд▓реНрдпреВ рджреЗрддрд╛ рд╣реИ ред

рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд▓реЗрдЦреЛрдВ рдореЗрдВ рд╕реЗ рдПрдХ рдореЗрдВ рдореИрдВ рдирд┐рд░реНрднрд░рддрд╛ рдЗрдВрдЬреЗрдХреНрд╢рди рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд▓рд┐рдЦреВрдВрдЧрд╛ рдХрд┐ рд╡реНрдпреВрдореЙрдбрд▓ рдореЗрдВ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдЗрдВрд╕реНрдЯреЗрдВрд╕реЗрд╕ рдмрдирд╛рдирд╛ рдХрд┐рддрдирд╛ рдмреБрд░рд╛ рд╣реИ, рдФрд░ рдПрдВрдбреНрд░реЙрдЗрдб рд╡реНрдпреВрдореЙрдбрд▓ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рд╕реЗ рдХреИрд╕реЗ рдмрдЪреЗрдВред рдореИрдВ рдмрдбрд╝реА рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рдЙрди рд╕рдорд╕реНрдпрд╛рдУрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рднреА рд▓рд┐рдЦреВрдВрдЧрд╛ рдЬреЛ рдЕрдм рд╣рдорд╛рд░реЗ рдХреЛрдб рдореЗрдВ рд╣реИрдВред рдореИрдВрдиреЗ рдЙрдиреНрд╣реЗрдВ рдПрдХ рдХрд╛рд░рдг рдХреЗ рд▓рд┐рдП рдЫреЛрдбрд╝ рджрд┐рдпрд╛ ...

рдореИрдВ рдЖрдкрдХреЛ рд╕рдорд╕реНрдпрд╛рдПрдВ рджрд┐рдЦрд╛рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ рддрд╛рдХрд┐ рдЖрдк рд╕рдордЭ рд╕рдХреЗрдВ рдХрд┐ рдпреЗ рд╕рднреА рдкреБрд╕реНрддрдХрд╛рд▓рдп рд▓реЛрдХрдкреНрд░рд┐рдп рдХреНрдпреЛрдВ рд╣реИрдВ рдФрд░ рдЖрдк рдЙрдирдХрд╛ рдЙрдкрдпреЛрдЧ рдХреНрдпреЛрдВ рдХрд░рддреЗ рд╣реИрдВред

рдкреБрдирд╢реНрдЪ рдореИрдВ рдирдХреНрд╢рд╛рдХрд╛рд░ (рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЕрдкрдирд╛ рдорди рдмрджрд▓ рджрд┐рдпрд╛ рдорд╛рдирдЪрд┐рддреНрд░рдХрд╛рд░реЛрдВ )ред рдореИрдВрдиреЗ рдЗрд╕реЗ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд▓реЗрдЦреЛрдВ рдореЗрдВ рд╢рд╛рдорд┐рд▓ рдХрд░рдиреЗ рдХрд╛ рдирд┐рд░реНрдгрдп рд▓рд┐рдпрд╛ред

Source: https://habr.com/ru/post/hi432826/


All Articles