Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Arquitetura para android

Arquitetura para android

José Caique Oliveira

August 23, 2017
Tweet

More Decks by José Caique Oliveira

Other Decks in Programming

Transcript

  1. Agenda - Introdução - Problemas comuns no desenvolvimento - Arquitetura

    Limpa(Clean Architecture) - Dependências úteis
  2. No começo do aprendizado - Tudo na activity ou fragment

    - Pouca preocupação com organização - View Einstein - Não me chamo MainActivity atoa
  3. Arquitetura de software Como eu posso criar um projeto de

    forma a não ser xingado por quem pegar meu código?
  4. Arquitetura de software - Desacoplar o código - Passar a

    usar o framework ao invés de depender dele - Separar responsabilidades - Testabilidade - Manutenibilidade - Escalabilidade
  5. Desacoplando do framework - A view deve apenas exibir informações

    - Remover lógica da sua view - Remover acesso a banco de dados - Remover request
  6. Einstein Activity class EinsteinActivity: AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?)

    { showList() } fun showList() { retrofit.enqueue(object : Callback<Contacts> { override fun onResponse(call: Call<Contacts>, response: Response<Contacts>) { // exibe lista } override fun onFailure(call: Call<Contacts>, t: Throwable) { // exibe erro } }) } }
  7. Desacoplando do framework interface Contract { interface View { fun

    showContacts(contacts: ArrayList<Contacts>) fun showError(msg: String) } } class MainActivity : AppCompatActivity(), Contract.View { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } override fun showContacts(contacts: ArrayList<Contacts>) { //exibe lista } override fun showError(msg: String) { //mostra erro } }
  8. Desacoplando do framework interface Contract { interface View { fun

    showContacts(contacts: ArrayList<Contacts>) fun showError(msg: String) } interface Presenter { fun loadContacts() } } class Presenter : Contract.Presenter { override fun loadContacts(){ // faz algo aqui } }
  9. Modelos de arquitetura - MVP - MVVM - Viper -

    Clean Architecture - Hexagonal - ...
  10. Clean Architecture - Depender o mínimo possível de framework -

    Depender de comportamentos(interface) - Núcleo Testável
  11. Q?

  12. Domain - Regras de negócio - Entidades - Sabe executar

    uma operação - Dependência apenas da linguagem de programação usada
  13. interface PhotoRepository { fun photoUpload(string: String, callback: ResultCallback) } interface

    ResultCallback(){ fun success(result:String) fun 4xx() fun 5xx() fun timeOut() } data class User( val id: Int, val name: String, val email: String, val phone: String, val birthDate: Date, val photoUrl: String)
  14. Data - Entrada e saída de dados - Rest -

    Banco de dados - Cache - Deve ser fácil de substituir - Implementação dos contratos definidos pelo Domain(Repository)
  15. class PhotoManager : PhotoRepository { var photoService: PhotoService override fun

    photoUpload(string: String, callbackResult :ResultCallback){ photoService.upload(string).enqueue(object : Callback<String>{ override fun onResponse(call: Call<String>, response:Response<String>) { callbackResult.success(response.body()) } override fun onFailure(call: Call<String>, t: Throwable) { //trata erro e passa para callbackResult } }) } } interface PhotoRepository { fun photoUpload(string: String, callback: ResultCallback) } interface ResultCallback(){ fun success(result:String) fun 4xx() fun 5xx() fun timeOut() }
  16. Presentation Sabe como se comunicar com o domínio da aplicação

    Fornece os dados para o framework - Data formatada - Entrega tudo mastigado para a view só exibir
  17. class SearchPresenter() : SearchContract.Presenter { var useCase = SearchUseCase() var

    view: SearchContract.View override fun search(name: String) { useCase.execute(name,object : OnComplete { override fun success(result: String) { view.showSearch(result) } override fun error(t: Throwable) { view.showError(“msg”) } }) } } interface OnComplete { fun success(result: String) fun error(t: Throwable) }
  18. Establishment{ id = 123 address{ address = "R. Visconde", number

    = "414", state = "Rio de Janeiro", city = "Rio de Janeiro", district = "Ipanema", zip_code = "22410-002", latitude = 22.9837684, longitude = -43.2074878 } name = "Estabelecimento do bolinha" status : enum = [open, close] } Data Domain Presentation Establishment{ id = 123 address{ "address": "R. Visconde", "number": "414", "state": "Rio de Janeiro", "city": "Rio de Janeiro", "district": "Ipanema", "zip_code": "22410-002" } name = "Estabelecimento do bolinha" distance = 1400 status= true } Establishment{ id = 123 address=”Rua visconde, 414, Rio de janeiro - Rj” name = "Estabelecimento do bolinha" distance = 1,4Km status= “Aberto” }
  19. Passo a passo Defina uma interface para repository Defina seus

    casos de uso e suas entidades interface ResultCallback{ fun success(profile:Profile) fun 4xx() fun 5xx() fun error() } interface AuthenticationRepository{ fun login(credential: Credential, callback:ResultCallback) } class LoginUseCase(){ fun login(credentials: Credentials){ return authenticationRepository.login(credentials,callback) } } data class Profile(var name: String, var age : Int) data class Credential(var email: String, var password)
  20. Passo a passo Implemente seu repository interface Service { @Get(...)

    fun signIn(@Body credential: Credential): Call<ProfileResponse> } class AuthenticatorManager(): AuthenticationRepository{ val service : Service override fun login(credential,callback){ service.signIn(credential).enqueue( success(profileResponse){ callback.success(Mapper.toProfile(responsse)) } error(){ // controle o erro aqui }) } }
  21. Passo a passo Defina o contrato para View e Presenter

    interface Contract { inteface View(){ fun showProfile(profile: ProfilePresentation) } interface Presenter { fun attachView(view: View) fun login(email: String, password: String) } }
  22. Passo a passo Implemente o presenter inteface OnComplete{ fun onSuccess()

    fun onError() } class Presenter(loginUseCase: LoginUseCase): Contract.Presenter{ val view : View?=null override attachView(view : View){ this.view = view } override login(email: String, password : String){ loginUseCase.login(Credential(email,password),onComplete{ onSuccess(response){ view?.showProfile(Mapper.toProfilePresenter(response)) } onError(throwable : Throwable){ //trata erro aqui } }) }
  23. Passo a passo Implemente o contrato da View class ProfileFragment

    : Fragment(), Contract.View{ val presenter : Contract.Presenter ?= null override fun onViewCreated(....) { super.onViewCreated(....) presenter = Presenter(...) presenter.attachView(this) } override showProfile(profile: ProfilePresentation){ nameTextView.text = profile.name ageTextView.text = profile.age } override showErrorLogin(msg: String){ toast(msg) } @OnClick(R.id.loginButton) fun onClick(){ presenter.login(emailEditText.text.toString, passwordEditText.text.toString()) } }