O slideshow foi denunciado.
Utilizamos seu perfil e dados de atividades no LinkedIn para personalizar e exibir anúncios mais relevantes. Altere suas preferências de anúncios quando desejar.

TDC2016SP - Trilha Mobile

145 visualizações

Publicada em


MVVM em aplicações Mobile - Comparação entre iOS, Android e Xamarin

Publicada em: Educação
  • Seja o primeiro a comentar

  • Seja a primeira pessoa a gostar disto

TDC2016SP - Trilha Mobile

  1. 1. 11 MVVM - IOS, ANDROID, XAMARIN GUILHERME ENDRES
  2. 2. 22 MVVM - IOS, ANDROID, XAMARIN GUILHERME ENDRES
  3. 3. MVVM != !=
  4. 4. MVVM IOS
  5. 5. IOS | MVC Model View Controller
  6. 6. IOS | MVC Model View View Controller
  7. 7. Massive View Controller IOS | MVC
  8. 8. M V V M
  9. 9. Model ViewModelView View Controller IOS | MVVM
  10. 10. Model Nome Preço Teor Alcoólico Marca IOS | MODEL
  11. 11. Model ViewModelView View Controller IOS | MVVM
  12. 12. ViewModel BANCO DE DADOS VALIDAÇÃO DE DADOS MANIPULAÇÃO DE MODELOS IOS | VIEW MODEL
  13. 13. Model ViewModelView View Controller IOS | MVVM
  14. 14. ViewModel View Controller 4.5% R$ 5,00 TDCBeer Pale Ale Model
  15. 15. swift
  16. 16. var beerView = BeerView( beerViewModel )
  17. 17. var beerView = BeerView( beerViewModel ) var beerViewController = BeerViewController() beerViewController.beerView = beerView
  18. 18. var beerViewController = BeerViewController( beerViewModel)
  19. 19. Model ViewModelView View Controller IOS | MVVM
  20. 20. ViewModel View Controller beerViewModel.quantity = 5 imageView.image = beerViewModel.image beerViewModel.quantity = textField.text beerViewModel.image { image in imageView.image = image } IOS | COMUNICAÇÃO
  21. 21. DELEGATE KVO BINDING THIRD PARTY
  22. 22. beerViewModel.addObserver(self, forKeyPath: "userImage", options: .New, context: &imageContext) BINDING | KVO
  23. 23. beerViewModel.addObserver(self, forKeyPath: "userImage", options: .New, context: &imageContext) deinit { beerViewModel.removeObserver(self, forKeyPath: "userImage") } BINDING | KVO
  24. 24. override func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, change: [NSObject: AnyObject], context: UnsafeMutablePointer<Void>) { if context == &imageContext { self.imageView.image= change[NSKeyValueChangeNewKey] } } BINDING | KVO
  25. 25. override func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, change: [NSObject: AnyObject], context: UnsafeMutablePointer<Void>) { if context == &imageContext { self.imageView.image= change[NSKeyValueChangeNewKey] } else if context == &quantityContext { self.textField.text = change[NSKeyValueChangeNewKey] } } BINDING | KVO
  26. 26. override func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, change: [NSObject: AnyObject], context: UnsafeMutablePointer<Void>) { if context == &imageContext { self.imageView.image= change[NSKeyValueChangeNewKey] } else if context == &quantityContext { self.textField.text = change[NSKeyValueChangeNewKey] } } BINDING | KVO else if context == &context { self.variable = change[NSKeyValueChangeNewKey] }else if context == &context { self.variable = change[NSKeyValueChangeNewKey] } else if context == &context { self.variable = change[NSKeyValueChangeNewKey] } else if context == &context { self.variable = change[NSKeyValueChangeNewKey] else if context == &context { self.variable = change[NSKeyValueChangeNewKey] } else if context == &context { self.variable = change[NSKeyValueChangeNewKey } else if context == &context { self.variable = change[NSKeyValueChangeNewKey } else if context == &context { self.variable = change[NSKeyValueChangeNewKey] } else if context == &context { self.variable = change[NSKeyValueChangeNewKey] } else if context == &context { self.variable = change[NSKeyValueChangeNewKey] }
  27. 27. DELEGATE KVO BINDING THIRD PARTY
  28. 28. protocol BeerViewModelDelegate { func viewModelDidUpdate() } BINDING | DELEGATE
  29. 29. protocol BeerViewModelDelegate { func viewModelDidUpdate() } class BeerViewModel { var delegate: BeerViewModelDelegate? //Quando atualizar delegate!.viewModelDidUpdate() } BINDING | DELEGATE
  30. 30. class ViewController { beerViewModel.delegate = self func viewModelDidUpdate() { imageView.image = beerViewModel.userImage } } BINDING | DELEGATE
  31. 31. DELEGATE KVO BINDING THIRD PARTY
  32. 32. Swift ReactiveCocoa4 BINDING | THIRD PARTY
  33. 33. <~<~
  34. 34. errorLabel.rac_text <~ userViewModel.errorMessage errorLabel.rac_hidden <~ userViewModel.usernameCorrect UserViewController
  35. 35. errorLabel.rac_text <~ userViewModel.errorMessage errorLabel.rac_hidden <~ userViewModel.usernameCorrect enterButton.rac_hidden <~ userViewModel.hiddenButton UserViewController
  36. 36. imageView.image <~ beerViewModel .userImage BeerViewController
  37. 37. UNIT TEST
  38. 38. let userViewModel: UserViewModel = UserViewModel() IOS | UNIT TEST
  39. 39. let userViewModel: UserViewModel = UserViewModel() userViewModel.username.value = "Skywalker" IOS | UNIT TEST
  40. 40. let userViewModel: UserViewModel = UserViewModel() userViewModel.username.value = "Skywalker" userViewModel.saveUser().on( completed: { // success }, failed: { error in // fail }).start() IOS | UNIT TEST
  41. 41. userViewModel.saveUser().on( completed: { // success }, failed: { error in // fail }).start() IOS | UNIT TEST
  42. 42. userViewModel.username.value = "Darth Vader" userViewModel.saveUser().on( completed: { // fail }, failed: { error in // success }).start() IOS | UNIT TEST
  43. 43. MVVM ANDROID
  44. 44. MVVM?
  45. 45. MVVM Data Binding!
  46. 46. MVVM Data Binding! Android?
  47. 47. MVVM Data Binding! Android? SIM!
  48. 48. ANDROID DATA BINDING LIBRARY
  49. 49. ATIVANDO DATA BINDING android {
 ....
 dataBinding {
 enabled = true
 }
 }
  50. 50. ANTES… <EditText
 android:id="@+id/beer_count_edit_text"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:gravity="end"
 android:inputType="numberDecimal"
 android:singleLine="true" /> EditText beerCountEditText = (EditText)findViewById(R.id.beer_count_edit_text);
 beerCountEditText.setText(beerViewModel.getBeerCount());
  51. 51. USANDO DATA BINDING LIBRARY <data>
 <variable
 name="beerViewModel"
 type="com.arctouch.beerbind.beer.BeerCountViewModel" />
 </data> <EditText
 android:id="@+id/beer_count_edit_text"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:gravity="end"
 android:inputType="numberDecimal"
 android:singleLine="true" />
  52. 52. USANDO DATA BINDING LIBRARY <EditText
 android:id="@+id/beer_count_edit_text"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:gravity="end"
 android:inputType="numberDecimal"
 android:singleLine="true" android:text="@{beerViewModel.beerCountText}" /> <data>
 <variable
 name="beerViewModel"
 type="com.arctouch.beerbind.beer.BeerCountViewModel" />
 </data>
  53. 53. TWO-WAY BINDING <EditText
 android:id="@+id/beer_count_edit_text"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:gravity="end"
 android:inputType="numberDecimal"
 android:singleLine="true" android:text="@{beerViewModel.beerCountText}" /> <data>
 <variable
 name="beerViewModel"
 type="com.arctouch.beerbind.beer.BeerCountViewModel" />
 </data>
  54. 54. TWO-WAY BINDING <EditText
 android:id="@+id/beer_count_edit_text"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:gravity="end"
 android:inputType="numberDecimal"
 android:singleLine="true" android:text="@{beerViewModel.beerCountText}" app:addTextChangedListener="@{beerViewModel.beerCountTextWatcher}" /> <data>
 <variable
 name="beerViewModel"
 type="com.arctouch.beerbind.beer.BeerCountViewModel" />
 </data>
  55. 55. TWO-WAY BINDING <EditText
 android:id="@+id/beer_count_edit_text"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:gravity="end"
 android:inputType="numberDecimal"
 android:singleLine="true" android:text="@{beerViewModel.beerCountText}" app:addTextChangedListener="@{beerViewModel.beerCountTextWatcher}" /> public TextWatcher getBeerCountTextWatcher() {
 return new TextWatcher() { 
 @Override
 public void afterTextChanged(Editable s) {
 setBeerCount(Integer.parseInt(s.toString()));
 }
 };
 }
  56. 56. ACTIVITY @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 ActivityBeerBinding binding = 
 DataBindingUtil.setContentView(this, R.layout.activity_beer); 
 BeerCountViewModel beerViewModel = 
 new BeerCountViewModel(new BeerCountModel());
 binding.setBeerViewModel(beerViewModel);
 }
  57. 57. ACTIVITY @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 ActivityBeerBinding binding = 
 DataBindingUtil.setContentView(this, R.layout.activity_beer); 
 BeerCountViewModel beerViewModel = 
 new BeerCountViewModel(new BeerCountModel());
 binding.setBeerViewModel(beerViewModel);
 }
  58. 58. FRAGMENT @Override
 public View onCreateView(…){ 
 ActivityBeerBinding binding =
 DataBindingUtil.inflate(inflater, R.layout.activity_beer, container, false); 
 BeerCountViewModel viewModel =
 new BeerCountViewModel(new BeerCountModel()); 
 binding.setBeerViewModel(viewModel);
 return binding.getRoot();
 }
  59. 59. FRAGMENT @Override
 public View onCreateView(…){ 
 ActivityBeerBinding binding =
 DataBindingUtil.inflate(inflater, R.layout.activity_beer, container, false); 
 BeerCountViewModel viewModel =
 new BeerCountViewModel(new BeerCountModel()); 
 binding.setBeerViewModel(viewModel);
 return binding.getRoot();
 }
  60. 60. VIEW MODEL public class BeerCountViewModel extends BaseObservable {
 
 private int beerCount;
 
 @Bindable
 public int getBeerCount() {
 return beerCount;
 }
 
 public void setBeerCount(int beerCount) {
 this.beerCountModel.setBeerCount(beerCount);
 notifyPropertyChanged(BR.beerCount);
 }
 
 }
  61. 61. VIEW MODEL extends BaseObservable {
 t beerCount) {
 BeerCount(beerCount);
 R.beerCount);
 • Classe base • Implementa a interface Observable • Usado pra notificar a mudanças para a view
  62. 62. VIEW MODEL public class BeerCountViewModel extends BaseObservable {
 
 private int beerCount;
 
 @Bindable
 public int getBeerCount() {
 return beerCount;
 }
 
 public void setBeerCount(int beerCount) {
 this.beerCountModel.setBeerCount(beerCount);
 notifyPropertyChanged(BR.beerCount);
 }
 
 }
  63. 63. VIEW MODEL ublic class BeerCountViewModel extends BaseObservable {
 private int beerCount;
 @Bindable
 public int getBeerCount() {
 return beerCount;
 }
 public void setBeerCount(int beerCount) {
 this.beerCountModel.setBeerCount(beerCount);
 notifyPropertyChanged(BR.beerCount);
 }

  64. 64. VIEW MODEL ublic class BeerCountViewModel extends BaseObservable {
 private int beerCount;
 @Bindable
 public int getBeerCount() {
 return beerCount;
 }
 public void setBeerCount(int beerCount) {
 this.beerCountModel.setBeerCount(beerCount);
 notifyPropertyChanged(BR.beerCount);
 }

  65. 65. CUSTOM SETTER @BindingAdapter("app:imageUrl")
 public static void loadImage(ImageView imageView, String url) {
 Glide.with(imageView.getContext())
 .load(url)
 .into(imageView); } <ImageView
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:layout_marginTop="@dimen/default_margin"
 app:imageUrl="@{beerViewModel.imageUrl}" />
  66. 66. ANDROID DATA BINDING • One-way binding: • Two-way binding: • Custom setters:
  67. 67. ANDROID DATA BINDING • One-way binding: • Two-way binding: • Custom setters:
  68. 68. ANDROID DATA BINDING • One-way binding: • Two-way binding: • Custom setters:
  69. 69. ANDROID DATA BINDING • One-way binding: • Two-way binding: • Custom setters:
  70. 70. MVVM XAMARIN
  71. 71. No .NET desde 2008
  72. 72. XAMARIN | MVVM VIEW (XAML) VIEWMODEL MODEL Command BindingContext / Binding Read/Update INotifyPropertyChanged BindableObject
  73. 73. using System;
 
 namespace System.ComponentModel
 {
 public interface INotifyPropertyChanged
 {
 //
 // Events
 //
 event PropertyChangedEventHandler PropertyChanged;
 }
 } XAMARIN | Data Binding
  74. 74. XAMARIN | Data Binding public abstract class BaseViewModel : INotifyPropertyChanged
 {
 public event PropertyChangedEventHandler PropertyChanged;
 
 protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
 {
 PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
 }
 }

  75. 75. XAMARIN | Data Binding private string errorMessage;
 public string ErrorMessage
 {
 get { return this.errorMessage; }
 set
 {
 this.errorMessage = value;
 OnPropertyChanged();
 }
 }
  76. 76. XAMARIN | Data Binding - Genérico protected bool SetPropertyAndNotify<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
 {
 if (Equals(storage, value))
 {
 return false;
 }
 
 storage = value;
 OnPropertyChanged(propertyName);
 return true;
 }
 this.myField = value;
  77. 77. XAMARIN | Data Binding private string errorMessage;
 public string ErrorMessage
 {
 get { return this.errorMessage; }
 set
 {
 this.errorMessage = value;
 OnPropertyChanged();
 }
 }
  78. 78. XAMARIN | Data Binding private string errorMessage;
 public string ErrorMessage
 {
 get { return this.errorMessage; }
 set { SetPropertyAndNotify(ref this.errorMessage, value); }
 }

  79. 79. XAMARIN | Data Binding <Label
 Text="{Binding ErrorMessage}"
 TextColor="White"
 FontSize="17"
 HorizontalTextAlignment="Center"
 FontFamily="HelveticaNeue-CondensedBold"
 HorizontalOptions="Center"
 HeightRequest="20"/>
  80. 80. <ContentPage.BindingContext>
 <custom:UserViewModel />
 </ContentPage.BindingContext> UserView.xaml
  81. 81. <StackLayout> <Label Text="{Binding ErrorMessage}” />
 <Entry Placeholder="Digite seu nome aqui"
 Text="{Binding Username}"/>
 <Button Text="ENTER"
 Command="{Binding EnterCommand}” IsVisible="{Binding IsUsernameValid}”/> </StackLayout> UserView.xaml
  82. 82. public class UserViewModel : BaseViewModel
 public string Username
 {
 get { return this.username; }
 set
 {
 SetPropertyAndNotify(ref this.username, value);
 ValidateUsername();
 }
 } UserViewModel Apenas validação simples!
 
 Sem longos processamentos e/ou chamadas assíncronas.
 Ex:. APIs ou banco de dados
  83. 83. <Slider Maximum=“20" Minimum="0"
 Value="{Binding DrankBeersCount, Mode=TwoWay}"/>
 BeerView.xaml
  84. 84. public int DrankBeersCount
 {
 get
 {
 return this.drankBeersCount;
 }
 set
 {
 SetPropertyAndNotify(ref this.drankBeersCount, value);
 OnPropertyChanged(nameof(DrunkenPersonImage));
 }
 }
 
 public string DrunkenPersonImage
 {
 get { return GetBeerImage(DrankBeersCount); }
 }
 BeerViewModel
  85. 85. COMPARAÇÃO MVVM IOS/ANDROID/XAMARIN
  86. 86. Suporte MVVM | Comparação entre plataformas Anunciado em 2015/Android M + No .NET desde 2008 Delegate / KVO / ReactiveCocoa
  87. 87. iOS: https://github.com/gfendres/ractdc2016 Android: https://github.com/thiagocechetto/BeerBind Xamarin: https://github.com/oberdanf/tdc2016mvvm
  88. 88. OBRIGADO. Big Brains Wanted Join our team! Go to arctouch.com/brjobs guilherme.endres@arctouch.com

×