mvvm com rxjava com kotlin
TRANSCRIPT
MVVM com RxJava em Kotlin no Android
GDGFoz
Quem ?• Houssan Ali Hijazi - [email protected]
• Desenvolvedor Android na www.HElabs.com
• Organizador GDG Foz do Iguaçu
• www.lojasnoparaguai.com.br
• www.desaparecidosbr.org
• www.hussan.com.br
GDGFoz
Kotlin
• 2011/JetBrains
• 1.0 em Fev. 2016
• 1.1 em Mar. 2017
• Pinterest, Coursera, Netflix, Uber, Square, Trello e Basecamp
• 17/Maio - Google IO 2017
GDGFoz
Kotlin
• Interoperabilidade
• Null Safety
• Conciso
GDGFoz
Manifesto reativo
• Responsivo - Reagir rápido
• Resiliente - Reagir a falhas
• Elástico - Reagir a carga / Autoescalar
• Orientado a mensagens - Comunicação assíncrona
Fonte: https://www.reactivemanifesto.org/pt-BR
GDGFoz
RxJava
• RxJava - Reactive Extensions para a JVM - uma
biblioteca para compor programas assíncronos e
baseados em eventos usando sequências
observáveis.
• Netflix
• 1.0.0 em 18 Nov 2014
• 2.0.0 em 28 Out 2016
GDGFoz
RxJava
Observable
Disposable
subscribe(Observer<T>)
Emite
Observer
onNext(T)
onComplete()
onError(Throwable)Consome
GDGFoz
RxJava
• Observable - Emite dados
• Observer - Consome dados
• Disposable
• Operators: map, flatmap, filter, last, first etc..
• Schedulers
GDGFoz
Código
• Robusto
• Estável
• Testável
• Modular
GDGFoz
Model/View/Controller
Activity
IView
GDGFoz
Model/View/Presenter
Contract
GDGFoz
App
GDGFoz
Model/View/Presenter// View contract
interface RepositoriesContract{
interface View{
fun setRepositories(repositories: List<Repository>)
}
}
// Activity/Fragment
class RepositoriesActivity : AppCompatActivity(), RepositoriesContract.View {
...
// Passing the View to Presenter
presenter = RepositoriesPresenter(this)
override fun setRepositories(repositories: List<Repository>) {
// Setting data to view
}
GDGFoz
Model/View/Presenter// Presenter contract
interface RepositoriesContract {
interface Presenter {
fun getAllRepositories()
}
}
// Passing View to Presenter
class RepositoriesPresenter(val view: RepositoriesContract.View): RepositoriesContract.Presenter
lateinit var model: RepositoryModel
override fun getAllRepositories() {
// Call model and set data to View
// Can be RxJava
var repositories:List<Repository> = model.getAllRepositories()
view.setRepositories(repositories)
}
GDGFoz
Model/View/ViewModel
• Microsoft
• 2005
• Orientado à eventos
GDGFoz
Model/View/ViewModel
GDGFoz
MVVM// ViewModelclass RepositoriesViewModel(var model: RepositoryDataSource) {
...
fun getAllRepositories() {
// Return an Observable
fun getAllRepositories(): Observable<List<Repository>> = model.getAllRepositories()
}
GDGFoz
MVVM// Activity/Fragment
class RepositoriesActivity : AppCompatActivity() {
private val viewModel: RepositoriesViewModel by lazy {RepositoriesViewModel(RepositoryModel())
}
private val mDisposable = CompositeDisposable()...
GDGFoz
MVVM
// Activity/Fragment
override fun onCreate(savedInstanceState: Bundle?) {
...
mDisposable.add(
viewModel.getAllRepositories()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
// onNext
this::setRepositories,
// onError
{ error -> Log.d(TAG, "Error: ", error) },
// onComplete
{ Log.d(TAG, "Completed: ") }
)
)
// Activity/Fragment
fun setRepositories(repositories: List<Repository>) {
// Setting data to view
}
GDGFoz
Android lifecycle
// Activity/Fragment
override fun onDestroy() {
super.onDestroy()
mDisposable.dispose()
}
GDGFoz
MVP/MVVMclass Presenter: IPresenter {
override fun getAllRepositories() {
...
view.setRepositories(repositories)
}
}
class ViewModel {
fun getAllRepositories(): Observable<List<Repository>> {
...
}
}
GDGFoz
MVVM testsclass RepositoriesViewModelTest {
@Mock
lateinit var model: RepositoryDataSource
lateinit var viewModel: RepositoriesViewModel
…
@Before
fun setup()
{
model = mock()
viewModel = RepositoriesViewModel(model)
}
GDGFoz
MVVM tests@Test
fun `get repositories emit correct values`() {
val repositories = listOf(Repository(name = "Test"), Repository(name = "Test2"
`when`(model.getAllRepositories()).thenReturn(Observable.just(repositories))
viewModel.getAllRepositories()
.test()
.assertNoErrors()
.assertComplete()
.assertValue(repositories)
}
GDGFoz
Save states
// Save
override fun onSaveInstanceState(state: Bundle?) {
super.onSaveInstanceState(state)
//Can create Bundle here
state.putAll(viewModel.getState())
}
// Restore
override fun onRestoreInstanceState(bundle: Bundle) {
super.onRestoreInstanceState(bundle)
viewModel.restoreState(bundle)
}
GDGFoz
Activity
Fragment
CustomView
CustomView
P / VM
View
GDGFoz
Lógica de UI ?
• Tem lógica de UI ?
• Sim - Presenter/ViewModel (Testes)
• Não - View
GDGFoz
Qual ?
• Classes Android sem lógica ?
• Pode ser testado (unit test) ?
• Suas classes tem uma responsabilidade bem definida ?
GDGFoz
Links
• http://reactivex.io/
• https://github.com/ReactiveX/RxJava/
• https://kotlinlang.org/
• https://medium.com/upday-devs/android-architecture-patterns-part-3-model-view-viewmodel-e7eeee76b73b
• https://github.com/googlesamples/android-architecture
• https://github.com/hussanhijazi/retrofit-rxjava-databinding/tree/kotlin-mvvm
Obrigado