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

рдЗрд╕рд▓рд┐рдП рд╕рднреА рдХреЛ рдирдорд╕реНрдХрд╛рд░!
рдореЗрд░рд╛ рдирд╛рдо рдЕрд▓реЗрдХреНрд╕реА рд╣реИ, рдореИрдВ Home Credit Bank рдореЗрдВ рдПрдХ Android рдбреЗрд╡рд▓рдкрд░ рд╣реВрдВред
рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ, рдореИрдВ ViewModels рд╕реЗ рд▓реЗрдХрд░ Views (рдХреНрд░рд┐рдпрд╛рдПрдБ / Fragments) рддрдХ рдХреА рдШрдЯрдирд╛рдУрдВ рдХреЛ рднреЗрдЬрдиреЗ рдФрд░ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХрд╛ рд╣рдорд╛рд░рд╛ рддрд░реАрдХрд╛ рд╕рд╛рдЭрд╛ рдХрд░реВрдБрдЧрд╛ред
рд╣рдорд╛рд░реЗ рдЖрд╡реЗрджрди рдореЗрдВ "рд╣реЛрдо рдХреНрд░реЗрдбрд┐рдЯ рдмреИрдВрдХ рд╕реЗ рдХрд┐рд╕реНрдд рдорд╛рд▓" рд╣рдо рдЯреБрдХрдбрд╝реЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП рд╣рдо рдЙрдирдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмрд╛рдд рдХрд░реЗрдВрдЧреЗ, рд▓реЗрдХрд┐рди рдЧрддрд┐рд╡рд┐рдзрд┐ рдХреЗ рд▓рд┐рдП рднреА рд╕рдм рдХреБрдЫ рдкреНрд░рд╛рд╕рдВрдЧрд┐рдХ рд╣реИредрд╣рдо рдХреНрдпрд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ?
рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдПрдХ Fragment рд╣реИ, рдЬрд┐рд╕рдореЗрдВ рдХрдИ ViewModel рд╢рд╛рдорд┐рд▓ рд╣реИрдВ, рдбреЗрдЯрд╛
DataBinding
рджреНрд╡рд╛рд░рд╛ рдмрд╛рдзреНрдп рд╣реИред рд╕рднреА рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдИрд╡реЗрдВрдЯреНрд╕ ViewModel рдкреНрд░рд╛рдкреНрдд рдХрд░рддреЗ рд╣реИрдВред рдпрджрд┐ рдИрд╡реЗрдВрдЯ рдПрдХ рдиреЗрд╡рд┐рдЧреЗрд╢рди рдПрдХ рд╣реИ: рдЖрдкрдХреЛ рдПрдХ рдФрд░ рдЯреБрдХрдбрд╝рд╛ / рдЧрддрд┐рд╡рд┐рдзрд┐ рдЦреЛрд▓рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ,
AlertDialog
,
AlertDialog
, рдЕрдиреБрдорддрд┐рдпреЛрдВ рдХреЗ рд▓рд┐рдП рдПрдХ рд╕рд┐рд╕реНрдЯрдо рдЕрдиреБрд░реЛрдз рдЗрддреНрдпрд╛рджрд┐ рджрд┐рдЦрд╛рдПрдВ, рдлрд┐рд░ рдЗрд╕ рддрд░рд╣ рдХреЗ рдЖрдпреЛрдЬрди рдХреЛ рдЯреБрдХрдбрд╝реЗ рдореЗрдВ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред
рдФрд░ рдХреНрдпрд╛, рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рд╕рдорд╕реНрдпрд╛ рд╣реИ?
рджреГрд╢реНрдп рдФрд░ ViewModels рдЬреАрд╡рди рдЪрдХреНрд░ рдЕрд╕рдВрдмрдВрдзрд┐рдд рд╣реИрдВред рд╢реНрд░реЛрддрд╛рдУрдВ рдХреЗ рд╕рд╛рде рдмрдВрдзрдирд╛ рдЕрд╕рдВрднрд╡ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ ViewModel рдХреЛ рдЯреБрдХрдбрд╝реЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХреБрдЫ рднреА рдирд╣реАрдВ рдкрддрд╛ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП, рдФрд░ рдЗрд╕рдореЗрдВ рдЯреБрдХрдбрд╝реЛрдВ рдХрд╛ рд▓рд┐рдВрдХ рднреА рдирд╣реАрдВ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП, рдЕрдиреНрдпрдерд╛, рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рдЬрд╛рдирддреЗ рд╣реИрдВ, рд╕реНрдореГрддрд┐ "
рдЖрдирдиреНрджрд┐рдд " рд╣реЛрдиреЗ рд▓рдЧреЗрдЧреАред
Fragments рдФрд░ ViewModels рдХреЗ рдмреАрдЪ рдмрд╛рддрдЪреАрдд рдХреЗ рд▓рд┐рдП рдорд╛рдирдХ рджреГрд╖реНрдЯрд┐рдХреЛрдг ViewModel рдореЗрдВ рд╕реНрдерд┐рдд
LiveData
рд╕рджрд╕реНрдпрддрд╛ рд▓реЗрдирд╛ рд╣реИред
LiveData
рдорд╛рдзреНрдпрдо рд╕реЗ рд╕реАрдзреЗ рдШрдЯрдирд╛рдУрдВ рдХреЛ рдкреНрд░рд╕рд╛рд░рд┐рдд рдХрд░рдирд╛ рдЕрд╕рдВрднрд╡ рд╣реИ, рдЗрд╕ рддрдереНрдп рдХреЗ рдХрд╛рд░рдг рдХрд┐ рдпрд╣ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдзреНрдпрд╛рди рдореЗрдВ рдирд╣реАрдВ рд░рдЦрддрд╛ рд╣реИ рдХрд┐ рдХреНрдпрд╛ рдШрдЯрдирд╛ рдкрд╣рд▓реЗ рд╣реА рдкреВрд░реА рд╣реЛ рдЪреБрдХреА рд╣реИ рдпрд╛ рдирд╣реАрдВред
рдХреНрдпрд╛ рд╕рдорд╛рдзрд╛рди рдореМрдЬреВрдж рд╣реИрдВ:
1.
SingleLiveEvent
рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ
рдкреЗрд╢реЗрд╡рд░реЛрдВ: рдШрдЯрдирд╛ рдХреЛ рдПрдХ рдмрд╛рд░ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред
рд╡рд┐рдкрдХреНрд╖: рдПрдХ рдШрдЯрдирд╛ - рдПрдХ
SingleLiveEvent
ред рдмрдбрд╝реА рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рдШрдЯрдирд╛рдУрдВ рдХреЗ рд╕рд╛рде, рдПрди рдЗрд╡реЗрдВрдЯ-рдСрдмреНрдЬреЗрдХреНрдЯ рд╡реНрдпреВрдореЙрдбрд▓ рдореЗрдВ рджрд┐рдЦрд╛рдИ рджреЗрддреЗ рд╣реИрдВ, рдЬрд┐рдирдореЗрдВ рд╕реЗ рдкреНрд░рддреНрдпреЗрдХ рдХреЛ рдЯреБрдХрдбрд╝реЗ рдореЗрдВ рд╕рдмреНрд╕рдХреНрд░рд╛рдЗрдм рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред
2. рдПрдХ рдЕрдЪреНрдЫрд╛
рдЙрджрд╛рд╣рд░рдг ред
рдкреЗрд╢реЗрд╡рд░реЛрдВ: рдПрдХ рдШрдЯрдирд╛ рдХреЛ рдПрдХ рдмрд╛рд░ рднреА рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЖрдк рдбреЗрдЯрд╛ рдХреЛ рд╡реНрдпреВрдХреЛрдб рд╕реЗ рдЯреБрдХрдбрд╝реЗ рдореЗрдВ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред
рд╡рд┐рдкрдХреНрд╖: рдШрдЯрдирд╛ рдореЗрдВ рдбреЗрдЯрд╛ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдЕрдЧрд░ рдЖрдкрдХреЛ рдбреЗрдЯрд╛ рдХреЗ рдмрд┐рдирд╛ рдХрд┐рд╕реА рдШрдЯрдирд╛ рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ
(val content: T)
, рддреЛ рдЖрдкрдХреЛ рдПрдХ рдФрд░ рд╡рд░реНрдЧ рдмрдирд╛рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреАред рдпрд╣ рдПрдХ рдкреНрд░рдХрд╛рд░ рдХреА рдШрдЯрдирд╛ рдХреЛ рдПрдХ рдмрд╛рд░ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдХреА рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╣рд▓ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ (рдШрдЯрдирд╛ рдХреЛ рдПрдХ рдмрд╛рд░ рд╣реА рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдЗрд╕ рдкреНрд░рдХрд╛рд░ рдХреА рдШрдЯрдирд╛ рдХреЛ рдХрдИ рдмрд╛рд░ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ рдХреНрдпреЛрдВрдХрд┐ рд╣рдо рдЗрд╕реЗ рд╡реНрдпреВрдореЙрдбрд▓ рд╕реЗ рдЪрд▓рд╛рддреЗ рд╣реИрдВ)ред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдПрди-рдЕрдиреБрд░реЛрдз рдПрд╕рд┐рдВрдХреНрд░реЛрдирд╕ рд░реВрдк рд╕реЗ рдЪрд▓рддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдХреЛрдИ рдиреЗрдЯрд╡рд░реНрдХ рдирд╣реАрдВ рд╣реИред рдкреНрд░рддреНрдпреЗрдХ рдЕрдиреБрд░реЛрдз рдиреЗрдЯрд╡рд░реНрдХ рддреНрд░реБрдЯрд┐ рдХреЗ рд╕рд╛рде рд╡рд╛рдкрд╕ рдЖ рдЬрд╛рдПрдЧрд╛, рдФрд░ рдиреЗрдЯрд╡рд░реНрдХ рддреНрд░реБрдЯрд┐ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдПрди рдШрдЯрдирд╛рдУрдВ рдХреЗ рдПрдХ рдЯреБрдХрдбрд╝реЗ рдореЗрдВ рдЦреАрдВрдЪ рд▓реЗрдЧрд╛, рдПрди рдЕрд▓рд░реНрдЯ рдЯреБрдХрдбрд╝реЗ рдореЗрдВ рдЦреБрд▓ рдЬрд╛рдПрдЧрд╛ред рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЗрд╕ рддрд░рд╣ рдХреЗ рдирд┐рд░реНрдгрдп рдХреЛ рдордВрдЬреВрд░реА рдирд╣реАрдВ рджреЗрдЧрд╛ :)ред рд╣рдореЗрдВ рдЗрд╕ рддреНрд░реБрдЯрд┐ рдХреЗ рд╕рд╛рде рдПрдХ рдмрд╛рд░ рд╕рдВрджреЗрд╢ рджрд┐рдЦрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред рджреВрд╕рд░реЗ рд╢рдмреНрджреЛрдВ рдореЗрдВ, рдЗрд╕ рдкреНрд░рдХрд╛рд░ рдХреЗ рдЖрдпреЛрдЬрди рдХреЛ рдПрдХ рдмрд╛рд░ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред
рдирд┐рд░реНрдгрдп
рд╣рдо рдЖрдзрд╛рд░ рдХреЗ рд░реВрдк рдореЗрдВ рдШрдЯрдирд╛ рд╕реЗ рдирд┐рдкрдЯрдиреЗ рдХреА рдЬрд╛рдирдХрд╛рд░реА рдХреЛ рдмрдЪрд╛рдиреЗ рдХреЗ рд▓рд┐рдП
SingleLiveEvent
рдХрд╛ рд╡рд┐рдЪрд╛рд░ рд▓реЗрддреЗ рд╣реИрдВред
рд╕рдВрднрд╛рд╡рд┐рдд рдИрд╡реЗрдВрдЯ рдкреНрд░рдХрд╛рд░реЛрдВ рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░реЗрдВ
enum class Type { EXECUTE_WITHOUT_LIMITS,
рдПрдХ рдИрд╡реЗрдВрдЯ рдмреЗрд╕ рдХреНрд▓рд╛рд╕ рдмрдирд╛рдПрдВ - NavigationEvent
isHandled
рдЗрдВрдЧрд┐рдд рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдХреНрдпрд╛ рдШрдЯрдирд╛ рдкреНрд░рд╛рдкреНрдд рд╣реБрдИ рдереА (рд╣рдо рдорд╛рдирддреЗ рд╣реИрдВ рдХрд┐ рдпрд╣ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ рдпрджрд┐ рдкрд░реНрдпрд╡реЗрдХреНрд╖рдХ рдХреЛ рдЯреБрдХрдбрд╝реЗ рдореЗрдВ рдкреНрд░рд╛рдкреНрдд рд╣реБрдЖ рдерд╛)ред
open class NavigationEvent(var isHandled: Boolean = false, var type: Events.Type)
рдПрдХ Emitter
рд╡рд░реНрдЧ рдмрдирд╛рдПрдВ - Emitter
рдЗрд╡реЗрдВрдЯ рдПрдорд┐рдЯрд░ рдХреНрд▓рд╛рд╕ рдХреЛ
LiveData
<
NavigationEvent
> рд╕реЗ рд╡рд┐рд░рд╛рд╕рдд рдореЗрдВ рдорд┐рд▓рд╛ рд╣реИред рдЗрд╕ рд╡рд░реНрдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ ViewModel рдореЗрдВ рдШрдЯрдирд╛рдУрдВ рдХреЛ рднреЗрдЬрдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред
class Emitter : MutableLiveData<NavigationEvent>() { private val waitingEvents: ArrayList<NavigationEvent> = ArrayList() private var isActive = false override fun onInactive() { isActive = false } override fun onActive() { isActive = true val postingEvents = ArrayList<NavigationEvent>() waitingEvents .forEach { if (hasObservers()) { this.value = it postingEvents.add(it) } }.also { waitingEvents.removeAll(postingEvents) } } private fun newEvent(event: NavigationEvent, type: Type) { event.type = type this.value = when (type) { Type.EXECUTE_WITHOUT_LIMITS, Type.EXECUTE_ONCE -> if (hasObservers()) event else null Type.WAIT_OBSERVER_IF_NEEDED, Type.WAIT_OBSERVER_IF_NEEDED_AND_EXECUTE_ONCE -> { if (hasObservers() && isActive) event else { waitingEvents.add(event) null } } } } fun clearWaitingEvents() = waitingEvents.clear() }
isActive
- рд╣рдореЗрдВ рдпрд╣ рд╕рдордЭрдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдХрд┐ рдХреНрдпрд╛ рдХрдо рд╕реЗ рдХрдо рдПрдХ
Observer
рдХреЛ
Emitter
рд╕рджрд╕реНрдпрддрд╛ рджреА рдЧрдИ рд╣реИред рдФрд░ рдЙрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ рдЬрдм рдЧреНрд░рд╛рд╣рдХ рджрд┐рдЦрд╛рдИ рджрд┐рдпрд╛ рд╣реИ рдФрд░ рдЙрд╕рдХреЗ рдЗрдВрддрдЬрд╛рд░ рдХреА рдШрдЯрдирд╛рдПрдВ рдЬрдорд╛ рд╣реЛ рдЧрдИ рд╣реИрдВ, рд╣рдо рдЗрди рдШрдЯрдирд╛рдУрдВ рдХреЛ рднреЗрдЬрддреЗ рд╣реИрдВред рдПрдХ рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╕реНрдкрд╖реНрдЯреАрдХрд░рдг: рдИрд╡реЗрдВрдЯ рднреЗрдЬрдирд╛ рдЖрд╡рд╢реНрдпрдХ рдирд╣реАрдВ рд╣реИред рдпрд╣
this.postValue(event)
рдорд╛рдзреНрдпрдо рд╕реЗ рдирд╣реАрдВ, рдмрд▓реНрдХрд┐ рд╕реЗрдЯрд░ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЗрд╕
this.value = event
ред рдЕрдиреНрдпрдерд╛, рдЧреНрд░рд╛рд╣рдХ рдХреЛ рд╕реВрдЪреА рдореЗрдВ рдХреЗрд╡рд▓ рдЕрдВрддрд┐рдо рдШрдЯрдирд╛ рдкреНрд░рд╛рдкреНрдд рд╣реЛрдЧреАред
рдПрдХ рдирдИ рдШрдЯрдирд╛ рднреЗрдЬрдиреЗ рдХреА рд╡рд┐рдзрд┐,
newEvent(event, type)
, рджреЛ рдорд╛рдкрджрдВрдбреЛрдВ рдХреЛ рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рддрд╛ рд╣реИ - рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдШрдЯрдирд╛ рд╕реНрд╡рдпрдВ рдФрд░ рдЗрд╕ рдШрдЯрдирд╛ рдХрд╛ рдкреНрд░рдХрд╛рд░ред
рд╕рднреА рдкреНрд░рдХрд╛рд░ рдХреА рдШрдЯрдирд╛рдУрдВ (рд▓рдВрдмреЗ рдирд╛рдореЛрдВ) рдХреЛ рдпрд╛рдж рди рд░рдЦрдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдЕрд▓рдЧ-рдЕрд▓рдЧ рд╕рд╛рд░реНрд╡рдЬрдирд┐рдХ рддрд░реАрдХреЗ рдмрдирд╛рдПрдВрдЧреЗ рдЬреЛ рдХреЗрд╡рд▓ рдШрдЯрдирд╛ рдХреЛ рд╣реА рд╕реНрд╡реАрдХрд╛рд░ рдХрд░реЗрдВрдЧреЗ:
class Emitter : MutableLiveData<NavigationEvent>() { тАж fun emitAndExecute(event: NavigationEvent) = newEvent(event, Type.EXECUTE_WITHOUT_LIMITS) fun emitAndExecuteOnce(event: NavigationEvent) = newEvent(event, Type.EXECUTE_ONCE) fun waitAndExecute(event: NavigationEvent) = newEvent(event, Type.WAIT_OBSERVER_IF_NEEDED) fun waitAndExecuteOnce(event: NavigationEvent) = newEvent(event, Type.WAIT_OBSERVER_IF_NEEDED_AND_EXECUTE_ONCE) }
рдФрдкрдЪрд╛рд░рд┐рдХ рд░реВрдк рд╕реЗ, рдЖрдк рдкрд╣рд▓реЗ рд╕реЗ рд╣реА ViewModel рдореЗрдВ
Emitter
рдХреЛ рд╕рдмреНрд╕рдХреНрд░рд╛рдЗрдм рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдЙрдирдХреЗ рд╣реИрдВрдбрд▓рд┐рдВрдЧ рдХреА рдкрд░рд╡рд╛рд╣ рдХрд┐рдП рдмрд┐рдирд╛ рдИрд╡реЗрдВрдЯ рдкреНрд░рд╛рдкреНрдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ (рдИрд╡реЗрдВрдЯ рдХреЛ рдкрд╣рд▓реЗ рд╣реА рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рдЪреБрдХрд╛ рд╣реИ рдпрд╛ рдирд╣реАрдВ)ред
рдПрдХ рдЗрд╡реЗрдВрдЯ рдСрдмреНрдЬрд░реНрд╡рд░ рдХреНрд▓рд╛рд╕ рдмрдирд╛рдПрдВ - EventObserver
class EventObserver(private val handlerBlock: (NavigationEvent) -> Unit) : Observer<NavigationEvent> { private val executedEvents: HashSet<String> = hashSetOf() fun clearExecutedEvents() = executedEvents.clear() override fun onChanged(it: NavigationEvent?) { when (it?.type) { Type.EXECUTE_WITHOUT_LIMITS, Type.WAIT_OBSERVER_IF_NEEDED -> { if (!it.isHandled) { it.isHandled = true it.apply(handlerBlock) } } Type.EXECUTE_ONCE, Type.WAIT_OBSERVER_IF_NEEDED_AND_EXECUTE_ONCE -> { if (it.javaClass.simpleName !in executedEvents) { if (!it.isHandled) { it.isHandled = true executedEvents.add(it.javaClass.simpleName) it.apply(handlerBlock) } } } } } }
рдпрд╣ рдСрдмреНрдЬрд░реНрд╡рд░ рдПрдХ рдЙрдЪреНрдЪ-рдХреНрд░рдо рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдПрдХ рдЗрдирдкреБрдЯ рдХреЗ рд░реВрдк рдореЗрдВ рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рддрд╛ рд╣реИ - рдШрдЯрдирд╛ рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдПрдХ рдЯреБрдХрдбрд╝рд╛ (рдиреАрдЪреЗ рдЙрджрд╛рд╣рд░рдг) рдореЗрдВ рд▓рд┐рдЦрд╛ рдЬрд╛рдПрдЧрд╛ред
clearExecutedEvents()
рд╡рд┐рдзрд┐ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдШрдЯрдирд╛рдУрдВ рдХреА рд╕рдлрд╛рдИ рдХреЗ рд▓рд┐рдП рд╡рд┐рдзрд┐ (рд╡реЗ рдЬрд┐рдиреНрд╣реЗрдВ рдПрдХ рдмрд╛рд░ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП)ред рд╕реНрдХреНрд░реАрди рдХреЛ рдЕрдкрдбреЗрдЯ рдХрд░рддреЗ рд╕рдордп рдЖрд╡рд╢реНрдпрдХ рд╣реИ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП,
swipeToRefresh()
ред
рдЦреИрд░, рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдореБрдЦреНрдп
onChange()
рд╡рд┐рдзрд┐, рдЬреЛ рддрдм рд╣реЛрддреА рд╣реИ рдЬрдм рдирдпрд╛ рдПрдорд┐рдЯрд░ рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рд╣реЛрддрд╛ рд╣реИ, рдЬрд┐рд╕рдХреЗ рд▓рд┐рдП рдпрд╣ рдкрд░реНрдпрд╡реЗрдХреНрд╖рдХ рд╕рджрд╕реНрдпрддрд╛ рд▓реЗрддрд╛ рд╣реИред
рдпрджрд┐ рдШрдЯрдирд╛ рдореЗрдВ рдХрдИ рдмрд╛рд░ рдЕрд╕реАрдорд┐рдд рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рдирд┐рд╖реНрдкрд╛рджрди рдкреНрд░рдХрд╛рд░ рд╣реЛрддрд╛ рд╣реИ, рддреЛ рд╣рдо рдЬрд╛рдВрдЪрддреЗ рд╣реИрдВ рдХрд┐ рдХреНрдпрд╛ рдШрдЯрдирд╛ рдХреЛ рдЕрдВрдЬрд╛рдо рджрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ рдФрд░ рдЗрд╕реЗ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░реЗрдВред рд╣рдо рдШрдЯрдирд╛ рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рдЗрдВрдЧрд┐рдд рдХрд░рддреЗ рд╣реИрдВ рдХрд┐ рдпрд╣ рдкреНрд░рд╛рдкреНрдд рдФрд░ рд╕рдВрд╕рд╛рдзрд┐рдд рд╣реИред
if (!it.isHandled) { it.isHandled = true it.apply(handlerBlock) }
рдпрджрд┐ рдШрдЯрдирд╛ рдЙрд╕ рдкреНрд░рдХрд╛рд░ рдХреА рд╣реИ рдЬрд┐рд╕реЗ рдПрдХ рдмрд╛рд░ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП, рддреЛ рдЬрд╛рдВрдЪреЗрдВ рдХрд┐ рдХреНрдпрд╛ рдЗрд╕ рдШрдЯрдирд╛ рдХрд╛ рд╡рд░реНрдЧ рд╣реИрд╢ рддрд╛рд▓рд┐рдХрд╛ рдореЗрдВ рд╣реИред рдпрджрд┐ рдирд╣реАрдВ, рддреЛ рдШрдЯрдирд╛ рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░реЗрдВ рдФрд░ рдЗрд╕ рдШрдЯрдирд╛ рдХреЗ рд╡рд░реНрдЧ рдХреЛ рд╣реИрд╢ рддрд╛рд▓рд┐рдХрд╛ рдореЗрдВ рдЬреЛрдбрд╝реЗрдВред
if (it.javaClass.simpleName !in executedEvents) { if (!it.isHandled) { it.isHandled = true executedEvents.add(it.javaClass.simpleName) it.apply(handlerBlock) } }
рд▓реЗрдХрд┐рди рдШрдЯрдирд╛рдУрдВ рдХреЗ рдЕрдВрджрд░ рдбреЗрдЯрд╛ рдХреИрд╕реЗ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░реЗрдВ?
рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП,
MyFragmentNavigation
рдЗрдВрдЯрд░рдлрд╝реЗрд╕
MyFragmentNavigation
, рдЬрд┐рд╕рдореЗрдВ
NavigationEvent()
рд╕реЗ рд╡рд┐рд░рд╛рд╕рдд рдореЗрдВ рдорд┐рд▓реА рдХрдХреНрд╖рд╛рдПрдВ рд╢рд╛рдорд┐рд▓ рд╣реЛрдВрдЧреАред рдЙрддреНрддреАрд░реНрдг рдорд╛рдкрджрдВрдбреЛрдВ рдХреЗ рд╕рд╛рде рдФрд░ рдмрд┐рдирд╛ рд╡рд┐рднрд┐рдиреНрди рдХрдХреНрд╖рд╛рдПрдВ рдиреАрдЪреЗ рдмрдирд╛рдИ рдЧрдИ рд╣реИрдВред
interface MyFragmentNavigation { class ShowCategoryList : NavigationEvent() class OpenProduct(val productId: String, val productName: String) : NavigationEvent() class PlayVideo(val url: String) : NavigationEvent() class ShowNetworkError : NavigationEvent() }
рдпрд╣ рд╡реНрдпрд╡рд╣рд╛рд░ рдореЗрдВ рдХреИрд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ
ViewModel рд╕реЗ рдШрдЯрдирд╛рдПрдБ рднреЗрдЬрдирд╛:
class MyViewModel : ViewModel() { val emitter = Events.Enitter() fun doOnShowCategoryListButtonClicked() = emitter.emitAndExecute(MyNavigation.ShowCategoryList()) fun doOnPlayClicked() = emitter.waitAndExecuteOnce(MyNavigation.PlayVideo(url = "https://site.com/abc")) fun doOnProductClicked() = emitter.emitAndExecute(MyNavigation.OpenProduct( productId = "123", productTitle = " Samsung") ) fun doOnNetworkError() = emitter.emitAndExecuteOnce(MyNavigation.ShowNetworkError()) fun doOnSwipeRefresh(){ emitter.clearWaitingEvents() ..
рдПрдХ рдЯреБрдХрдбрд╝реЗ рдореЗрдВ рдШрдЯрдирд╛рдПрдБ рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛:
class MyFragment : Fragment() { private val navigationEventsObserver = Events.EventObserver { event -> when (event) { is MyFragmentNavigation.ShowCategoryList -> ShowCategoryList() is MyFragmentNavigation.PlayVideo -> videoPlayerView.loadUrl(event.url) is MyFragmentNavigation.OpenProduct -> openProduct(id = event.productId, name = event.otherInfo) is MyFragmentNavigation.ShowNetworkError -> showNetworkErrorAlert() } } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState)
рд╕рдВрдХреНрд╖реЗрдк рдореЗрдВ, рд╣рдореЗрдВ Rx-
BehaviorSubjec
ta рдФрд░
EventBus
-a рдХрд╛ рдПрдХ рдПрдирд╛рд▓реЙрдЧ рдорд┐рд▓рд╛ рд╣реИ, рдЬреЛ рдХреЗрд╡рд▓
LiveData
рдкрд░ рдЖрдзрд╛рд░рд┐рдд рд╣реИ, рдЬрд┐рд╕рдореЗрдВ
Emitter
рдСрдмреНрдЬрд░реНрд╡рд░ рдирд┐рд╖реНрдкрд╛рджрдХ рдХреЗ рд╕рд╛рдордиреЗ рдЖрдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдШрдЯрдирд╛рдУрдВ рдХреЛ рдПрдХрддреНрд░ рдХрд░ рд╕рдХрддрд╛ рд╣реИ, рдФрд░ рдЬрд┐рд╕рдореЗрдВ рдСрдмреНрдЬрд░реНрд╡рд░ рдЗрд╡реЗрдВрдЯ рдкреНрд░рдХрд╛рд░реЛрдВ рдХреА рдирд┐рдЧрд░рд╛рдиреА рдХрд░ рд╕рдХрддрд╛ рд╣реИ рдФрд░ рдпрджрд┐ рдЖрд╡рд╢реНрдпрдХ рд╣реЛ, рддреЛ рдЙрдиреНрд╣реЗрдВ рдХреЗрд╡рд▓ рдПрдХ рдмрд╛рд░ рдХреЙрд▓ рдХрд░реЗрдВред
рд╕реБрдЭрд╛рд╡реЛрдВ рдХреЗ рд╕рд╛рде рдЯрд┐рдкреНрдкрдгрд┐рдпреЛрдВ рдореЗрдВ рдЖрдкрдХрд╛ рд╕реНрд╡рд╛рдЧрдд рд╣реИред
рд╕реНрд░реЛрдд рд╕реЗ рд▓рд┐рдВрдХ рдХрд░реЗрдВрд╣реЛрдо рдХреНрд░реЗрдбрд┐рдЯ рдмреИрдВрдХ рд╕реЗ рдХрд┐рд╕реНрдд рдпреЛрдЬрдирд╛ ред