рдЗрд╕ рд▓реЗрдЦ рдХрд╛ рдЙрджреНрджреЗрд╢реНрдп рдпрд╣ рджрд┐рдЦрд╛рдирд╛ рд╣реИ рдХрд┐ рдХреЛрдЯрд▓рд┐рди рдХреЙрд░рдЯрд╛рдЗрдиреНрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХреИрд╕реЗ рдХрд░реЗрдВ рдФрд░ рд░рд┐рдПрдХреНрд╕реЗрдЯрд┐рд╡ рдПрдХреНрд╕рдПрдХреНрд╕рдЯреЗрдВрд╢рди (рдЖрд░рдПрдХреНрд╕) рдХреЛ рд╣рдЯрд╛ рджреЗрдВред
рд▓рд╛рдн
рдЖрд░рдПрдХреНрд╕ рдкрд░ рдХреЛрд░рд╛рдЯрд╛рдЗрди рдХреЗ рдЪрд╛рд░ рд▓рд╛рднреЛрдВ рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░рдирд╛ рд╢реБрд░реВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП:
рдЕрд╡рд░реБрджреНрдз рдХрд░рдиреЗ рдкрд░ рдирд┐рд▓рдВрдмрди
Rx рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЧреИрд░-рдЕрд╡рд░реЛрдзрдХ рдХреЛрдб рдЪрд▓рд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрдк рдХреБрдЫ рдЗрд╕ рддрд░рд╣ рд╕реЗ рд▓рд┐рдЦреЗрдВрдЧреЗ:
Observable.interval(1, TimeUnit.SECONDS) .subscribe { textView.text = "$it seconds have passed" }
рдЬреЛ рдкреНрд░рднрд╛рд╡реА рд░реВрдк рд╕реЗ рдПрдХ рдирдпрд╛ рд╕реВрддреНрд░ рдмрдирд╛ рд░рд╣рд╛ рд╣реИред рдереНрд░реЗрдб рд╕реНрдореГрддрд┐ рдФрд░ рдкреНрд░рджрд░реНрд╢рди рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ рднрд╛рд░реА рд╡рд╕реНрддреБрдПрдВ рд╣реИрдВред
рджреЛрдиреЛрдВ рдореЛрдмрд╛рдЗрд▓ рд╡рд┐рдХрд╛рд╕ рдХреА рджреБрдирд┐рдпрд╛ рдореЗрдВ рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИрдВред
рдЖрдк рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╕реНрдирд┐рдкреЗрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╕рдорд╛рди рд╡реНрдпрд╡рд╣рд╛рд░ рдкреНрд░рд╛рдкреНрдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:
launch { var i = 0 while (true){ textView.text = "${it++} seconds have passed" delay(1000) } }
рдореВрд▓ рд░реВрдк рд╕реЗ, рдХреЛрд░рдЖрдЙрдЯреНрд╕ рд╣рд▓реНрдХреЗ рд╡рдЬрди рдХреЗ рдзрд╛рдЧреЗ рд╣реЛрддреЗ рд╣реИрдВ рд▓реЗрдХрд┐рди рд╣рдо рдХреЛрдИ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рдзрд╛рдЧрд╛ рдирд╣реАрдВ рдмрдирд╛рддреЗ рд╣реИрдВред
рдпрд╣рд╛рдВ рд╣рдо рдиреЙрди-рдмреНрд▓реЙрдХрд┐рдВрдЧ рджреЗрд░реА () рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣реЗ рд╣реИрдВ, рдЬреЛ рдПрдХ рд╡рд┐рд╢реЗрд╖ рдирд┐рд▓рдВрдмрд┐рдд рдлрд╝рдВрдХреНрд╢рди рд╣реИ рдЬреЛ рдПрдХ рдереНрд░реЗрдб рдХреЛ рдмреНрд▓реЙрдХ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ рд▓реЗрдХрд┐рди рдХреЛрд░рдЖрдЙрдЯ рдХреЛ рдирд┐рд▓рдВрдмрд┐рдд рдХрд░рддрд╛ рд╣реИред
рдореИрдиреБрдЕрд▓ рдкрд░ рдкреНрд░рд╛рдХреГрддрд┐рдХ рдмреИрдХрдкреЗрдЪрд░ рд╣реИрдВрдбрд▓рд┐рдВрдЧ
Backpressure рддрдм рд╣реЛрддрд╛ рд╣реИ рдЬрдм рд╡реЗрдзрд╢рд╛рд▓рд╛рдПрдВ рдЙрди рд╡рд╕реНрддреБрдУрдВ рдХрд╛ рдЕрдзрд┐рдХ рддреЗрдЬреА рд╕реЗ рдЙрддреНрдкрд╛рджрди рдХрд░рддреА рд╣реИрдВ рдЬреЛ рдЙрдирдХреЗ рдкрд░реНрдпрд╡реЗрдХреНрд╖рдХ рдЙрдирдХрд╛ рдЙрдкрднреЛрдЧ рдХрд░рддреЗ рд╣реИрдВред
рдЖрд░рдПрдХреНрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╕рдордп рдЖрдкрдХреЛ рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ рдХрд┐ рдЖрдк рдмреИрдХрд╕реНрдкреЗрд╕ рдХреЗ рд╕рд╛рде рдХреИрд╕реЗ рд╡реНрдпрд╡рд╣рд╛рд░ рдХрд░реЗрдВрдЧреЗред
2 рдмреБрдирд┐рдпрд╛рджреА рджреГрд╖реНрдЯрд┐рдХреЛрдг рд╣реИрдВ:
- рдереНрд░реЙрдЯрд▓рд┐рдВрдЧ, рдмрдлрд╝рд░реНрд╕ рдпрд╛ рд╡рд┐рдВрдбреЛ рдСрдкрд░реЗрдЯрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ
- рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛рд╢реАрд▓ рдкреБрд▓ рдореЙрдбрд▓
рдЬрдмрдХрд┐ Coroutines рд╕рд╕реНрдкреЗрдВрдб рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рд╡реЗ рдмреИрдХрдкреНрд░реЗрд╢рд░ рдХреЛ рд╕рдВрднрд╛рд▓рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдкреНрд░рд╛рдХреГрддрд┐рдХ рдЙрддреНрддрд░ рдкреНрд░рджрд╛рди рдХрд░рддреЗ рд╣реИрдВред
рдЗрд╕ рдкреНрд░рдХрд╛рд░, рдХреЛрдИ рдЕрддрд┐рд░рд┐рдХреНрдд рдХрд╛рд░реНрд░рд╡рд╛рдИ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИред
Async рдкрд░ рдХреЛрдб рд╢реИрд▓реА рдХреЛ рд╕рд┐рдВрдХ рдХрд░реЗрдВ
рдореЛрдмрд╛рдЗрд▓ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреА рдореВрд▓ рдкреНрд░рдХреГрддрд┐ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреА рдХреНрд░рд┐рдпрд╛рдУрдВ рдкрд░ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХрд░рдирд╛ рд╣реИред рдпрд╣реА рдХрд╛рд░рдг рд╣реИ рдХрд┐ рд░рд┐рдПрдХреНрдЯрд┐рд╡ рдИрдПрдХреНрд╕рдЯреЗрдВрд╢рди рдПрдХ рдЕрдЪреНрдЫрд╛ рд╡рд┐рдХрд▓реНрдк рд╣реЛрдЧрд╛ред
рд╣рд╛рд▓рд╛рдВрдХрд┐, рдЖрдкрдХреЛ рдПрдХ рдХрд╛рд░реНрдпрд╛рддреНрдордХ рд╢реИрд▓реА рдореЗрдВ рдПрдХ рдХреЛрдб рд▓рд┐рдЦрдирд╛ рд╣реЛрдЧрд╛ред рдпрджрд┐ рдЖрдк рдЕрдирд┐рд╡рд╛рд░реНрдп рд╢реИрд▓реА рдореЗрдВ рд▓рд┐рдЦрддреЗ рдереЗ рддреЛ рдпрд╣ рдереЛрдбрд╝рд╛ рдХрдард┐рди рд╣реЛ рд╕рдХрддрд╛ рд╣реИред
рдЬрдмрдХрд┐ Coroutines рдЖрдкрдХреЛ Async рдХреЛрдб рд▓рд┐рдЦрдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рдХрд░рддрд╛ рд╣реИ рдЬреИрд╕реЗ рдХрд┐ рдпрд╣ рд╕рд╛рдорд╛рдиреНрдп рд╕рд┐рдВрдХ рдлрд╝рдВрдХреНрд╢рдВрд╕ рдерд╛ред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП,
suspend fun showTextFromRemote() { val text = remote.getText() textView.text = text }
рдпрд╣рд╛рдВ рддрдХ тАЛтАЛрдХрд┐ рдореИрдВ рд▓рдВрдмреЗ рд╕рдордп рддрдХ рдХрд╛рд░реНрдпрд╛рддреНрдордХ рд╢реИрд▓реА рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░ рд░рд╣рд╛ рд╣реВрдВ, рдлрд┐рд░ рднреА рдПрдХ рдЕрдирд┐рд╡рд╛рд░реНрдп рдХреЛрдб рдХреЛ рдкрдврд╝рдирд╛ рдФрд░ рдбреАрдмрдЧ рдХрд░рдирд╛ рдЖрд╕рд╛рди рд╣реИред
рддреАрд╕рд░реЗ рдкрдХреНрд╖ рдХреЗ рджрд╛рдпрд┐рддреНрд╡ рд╕реЗ рдЕрдзрд┐рдХ рдореВрд▓
рдХреЙрд░рдЯреАрди рдПрдХ рдореВрд▓ рдмрд┐рд▓реНрдб-рдЗрди рдХреЛрдЯрд▓рд┐рди рдХреА рд╡рд┐рд╢реЗрд╖рддрд╛ рд╣реИред
рдЖрдкрдХреЛ рдХреЛрдИ рдЕрддрд┐рд░рд┐рдХреНрдд рдирд┐рд░реНрднрд░рддрд╛ рдирд╣реАрдВ рдорд┐рд▓рд╛рдиреА рд╣реИред рд╡рд░реНрддрдорд╛рди рдореЗрдВ, рд╕рднреА рдореБрдЦреНрдп рдкреБрд╕реНрддрдХрд╛рд▓рдп рдХреЛрд░рдЖрдЙрдЯреНрд╕ рд╕реЗ рдирд┐рдкрдЯ рд╕рдХрддреЗ рд╣реИрдВред
рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП,
рдкреБрд░рд╛рдирд╛ рд╡рд╛рдкрд╕
interface Api { @Get("users") suspend fun loadUsers() : List<User> }
рдХрдХреНрд╖
interface Dao { @Update suspend fun update(user: UserEntity) }
рддреЛ, рдЖрдк рдПрдХ рдРрдк рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВ рдЬреЛ рд╕рднреА рддрд░рд╣ рд╕реЗ рдирд┐рд▓рдВрдмрд┐рдд рд╣реИ - рдпреВрдЖрдИ рдкрд░рдд рд╢реБрд░реВ рдХрд░рдирд╛, рдбреЛрдореЗрди рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдФрд░ рдбреЗрдЯрд╛ рдкрд░рдд рдореЗрдВ рд╕рдорд╛рдкреНрдд рд╣реЛрдирд╛ред
рдРрдк
рдЪрд▓реЛ рд╡реНрдпрд╛рдкрд╛рд░ рдХреЗ рд▓рд┐рдП рдиреАрдЪреЗ рдЬрд╛рдУред рд╣рдо рдПрдХ рдХреНрд▓рд╛рд╕рд┐рдХ рдорд╛рд╕реНрдЯрд░-рдбрд┐рдЯреЗрд▓ рдРрдк рдмрдирд╛рдПрдВрдЧреЗред
рдкрд╣рд▓реЗ рдкреГрд╖реНрда рдореЗрдВ рдкреНрд░рд╕рд╡ рдХреА рдЕрдирдВрдд рд╕реВрдЪреА рд╣реЛрдЧреАред
рдЖрдЗрдЯрдо рдкрд░ рдХреНрд▓рд┐рдХ рдХрд░рдиреЗ рдкрд░, рд╣рдо рдПрдХ рд╡рд┐рд╡рд░рдг рдкреГрд╖реНрда рдЦреЛрд▓реЗрдВрдЧреЗред
рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рд╣рдо рдСрдлрд╝рд▓рд╛рдЗрди рдореЛрдб рдХрд╛ рд╕рдорд░реНрдерди рдХрд░реЗрдВрдЧреЗ - рд╕рднреА рдбреЗрдЯрд╛ рдХреИрд╢ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред
рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдореИрдВ MVVM рдЖрд░реНрдХрд┐рдЯреЗрдХреНрдЪрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реВрдВрдЧрд╛ рдЬрд╣рд╛рдВ AACM рд╕реЗ ViewModel рдХреЗ рдмрдЬрд╛рдп ViewModel рдХреА рднреВрдорд┐рдХрд╛ Fragment рджреНрд╡рд╛рд░рд╛ рдирд┐рднрд╛рдИ рдЬрд╛рддреА рд╣реИред рдЗрд╕рдХреЗ рдХрдИ рдХрд╛рд░рдг рд╣реИрдВ:
рдЯреБрдХрдбрд╝реЗ рдЖрдорддреМрд░ рдкрд░ рдмрд╣реБрдд рдЧрдВрдЬреЗ рд╣реЛрддреЗ рд╣реИрдВ - рдмрд╕ рджреГрд╢реНрдпрдореЙрдбрд▓ рдХреЛ XML рд╕реЗ рдмрд╛рдВрдзреЗрдВред
рд╕реНрдерд┐рддрд┐ рдмрд╛рд░ рд░рдВрдЧ рд╕реЗрдЯ рдХрд░рдиреЗ рдЬреИрд╕реА рд╡рд┐рд╢реЗрд╖рддрд╛рдПрдВ AAC ViewModel рдореЗрдВ рдирд╣реАрдВ рдХреА рдЬрд╛ рд╕рдХреАрдВ - рдЖрдкрдХреЛ рдЯреБрдХрдбрд╝реЗ рдХреА рд╡рд┐рдзрд┐ рдХреЛ рдЯреНрд░рд┐рдЧрд░ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред ViewModel рдХреЗ рд░реВрдк рдореЗрдВ рдЯреБрдХрдбрд╝реЗ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рд╕реЗ рд╣рдореЗрдВ рдПрдХ рд╡рд░реНрдЧ рдореЗрдВ рд╕рднреА рд╕рдВрдмрдВрдзрд┐рдд рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ (рдПрдХ рд╕реНрдХреНрд░реАрди рдХреЛ рдкреНрд░рдмрдВрдзрд┐рдд рдХрд░рдирд╛) рдХреЛ рд╕реНрдЯреЛрд░ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рдорд┐рд▓реЗрдЧреАред
рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, BaseViewModel рдмрдирд╛рдПрдБ:
abstract class BaseViewModel<B : BaseBindings, V : ViewDataBinding> : Fragment(), CoroutineScope by CoroutineScope(Dispatchers.IO){ protected abstract val layoutId: Int protected abstract val bindings: B protected lateinit var viewBinding: V override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) retainInstance = true } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { viewBinding = DataBindingUtil.inflate(inflater, layoutId, container, false) return viewBinding.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) viewBinding.lifecycleOwner = viewLifecycleOwner viewBinding.setVariable(BR.bindings, bindings) } override fun onDestroy() { cancel() super.onDestroy() } }
рд╣рдо рдЕрдкрдиреЗ ViewModel рдХреЛ CoroutineScope рдХреЗ рд░реВрдк рдореЗрдВ рдЪрд┐рд╣реНрдирд┐рдд рдХрд░рддреЗ рд╣реИрдВ, рддрд╛рдХрд┐ рд╣рдо рд╡реНрдпреВ рдореЙрдбрд▓ рдХреЗ рдЕрдВрджрд░ рдХреЙрд░рдЖрдЙрдЯ рд╢реБрд░реВ рдХрд░ рд╕рдХреЗрдВ рдФрд░ рдХрд┐рд╕реА рднреА рд▓реЙрдиреНрдЪ рдХрд┐рдП рдЧрдП рдХреЙрд░рдЖрдЙрдЯ рдХреЛ рдПрдХ рдЯреБрдХрдбрд╝реЗ рдХреЗ рдЬреАрд╡рдирдЪрдХреНрд░ рддрдХ рд╕реАрдорд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХреЗред
рд╣рдореЗрдВ рдореЗрдореЛрд░реА рд▓реАрдХ рд╕реЗ рдмрдЪрдиреЗ рдХреЗ рд▓рд┐рдП рд╕рднреА рдЪрд▓ рд░рд╣реЗ рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЛ рд░рджреНрдж рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕реНрдХреЛрдк рдХреЗ рдЬреАрд╡рдирдЪрдХреНрд░ рдХреЙрд▓рд┐рдВрдЧ cancel()
рд╡рд┐рдзрд┐ рдХреЗ рдЕрдВрдд рдХреЛ рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред
рд╣рдордиреЗ retainInstance = true
рд╕реЗрдЯ рдХрд┐рдпрд╛ retainInstance = true
рддрд╛рдХрд┐ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдкрд░рд┐рд╡рд░реНрддрди рдореЗрдВ рдЯреБрдХрдбрд╝реЗ рдХреЛ рдлрд┐рд░ рд╕реЗ рди рдмрдирд╛рдпрд╛ рдЬрд╛рдП рддрд╛рдХрд┐ рд╣рдо рд╕рднреА рд▓рдВрдмреЗ рд╕рдордп рд╕реЗ рдЪрд▓ рд░рд╣реЗ рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЛ рдкреВрд░рд╛ рдХрд░ рд╕рдХреЗрдВред
рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рд╣рдореЗрдВ рджреЛ-рддрд░рдлрд╝рд╛ рдбреЗрдЯрд╛ рдмрд╛рдЗрдВрдбрд┐рдВрдЧ рдХреЛ рдЪрд╛рд▓реВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдмрд╛рдЗрдВрдбрд┐рдВрдЧ рдЬреАрд╡рдирдЪрдХреНрд░ рд╕реЗрдЯ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред
рдЕрдкрд╡рд╛рдж рд╕рдВрднрд╛рд▓рдирд╛
Coroutines рдкреНрд░рд▓реЗрдЦрди рдХреЗ рдЕрдиреБрд╕рд╛рд░:
Coroutine builders come in two flavors: propagating exceptions automatically (launch and actor) or exposing them to users (async and produce). The former treat exceptions as unhandled, similar to Java's Thread.uncaughtExceptionHandler
рдЪреВрдВрдХрд┐ рд╣рдо рдЬреНрдпрд╛рджрд╛рддрд░ рдорд╛рдорд▓реЛрдВ рдореЗрдВ рд▓реЙрдиреНрдЪ рдмрд┐рд▓реНрдбрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣реЗ рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП рд╣рдореЗрдВ CoroutineExceptionHandler рдХреЛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рдирд╛ рд╣реЛрдЧрд╛
CoroutineExceptionHandler CoroutineContext.Element рд╣реИ, рдЬрд┐рд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рд╕реА рдЕрдиреНрдп рдСрдкрд░реЗрдЯрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдХреЛрд░рдЯрд╛рдЗрди рд╕рдВрджрд░реНрдн рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред
рдореИрдВ рд╕реНрдереИрддрд┐рдХ рд╣реИрдВрдбрд▓рд░ рдХреА рдШреЛрд╖рдгрд╛ рдЗрд╕ рдкреНрд░рдХрд╛рд░ рдХрд░реЗрдЧрд╛:
val exceptionHandler = CoroutineExceptionHandler { _, throwable -> Timber.e(throwable) }
рдФрд░ BaseViewModel рдмрджрд▓реЗрдВ:
abstract class BaseViewModel<B : BaseBindings, V : ViewDataBinding> : Fragment(), CoroutineScope by CoroutineScope(Dispatchers.IO + exceptionHandler)
рдпрд╣рд╛рдБ рд╕реЗ ViewModel рдХреЗ рджрд╛рдпрд░реЗ рдореЗрдВ рд▓реЙрдиреНрдЪ рдХрд┐рдП рдЧрдП рдХреЛрд░рдЖрдЙрдЯ рдореЗрдВ рдХрд┐рд╕реА рднреА рдЕрдкрд╡рд╛рдж рдХреЛ рджрд┐рдП рдЧрдП рд╣реИрдВрдбрд▓рд░ рдХреЛ рджрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред
рдЗрд╕рдХреЗ рдмрд╛рдж, рдореБрдЭреЗ рдЕрдкрдирд╛ API рдФрд░ DAO рдШреЛрд╖рд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ:
interface DeliveriesApi { @GET("deliveries") suspend fun getDeliveries(@Query("offset") offset: Int, @Query("limit") limit: Int): List<DeliveryResponse> } @Dao interface DeliveryDao { @Query("SELECT * FROM ${DeliveryEntity.TABLE_NAME}") fun getAll(): DataSource.Factory<Int, DeliveryEntity> @Insert(onConflict = OnConflictStrategy.REPLACE) suspend fun insert(delivery: DeliveryEntity) }
рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рдореИрдВрдиреЗ рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЛ рдирд┐рд▓рдВрдмрд┐рдд рдХрд░ рджрд┐рдпрд╛ рд╣реИ рддрд╛рдХрд┐ рд╣рдо рдХреЗрд╡рд▓ рдЕрдкреЗрдХреНрд╖рд┐рдд рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рд╡рд╕реНрддреБрдУрдВ рдХреА рдШреЛрд╖рдгрд╛ рдХрд░ рд╕рдХреЗрдВред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдореВрд▓ рдХреЙрд░рдЖрдЙрдЯ рдХреЗ рд░рджреНрдж рд╣реЛрдиреЗ рд╕реЗ рдиреЗрдЯрд╡рд░реНрдХ рдХреЙрд▓ рднреА рд░рджреНрдж рд╣реЛ рдЬрд╛рдПрдЧреАред
DAO рдХреЗ рд▓рд┐рдП рднреА рдпрд╣реАред
рдЕрдВрддрд░ рдХреЗрд╡рд▓ рдЗрддрдирд╛ рд╣реИ рдХрд┐ рд╣рдо рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЛ рджреЗрдЦрдиреЗ рдХреА рдХреНрд╖рдорддрд╛ рдкреНрд░рджрд╛рди рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВред
рд╕рдмрд╕реЗ рдЖрд╕рд╛рди рддрд░реАрдХрд╛ рдЕрдВрддрд░реНрдирд┐рд╣рд┐рдд рдбреЗрдЯрд╛ рд╕рдорд░реНрдерди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рд╣реИред рд▓реЗрдХрд┐рди рдЕрдЧрд░ рд╣рдо getAll () рдХреЛ рдирд┐рд▓рдВрдмрд┐рдд рдХрд░ рджреЗрдВрдЧреЗ, рддреЛ рдпрд╣ рдПрдХ рд╕рдВрдХрд▓рди рддреНрд░реБрдЯрд┐ рдХрд╛ рдХрд╛рд░рдг рд╣реЛрдЧрд╛
рддреНрд░реБрдЯрд┐:
Not sure how to convert a Cursor to this method's return type ...
рдпрд╣рд╛рдБ рд╣рдореЗрдВ рд╕рд╕реНрдкреЗрдВрдб рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ рдХреНрдпреЛрдВрдХрд┐:
- рдбреАрдмреА рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЛ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ рдкреГрд╖реНрдарднреВрдорд┐ рдореЗрдВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ
- рдкрд░рд┐рдгрд╛рдореА LiveData рдЬреАрд╡рдирдЪрдХреНрд░ рдЬрд╛рдЧрд░реВрдХ рд╣реИ, рдЗрд╕рд▓рд┐рдП рд╣рдореЗрдВ рдЗрд╕реЗ рдореИрдиреНрдпреБрдЕрд▓ рд░реВрдк рд╕реЗ рд░рджреНрдж рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ
рд╣рдореЗрдВ рдХрд┐рд╕реА рддрд░рд╣ рджреВрд░рд╕реНрде рдФрд░ рд╕реНрдерд╛рдиреАрдп рдбреЗрдЯрд╛ рд╕реНрд░реЛрддреЛрдВ рдХреЛ рдЬреЛрдбрд╝рдирд╛ рд╣реЛрдЧрд╛ред
рдпрд╣ рдпрд╛рдж рд░рдЦрдиреЗ рдпреЛрдЧреНрдп рд╣реИ - рд╕рддреНрдп рдХрд╛ рдПрдХ рд╣реА рдмрд┐рдВрджреБ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред
рдСрдлрд╝рд▓рд╛рдЗрди-рдкреНрд░рдердо рдбрд┐рдЬрд╝рд╛рдЗрди рдХреЗ рдЕрдиреБрд╕рд╛рд░, рдпрд╣ рд╕реНрдерд╛рдиреАрдп рднрдВрдбрд╛рд░рдг рд╣реЛрдЧрд╛ред рдЗрд╕рд▓рд┐рдП, рд╣рдо рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реНрдерд┐рддрд┐ рдХрд╛ рдирд┐рд░реАрдХреНрд╖рдг рдХрд░реЗрдВрдЧреЗред рдЬрдм рдХреЛрдИ рдкреБрдирд░реНрдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреБрдЫ рдирд╣реАрдВ рд╣реЛрддрд╛ рд╣реИ рддреЛ рд╣рдо рд░рд┐рдореЛрдЯ рд╕реЗ рдбреЗрдЯрд╛ рдкреВрдЫреЗрдВрдЧреЗ рдФрд░ рдЗрд╕реЗ рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рдбрд╛рд▓реЗрдВрдЧреЗред
рд╣рдо рд╕реВрдЪреА рд╡рд░реНрдЧ рдХрд╛ рдкрд░рд┐рдЪрдп рджреЗрдВрдЧреЗ
data class Listing<T>( val pagedList: LiveData<PagedList<T>>, val dataState: LiveData<DataState>, val refreshState: LiveData<DataState>, val refresh: () -> Unit, val retry: () -> Unit )
рдЖрдЗрдП рдЬрд╛рдиреЗ рд╡реИрд▓ рд╕реЗ рд╡реИрд▓:
- pagedList - рдореБрдЦреНрдп рдбреЗрдЯрд╛ рдЬрд┐рд╕реЗ PagedList рдХреЗ рд░реВрдк рдореЗрдВ рдмрдирд╛рдпрд╛ рдЧрдпрд╛ рд╣реИ рддрд╛рдХрд┐ рдЕрдирдВрдд рд╕реНрдХреНрд░реЙрд▓рд┐рдВрдЧ рдХреЛ рд╕рдХреНрд╖рдо рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХреЗ рдФрд░ рдбреЗрдЯрд╛ рдХреЛ рд╕рдХреНрд╖рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП LiveData рдХреЗ рд╕рд╛рде рд▓рд┐рдкрдЯреЗ
- dataState - рддреАрди рдореЗрдВ рд╕реЗ рдПрдХ рд╕реНрдерд┐рддрд┐ рдЬрд┐рд╕рдореЗрдВ рд╣рдорд╛рд░рд╛ рдбреЗрдЯрд╛ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ: рд╕рдХреНрд╕реЗрд╕, рд░рдирд┐рдВрдЧ, рдПрд░рд░ред рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ рдХреЛ рджреЗрдЦрдиреЗ рдХреЗ рд▓рд┐рдП рд▓рд╛рдЗрд╡рдбрд╛рдЯрд╛ рд╕реЗ рднреА рд▓рд┐рдкрдЯрд╛
- рд░рд┐рдлреНрд░реЗрд╢рд╕реНрдЯреЗрдЯ - рдЬрдм рд╣рдо рд╕реНрд╡рд╛рдЗрдк-рд░рд┐рдлреНрд░реЗрд╢ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд░рд┐рдлреНрд░реЗрд╢рд┐рдВрдЧ рдбреЗрдЯрд╛ рдХреЛ рдЯреНрд░рд┐рдЧрд░ рдХрд░рддреЗ рд╣реИрдВ рддреЛ рд╣рдореЗрдВ рдХреБрдЫ рдЯреВрд▓ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ, рдЬрд┐рд╕рдХреЗ рджреНрд╡рд╛рд░рд╛ рд╣рдо рд░рд┐рдлреНрд░реЗрд╢ рд░рд┐рдХреНрд╡реЗрд╕реНрдЯ рдлреАрдбрдмреИрдХ рдФрд░ рдЕрдЧрд▓реЗ рдкреЗрдЬ рд░рд┐рдХреНрд╡реЗрд╕реНрдЯ рдлреАрдбрдмреИрдХ рдХреЗ рдмреАрдЪ рдЕрдВрддрд░ рдХрд░рддреЗ рд╣реИрдВред рдкреВрд░реНрд╡ рдХреЗ рд▓рд┐рдП, рд╣рдо рд╕реВрдЪреА рдХреЗ рдЕрдВрдд рдореЗрдВ рдПрдХ рддреНрд░реБрдЯрд┐ рджрд┐рдЦрд╛рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ рд▓реЗрдХрд┐рди рддрд╛рдЬрд╝рд╛ рддреНрд░реБрдЯрд┐ рдХреЗ рд▓рд┐рдП, рд╣рдо рдПрдХ рдЯреЛрд╕реНрдЯ рд╕рдВрджреЗрд╢ рджрд┐рдЦрд╛рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ рдФрд░ рдПрдХ рд▓реЛрдбрд░ рдХреЛ рдЫрд┐рдкрд╛рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВред
- рд░рд┐рдлреНрд░реЗрд╢ () - рд╕реНрд╡рд╛рдЗрдк-рд░рд┐рдлреНрд░реЗрд╢ рдкрд░ рдЯреНрд░рд┐рдЧрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреЙрд▓рдмреИрдХ
рдкреБрдирдГ рдкреНрд░рдпрд╛рд╕ рдХрд░реЗрдВ () - рдкреГрд╖реНрдард╛рдВрдХрд┐рдд рд▓реЛрдбрд┐рдВрдЧ рддреНрд░реБрдЯрд┐ рдкрд░ рдЯреНрд░рд┐рдЧрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреЙрд▓рдмреИрдХ
рдЕрдЧрд▓рд╛, рд╕реВрдЪреА рджреГрд╢реНрдп рдореЙрдбрд▓:
class DeliveryListViewModel : BaseViewModel<DeliveryListBindings, DeliveryListBinding>(), DeliveryListBindings, DeliveryListItemBindings, DeliveryListErrorBindings { override val layoutId: Int = R.layout.delivery_list override val bindings: DeliveryListBindings = this private val deliveryGateway: DeliveryGateway by inject { parametersOf(this) } private val listing = deliveryGateway.getDeliveries() override val dataState = listing.dataState override val isRefreshing = Transformations.switchMap(listing.refreshState) { MutableLiveData(it == DataState.Loading) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) setupList() setupRefresh() } private fun setupList() { val adapter = DeliveriesAdapter(this, this) viewBinding.deliveries.adapter = adapter viewBinding.deliveries.setHasFixedSize(true) listing.pagedList.observe(viewLifecycleOwner, Observer { adapter.submitList(it) }) listing.dataState.observe(viewLifecycleOwner, Observer { adapter.updateDataState(it) }) } private fun setupRefresh() { listing.refreshState.observe(viewLifecycleOwner, Observer { if (it is DataState.Error) { Toast.makeText(context, it.message, LENGTH_SHORT).show() } }) } override fun refresh() { listing.refresh() } override fun onDeliveryClicked(delivery: Delivery) { view?.findNavController()?.navigate(DeliveryListViewModelDirections.toDetails(delivery)) } override fun onRetryClicked() { listing.retry() } }
рдХрдХреНрд╖рд╛ рдШреЛрд╖рдгрд╛ рд╕реЗ рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВред
рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ DeliveryListBindings рдФрд░ DeliveryListBindingред рдкрд╣рд▓реЗ рдПрдХреНрд╕рдПрдордПрд▓ рджреГрд╢реНрдп рдХреЗ рд╕рд╛рде рджреГрд╢реНрдп рдореЙрдбрд▓ рдХреЛ рдЧреЛрдВрдж рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╣рдорд╛рд░рд╛ рдШреЛрд╖рд┐рдд рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рд╣реИред рджреВрд╕рд░рд╛ XML рдкрд░ рдЖрдзрд╛рд░рд┐рдд рдСрдЯреЛрдЬреЗрдирд░реЗрдЯреЗрдб рдХреНрд▓рд╛рд╕ рд╣реИред рд╣рдореЗрдВ рдЕрдкрдиреЗ рдмрд╛рдЗрдВрдбрд┐рдВрдЧ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдФрд░ рдЬреАрд╡рдирдЪрдХреНрд░ рдХреЛ XML рдкрд░ рд╕реЗрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рджреВрд╕рд░реЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред
рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдХреЛрдЯрд▓рд┐рди рдХреЗ рд╕рд┐рдВрдереЗрдЯрд┐рдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рдмрдЬрд╛рдп рдЗрд╕ рдСрдЯреЛрдЬреЗрдирд░реЗрдЯреЗрдб рдмрд╛рдЗрдВрдбрд┐рдВрдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╡рд┐рдЪрд╛рд░реЛрдВ рдХреЛ рд╕рдВрджрд░реНрднрд┐рдд рдХрд░рдирд╛ рдЕрдЪреНрдЫрд╛ рд╣реИред
рд╡рд░реНрддрдорд╛рди рджреГрд╢реНрдп рдореЗрдВ рд╕рд┐рдВрдереЗрдЯрд┐рдХ рджреГрд╢реНрдп рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд╕рдВрджрд░реНрднрд┐рдд рд╣реЛрдиреЗ рдкрд░ рдорд╛рдорд▓рд╛ рд╣реЛ рд╕рдХрддрд╛ рд╣реИред рдбреЗрдЯрд╛ рдмрд╛рдзреНрдпрдХрд╛рд░реА рдХреЗ рд╕рд╛рде, рдЖрдк рд╕рдВрдХрд▓рди рдЪрд░рдг рдкрд░ рднреА рддреЗрдЬреА рд╕реЗ рд╡рд┐рдлрд▓ рд╣реЛ рдЬрд╛рдПрдВрдЧреЗред
рдЗрд╕рдХреЗ рдмрд╛рдж, рддреАрди рдЗрдВрдЯрд░рдлреЗрд╕: рдбрд┐рд▓рд┐рд╡рд░реА рд▓рд┐рд╕реНрдЯрдмрд╛рдЗрдВрдбрд┐рдВрдЧ, рдбрд┐рд▓рд┐рд╡рд░реА рд▓рд┐рд╕реНрдЯрдЗрдордмрд╛рдЗрдВрдбрд┐рдВрдЧ, рдбрд┐рд▓рд┐рд╡рд░реА рд▓рд┐рд╕реНрдЯреНрд░рд╛рд░ рдмрд┐рдВрджрд┐рдВрдЧреНрд╕ред
- DeliveryListBindings - рд╕реНрдХреНрд░реАрди рдХреЗ рд▓рд┐рдП рд╣реА рдмрд╛рдЗрдВрдбрд┐рдВрдЧред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЗрд╕рдореЗрдВ рддрд╛рдЬрд╝рд╛ () рд╡рд┐рдзрд┐ рд╢рд╛рдорд┐рд▓ рд╣реИ рдЬрд┐рд╕реЗ рдКрд░реНрдзреНрд╡рд╛рдзрд░ рд╕реНрд╡рд╛рдЗрдк рдкрд░ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИред
- DeliveryListItemBindings - рд╕реВрдЪреА рдореЗрдВ рдПрдХ рдЖрдЗрдЯрдо рдХреЗ рд▓рд┐рдП рдмрд╛рдЗрдВрдбрд┐рдВрдЧред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, onClicked ()
- DeliveryListErrorBindings - рддреНрд░реБрдЯрд┐ рджреГрд╢реНрдп рдХреЗ рд▓рд┐рдП рдмрд╛рдЗрдВрдбрд┐рдВрдЧ рдЬреЛ рддреНрд░реБрдЯрд┐ рд╕реНрдерд┐рддрд┐ рдкрд░ рджрд┐рдЦрд╛рдИ рдЧрдИ рд╕реВрдЪреА рдЖрдЗрдЯрдо рднреА рд╣реИред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЗрд╕рдореЗрдВ рдкреБрдирд░реНрдкреНрд░рдпрд╛рд╕ () рд╡рд┐рдзрд┐ рд╢рд╛рдорд┐рд▓ рд╣реИ
рдЗрд╕ рдкреНрд░рдХрд╛рд░, рд╣рдо рд╕рд┐рдВрдЧрд▓ рд╡реНрдпреВ рдореЙрдбрд▓ рдореЗрдВ рд╕рдм рдХреБрдЫ рд╕рдВрднрд╛рд▓ рд░рд╣реЗ рд╣реИрдВ рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рд╕рд┐рдВрдЧрд▓ рд╕реНрдХреНрд░реАрди рд╣реИ, рд▓реЗрдХрд┐рди рдЗрдВрдЯрд░рдлреЗрд╕ рд╕реЗрдЧреНрд░реАрдЧреЗрд╢рди рд╕рд┐рджреНрдзрд╛рдВрдд рдХрд╛ рднреА рдкрд╛рд▓рди рдХрд░ рд░рд╣рд╛ рд╣реИ
рдЖрдЗрдП рдЗрд╕ рд▓рд╛рдЗрди рдкрд░ рд╡рд┐рд╢реЗрд╖ рдзреНрдпрд╛рди рджреЗрдВ:
private val deliveryGateway: DeliveryGateway by inject { parametersOf(this) }
DeliveryGateway рдХреЛ рдореБрдЦреНрдп рдереНрд░реЗрдб рд╕реЗ рдЕрдиреБрд░реЛрдз рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдЗрд╕рд▓рд┐рдП, рдЗрд╕ рджрд╛рдпрд░реЗ рдореЗрдВ рдирдП рдХреЙрд░рдЖрдЙрдЯреНрд╕ рдХреЛ рд▓реЙрдиреНрдЪ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдпрд╛ рддреЛ рддрд░реАрдХреЛрдВ рдХреЛ рдирд┐рд▓рдВрдмрд┐рдд рдХрд░рдиреЗ рдпрд╛ рдХреЛрд░рдЯрд╛рдЗрдирд╕реНрд╕реНрдХреЛрдк рдШреЛрд╖рд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рд╣рдо рджреВрд╕рд░реЗ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХрд╛ рдЪрдпрди рдХрд░реЗрдВрдЧреЗ рдХреНрдпреЛрдВрдХрд┐ рд╣рдореЗрдВ рдЕрдкрдиреА LiveData рдХреЛ рд╢реБрд░реВ рд╕реЗ рд╣реА рдЬрд░реВрд░рдд рд╣реИ рдФрд░ рдлрд┐рд░ рд╣рдо рдмрд╕ рдЗрд╕рдХреЗ рдЕрдкрдбреЗрдЯ рдХрд╛ рдЗрдВрддрдЬрд╛рд░ рдХрд░реЗрдВрдЧреЗред рдпрд╣ liveData рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП рд╕рджрд╕реНрдпрддрд╛ рд▓реЗрдиреЗ рдХреЗ рд╕рдорд╛рди рд╣реИ рдЬрдм рд╣рдо рдЬреАрд╡рдирдЪрдХреНрд░ рдкрд╛рд╕ рдХрд░ рд░рд╣реЗ рд╣реЛрддреЗ рд╣реИрдВ (рдЬреЛ рдЕрдХреНрд╕рд░ 'рдЗрд╕' рдХреЛ рд╕рдВрджрд░реНрднрд┐рдд рдХрд░рддрд╛ рд╣реИ)ред рдпрд╣рд╛рдВ рд╣рдо рдЙрд╕реА рддрд░рд╣ рд╕реЗ 'рдЗрд╕' рдХреЛ рдХреЛрд░рдЯрд╛рдЗрдирд╕реНрд╕реНрдХреЛрдк рдХреЗ рд░реВрдк рдореЗрдВ рдкрд╛рд░рд┐рдд рдХрд░ рд░рд╣реЗ рд╣реИрдВ
CoroutineScope рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдореЗрдВ рдПрдХрдорд╛рддреНрд░ рдлрд╝реАрд▓реНрдб рд╣реИ - CoroutineContextред рд╕рдВрдХреНрд╖реЗрдк рдореЗрдВ, рдПрдХ рдЧреБрдВрдЬрд╛рдЗрд╢ рдФрд░ рдПрдХ рд╕рдВрджрд░реНрдн рд╕рдорд╛рди рдЪреАрдЬреЗрдВ рд╣реИрдВред рдПрдХ рд╕рдВрджрд░реНрдн рдФрд░ рдПрдХ рджрд╛рдпрд░реЗ рдХреЗ рдмреАрдЪ рдХрд╛ рдЕрдВрддрд░ рдЙрдирдХреЗ рдЗрдЪреНрдЫрд┐рдд рдЙрджреНрджреЗрд╢реНрдп рдореЗрдВ рд╣реИред
рдЗрд╕рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЕрдзрд┐рдХ рдЬрд╛рдирдиреЗ рдХреЗ рд▓рд┐рдП рдореИрдВ рд░реЛрдорди рдПрд▓рд┐рд╕реИрд░реЛрд╡ рдХреЗ рдПрдХ рд▓реЗрдЦ рдХреА рд╕рд┐рдлрд╛рд░рд┐рд╢ рдХрд░реВрдВрдЧрд╛ред рдЗрд╕рд▓рд┐рдП, рдбрд┐рд▓реАрд╡рд░реАрдЧреЗрдЯ рдХреЛ рдЧреБрдВрдЬрд╛рдЗрд╢ рдкреНрд░рджрд╛рди рдХрд░рдиреЗ рд╕реЗ рднреА рдЙрд╕реА рд╕рдВрджрд░реНрдн рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рдзрд╛рдЧрд╛, рдиреМрдХрд░реА рдФрд░ рдЕрдкрд╡рд╛рдж рд╣реИрдВрдбрд▓рд░ред
рдЕрдм рд╣рдо рдЦреБрдж рдбрд┐рд▓реАрд╡рд░реАрдЧреЗрдЯ рдкрд░ рдПрдХ рдирдЬрд╝рд░ рдбрд╛рд▓рддреЗ рд╣реИрдВ:
class DeliveryBoundGateway( private val db: DataBase, private val api: DeliveriesApi, private val deliveryDao: DeliveryDao, private val coroutineScope: CoroutineScope ) : DeliveryGateway { private val boundaryCallback = DeliveriesBoundaryCallback( api = api, coroutineScope = coroutineScope, handleResponse = { insertIntoDatabase(it) } ) @MainThread override fun getDeliveries(): Listing<Delivery> { val refreshTrigger = MutableLiveData<Unit>() val refreshState = Transformations.switchMap(refreshTrigger) { refresh() } val pagingConfig = Config( initialLoadSizeHint = PAGE_SIZE, pageSize = PAGE_SIZE, prefetchDistance = PAGE_SIZE ) val deliveries = deliveryDao.getAll() .toLiveData( config = pagingConfig, boundaryCallback = boundaryCallback ) return Listing( pagedList = deliveries, dataState = boundaryCallback.dataState, retry = { boundaryCallback.helper.retryAllFailed() }, refresh = { refreshTrigger.value = null }, refreshState = refreshState ) } @MainThread private fun refresh(): LiveData<DataState> { boundaryCallback.refresh() val dataState = MutableLiveData<DataState>() dataState.value = DataState.Loading coroutineScope.launch { try { val deliveries = api.getDeliveries(0, PAGE_SIZE) db.withTransaction { deliveryDao.clear() insertIntoDatabase(deliveries) } dataState.postValue(DataState.Loaded) } catch (throwable: Throwable) { Timber.w(throwable) dataState.postValue(DataState.Error(throwable.message)) } } return dataState } private suspend fun insertIntoDatabase(deliveries: List<DeliveryResponse>) { deliveries.forEach { delivery -> val entity = deliveryConverter.fromNetwork(delivery) deliveryDao.insert(entity) } } companion object { const val PAGE_SIZE = 20 } }
рдпрд╣рд╛рдВ рд╣рдо рд╢реБрд░реБрдЖрдд рд╕реЗ рд╣реА LiveData рд╕рдВрд░рдЪрдирд╛ рдХрд╛ рдирд┐рд░реНрдорд╛рдг рдХрд░ рд░рд╣реЗ рд╣реИрдВ рдФрд░ рдлрд┐рд░ рдХреЛрд░рдЯрд╛рдЗрди рд▓реЛрдб рдбреЗрдЯрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рдЗрд╕реЗ LiveData рдкрд░ рдкреЛрд╕реНрдЯ рдХрд░ рд░рд╣реЗ рд╣реИрдВред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рд╣рдо рд╕реНрдерд╛рдиреАрдп рдбреЗрдЯрд╛рдмреЗрд╕ рдФрд░ рджреВрд░рд╕реНрде рдПрдкреАрдЖрдИ рдХреЛ рдЧреЛрдВрдж рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП PagedList.BoundaryCallback () рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣реЗ рд╣реИрдВ ред рдЬрдм рд╣рдо рдкреГрд╖реНрдард╛рдВрдХрд┐рдд рд╕реВрдЪреА рдХреЗ рдЕрдВрдд рддрдХ рдкрд╣реБрдБрдЪрддреЗ рд╣реИрдВ рддреЛ рд╕реАрдорд╛ рд╡рд╛рдкрд╕ рдЪрд╛рд▓реВ рд╣реЛ рдЬрд╛рддреА рд╣реИ рдФрд░ рдбреЗрдЯрд╛ рдХрд╛ рдЕрдЧрд▓рд╛ рд╣рд┐рд╕реНрд╕рд╛ рд▓реЛрдб рд╣реЛ рдЬрд╛рддрд╛ рд╣реИред
рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рд╣рдо рдирдП coroutines рдХреЛ рд▓реЙрдиреНрдЪ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП coroutineScope рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣реЗ рд╣реИрдВред
рдЪреВрдБрдХрд┐ рдпрд╣ рджрд╛рдпрд░рд╛ рдЦрдВрдб рдХреЗ рдЬреАрд╡рдирдЪрдХреНрд░ рдХреЗ рдмрд░рд╛рдмрд░ рд╣реИ - рд╕рднреА рд▓рдВрдмрд┐рдд рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЛ рдЦрдВрдб рдХреЗ onDestroy()
рдХреЙрд▓рдмреИрдХ рдкрд░ рд░рджреНрдж рдХрд░ рджрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред
рдбрд┐рд▓реАрд╡рд░реА рдбрд┐рдЯреЗрд▓ рдкреЗрдЬ рдХрд╛рдлреА рд╕реАрдзрд╛ рд╣реИ - рд╣рдо рд╕рд┐рд░реНрдл рдиреЗрд╡рд┐рдЧреЗрд╢рди рд╕реНрдХреНрд░реАрди рд╕реЗрд╡ рдСрд░реНрдЧреНрд╕ рдкреНрд▓рдЧрдЗрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдорд╛рд╕реНрдЯрд░ рд╕реНрдХреНрд░реАрди рд╕реЗ рдкрд╛рд░реНрд╕рд▓ рдХреЗ рд░реВрдк рдореЗрдВ рдбрд┐рд▓реАрд╡рд░реА рдСрдмреНрдЬреЗрдХреНрдЯ рдкрд╛рд╕ рдХрд░рддреЗ рд╣реИрдВред рд╡рд┐рд╡рд░рдг рд╕реНрдХреНрд░реАрди рдкрд░ рдмрд╕ рдПрдХ рдПрдХреНрд╕рдПрдордПрд▓ рдХреЗ рд▓рд┐рдП рдПрдХ рд╡рд╕реНрддреБ рджреА рдмрд╛рдБрдзред
class DeliveryViewModel : BaseViewModel<DeliveryBindings, DeliveryBinding>(), DeliveryBindings { override val layoutId: Int = R.layout.delivery override val bindings: DeliveryBindings = this private val args: DeliveryViewModelArgs by navArgs() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) viewBinding.delivery = args.delivery viewBinding.image.clipToOutline = true } }
рдпрд╣рд╛рдБ github рд╕реНрд░реЛрдд рдХреЛрдб рдХрд╛ рд▓рд┐рдВрдХ рджрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред
рдЯрд┐рдкреНрдкрдгрд┐рдпреЛрдВ рдФрд░ рдЦреБрд▓реЗ рдореБрджреНрджреЛрдВ рдХреЛ рдЫреЛрдбрд╝рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрдкрдХрд╛ рд╕реНрд╡рд╛рдЧрдд рд╣реИред