Caique Oliveira - Android Developer na Stone , fala sobre Arquitetura para projetos Android no Android Dev Conference 2017.
https://eventos.imasters.com.br/android-devconference/
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. 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. 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. 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. 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
}
}
36. 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)
37. 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)
38. 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()
}
39. 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
40. 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)
}
41. 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”
}
45. 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)
46. 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
})
}
}
47. 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)
}
}
48. 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
}
})
}
49. 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())
}
}