MVVM com RxJava com Kotlin

Post on 22-Jan-2018

82 views 2 download

Transcript of MVVM com RxJava com Kotlin

MVVM com RxJava em Kotlin no Android

GDGFoz

Quem ?• Houssan Ali Hijazi - hussanhijazi@gmail.com

• 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