Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Android Dev Conference 2017 - Arquitetura para projetos Android

104 views

Published on

Caique Oliveira - Android Developer na Stone , fala sobre Arquitetura para projetos Android no Android Dev Conference 2017.
https://eventos.imasters.com.br/android-devconference/

Published in: Technology
  • Be the first to comment

  • Be the first to like this

Android Dev Conference 2017 - Arquitetura para projetos Android

  1. 1. Arquitetura para projetos Android
  2. 2. Caique Oliveira Graduado em Ciência da computação - UFS Android developer - Stone Apresentação
  3. 3. Agenda - Introdução - Problemas comuns no desenvolvimento - Arquitetura Limpa(Clean Architecture) - Dependências úteis
  4. 4. No começo do aprendizado - Documentação oficial - Stack Overflow - Samples do google no github
  5. 5. No começo do aprendizado - Tudo na activity ou fragment - Pouca preocupação com organização - View Einstein - Não me chamo MainActivity atoa
  6. 6. No começo do aprendizado - Pouca separação de responsabilidades - Negócio misturado com framework
  7. 7. Por que isso acontece? A preocupação é de passar conhecimento sobre determinado assunto
  8. 8. Quais as consequências ?
  9. 9. Código acoplado
  10. 10. Dificuldade em resolver um erro
  11. 11. z23678’z23678
  12. 12. Realmente o erro foi corrigido? A correção não causa uma nova inconsistência?
  13. 13. Péssima testabilidade
  14. 14. - Ruim de escalar - Parece um hackathon
  15. 15. Resumindo...
  16. 16. Como melhorar? - Arquitetura de software - Aquela disciplina chata da faculdade serve pra alguma coisa!
  17. 17. Arquitetura de software Como eu posso criar um projeto de forma a não ser xingado por quem pegar meu código?
  18. 18. Arquitetura de software Definem estruturas de projeto visando uma boa qualidade de Software
  19. 19. Arquitetura de software - Desacoplar o código - Passar a usar o framework ao invés de depender dele - Separar responsabilidades - Testabilidade - Manutenibilidade - Escalabilidade
  20. 20. Desacoplando do framework - A view deve apenas exibir informações - Remover lógica da sua view - Remover acesso a banco de dados - Remover request
  21. 21. 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 } }) } }
  22. 22. 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 } }
  23. 23. 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 } }
  24. 24. Mas qual conceito aplicado?
  25. 25. Modelos de arquitetura - MVP - MVVM - Viper - Clean Architecture - Hexagonal - ...
  26. 26. Clean Architecture - Frameworks são detalhes(rest,banco,etc) - Casos de Usos são essenciais - Entidades são essenciais
  27. 27. Clean Architecture - Depender o mínimo possível de framework - Depender de comportamentos(interface) - Núcleo Testável
  28. 28. Dependency rule
  29. 29. Ubiratan Soares
  30. 30. Q?
  31. 31. Vamos lá - Camadas - Presentation - Domain - Data
  32. 32. Cada camada pode ser um módulo no Android Studio
  33. 33. Domain - Regras de negócio - Entidades - Sabe executar uma operação - Dependência apenas da linguagem de programação usada
  34. 34. Domain UseCasePayment.performPayment(...) UseCaseProfile.updateProfile(...) UseCaseProfile.uploadPhoto(...)
  35. 35. 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)
  36. 36. 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)
  37. 37. 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() }
  38. 38. 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
  39. 39. 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) }
  40. 40. 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” }
  41. 41. Organização de pacotes
  42. 42. Passo a passo
  43. 43. 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)
  44. 44. 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 }) } }
  45. 45. 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) } }
  46. 46. 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 } }) }
  47. 47. 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()) } }
  48. 48. Dependências úteis Dagger 2 Rxjava 2
  49. 49. Dúvidas?
  50. 50. Exemplo clean https://goo.gl/R2MzkK
  51. 51. Referências Escaping from framework(Ubiratan soares) https://speakerdeck.com/ubiratansoares/escaping-from-the-framework The clean architecture(Uncle Bob): https://8thlight.com/blog/uncle-bob/2012/08/13/the-clean-architecture.html
  52. 52. Obrigado! twitter: @_josecaique email: jcaique.jc@gmail.com slack android dev br: caique github: jcaiqueoliveira https://goo.gl/xjnnWs
  53. 53. Temos vagas! enter.stone.com.br

×