Slide 1

Slide 1 text

– Dead Poet’s Society “No matter what anybody tells you words and ideas can change the world.”

Slide 2

Slide 2 text

What is a Language? 1. First we listen, then speak and then we write. 2. We learn from structures. 3. Every word has a context. 4. Vocabulary and knowledge makes you express better. 5. The more we read, the more we learn the language.

Slide 3

Slide 3 text

What is a Computer Language? 1. First we listen, then speak and then we write. 2. We learn from structures. 3. Every word has a context. 4. Vocabulary and knowledge makes you express better. 5. The more we read, the more we learn the language.

Slide 4

Slide 4 text

Eloquence Fluent or persuasive speaking or writing.

Slide 5

Slide 5 text

Brevity Concise and exact use of words in writing or speech.

Slide 6

Slide 6 text

Boil Boilerplate Code With Data Binding

Slide 7

Slide 7 text

What? 1. Software Pattern to simplify UI development. 2. Binds UI elements to an App Domain Model. 3. Minimizes the glue code. 4. Incorporates Observer pattern. 5. Flexibility and broad compatibility (API level 7+). 6. Short and readable code.

Slide 8

Slide 8 text

What?

Slide 9

Slide 9 text

Why? private TextView name; private TextView age; protected void onCreate(Bundle savedInstanceState) { setContentView(R.layout.activity_main); name = (TextView) findViewById(R.id.name); age = (TextView) findViewById(R.id.age); } public void updateUI(User user) { if (user == null) { name.setText(null); age.setText(null); } else { name.setText(user.getName()); mLastName.setText(user.getLastName()); } } INSIPID BOILERPLATE BLOATED CLASSES REDUNDANT

Slide 10

Slide 10 text

Why? private @BindView(R.id.name) TextView name; private @BindView(R.id.age) TextView age; protected void onCreate(Bundle savedInstanceState) { setContentView(R.layout.activity_main); ButterKnife.bind(this); } public void updateUI(User user) { if (user == null) { name.setText(null); age.setText(null); } else { name.setText(user.getName()); mLastName.setText(user.getLastName()); } } Use Holdr? Use Butterknife?

Slide 11

Slide 11 text

Let’s boil the code! Boiler -plate Code Data Binding

Slide 12

Slide 12 text

Data Bound Code private ActivityMainBinding binding; protected void onCreate(Bundle savedInstanceState) { binding = DataBindingUtil.setContentView(this, R.layout.activity_main); } public void updateUI(User user) { binding.setUser(user); } Moustache Operator Generated Class View Model Layout Tag

Slide 13

Slide 13 text

How? android { .... dataBinding { enabled = true } } In your app-level build.gradle // For Activity binding = DataBindingUtil.setContentView(this, R.layout.layout); // For Fragment binding = DataBindingUtil.inflate(inflater, R.layout.layout, container, false); // For ViewHolder binding = DataBindingUtil.bind(view); In your View

Slide 14

Slide 14 text

Model View ViewModel Model View

Slide 15

Slide 15 text

Model View ViewModel

Slide 16

Slide 16 text

public class LoginModel extends BaseObservable { private String email; private String password; @Bindable public String getEmail() { return email; } public void setEmail(String email) { this.email = email; notifyPropertyChanged(BR.email); } @Bindable public String getPassword() { return password; } public void setPassword(String password) { this.password = password; notifyPropertyChanged(BR.password); } } View Model Java

Slide 17

Slide 17 text

View Model Kotlin public class LoginModel : BaseObservable() { @get:Bindable var email: String? = null set(email) { field = email notifyPropertyChanged(BR.email) } @get:Bindable var password: String? = null set(password) { field = password notifyPropertyChanged(BR.password) } }

Slide 18

Slide 18 text

public class LoginModel { public final ObservableField email = new ObservableField<>(); public final ObservableField password = new ObservableField<>(); public String getEmail() { return email.get(); } public String getPassword() { return password.get(); } public void setEmail(String email) { this.email.set(email); } public void setPassword(String password) { this.password.set(password); } } ObservableField<>

Slide 19

Slide 19 text

public class LoginModel implements Observable { public String email; public String password; private PropertyChangeRegistry registry = new PropertyChangeRegistry(); @Bindable public String getEmail() { return email; } public void setEmail(String email) { this.email = email; registry.notifyChange(this, BR.email); setLoginEnabled(isEmailAndPasswordSet()); } … @Override public void addOnPropertyChangedCallback(OnPropertyChangedCallback callback) { registry.add(callback); } @Override public void removeOnPropertyChangedCallback(OnPropertyChangedCallback callback) { registry.remove(callback); } } PropertyChangeRegistry

Slide 20

Slide 20 text

Login User enters email and password and taps Login

Slide 21

Slide 21 text

Event Handling

Slide 22

Slide 22 text

Event Handling public class MainActivity extends AppCompatActivity implements MainHandler { private ActivityMainBinding binding; private LoginModel model = new LoginModel(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = DataBindingUtil.setContentView(this, R.layout.activity_main); binding.setModel(model); binding.setHandler(this); } @Override public void onLoginClicked(String email, String password) { Toast.makeText(this, "Email: " + email + "\nPassword: " + password, Toast.LENGTH_SHORT).show(); } }

Slide 23

Slide 23 text

Event Handling public class Presenter { public void onCompletedChanged(Task task, boolean completed){} }

Slide 24

Slide 24 text

Two Way binding 2-way binding (Moustache with a nose)

Slide 25

Slide 25 text

public class LoginModel extends BaseObservable { private String email; private String password; private boolean loginEnabled; @Bindable public String getEmail() { return email; } public void setEmail(String email) { this.email = email; notifyPropertyChanged(BR.email); setLoginEnabled(isEmailAndPasswordSet()); } … private boolean isEmailAndPasswordSet() { return !TextUtils.isEmpty(getEmail()) && !TextUtils.isEmpty(getPassword()); } } Validations Good bye Text watchers "

Slide 26

Slide 26 text

Resources In Expressions: android:padding="@{isBig ? @dimen/bigPadding : @dimen/smallPadding}" Inline string formatting: android:text="@{@string/nameFormat(firstName, lastName)}" Inline plurals: android:text="@{@plurals/banana(bananaCount)}"

Slide 27

Slide 27 text

Null Safety UI won’t crash if user is null. @{user.card.number, default=@string/no_number} @{user.card.number ?? @string/no_number} Use Null Coalescing

Slide 28

Slide 28 text

RecyclerView Binding public class UserViewHolder extends RecyclerView.ViewHolder { static UserViewHolder create(LayoutInflater inflater, ViewGroup parent) { UserItemBinding binding = UserItemBinding.inflate(inflater, parent, false); return new UserViewHolder(binding); } private UserItemBinding mBinding; private UserViewHolder(UserItemBinding binding) { super(binding.getRoot()); mBinding = binding; } public void bindTo(User user) { mBinding.setUser(user); mBinding.executePendingBindings(); } }

Slide 29

Slide 29 text

RecyclerView Binding public UserViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) { return UserViewHolder.create(mLayoutInflater, viewGroup); } public void onBindViewHolder(UserViewHolder userViewHolder, int position) { userViewHolder.bindTo(mUserList.get(position)); }

Slide 30

Slide 30 text

Slide 31

Slide 31 text

Custom View Inflation public class CustomView extends LinearLayout implements CustomViewHandler { private LayoutCustomViewBinding binding; private CustomViewModel model = new CustomViewModel() public CustomView(Context context) { this(context, null); } public CustomView(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } public CustomView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context); } @Override public void init(Context context) { final LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); binding = LayoutCustomViewBinding.inflate(inflater, this, true); binding.setModel(model); binding.setHandler(this); } @Override public void onCustomViewClicked() { Toast.makeText(this, “Hello", Toast.LENGTH_SHORT).show(); } }

Slide 32

Slide 32 text

Binding Adapter @BindingAdapter({"app:src", "app:error"}) public static void loadImage(ImageView view, String srcUrl, Drawable error) { Glide.with(view.getContext()) .load(srcUrl) .error(error) .into(view); } @BindingAdapter(value = {“app:src", "app:error"}, requireAll = false) Has to be static

Slide 33

Slide 33 text

Binding Conversions @BindingConversion public static int convertBooleanToVisibility(boolean visible) { return visible ? View.VISIBLE : View.GONE; } Great use case for Empty/Placeholder Views …

Slide 34

Slide 34 text

Binding Fonts // In Application class FontCache fontCache = FontCache.getInstance(this); fontCache.addFont("droid", "DroidSerif.ttf"); // In BindingAdapter @BindingAdapter({"app:font"}) public static void setFont(TextView textView, String fontName) { textView .setTypeface(FontCache.getInstance(context) .get(fontName)); } // In Layout

Slide 35

Slide 35 text

Dependency Injection public interface TestableAdapter { @BindingAdapter("android:src") void setImageUrl(ImageView imageView, String url); } public interface DataBindingComponent { TestableAdapter getTestableAdapter(); } DataBindingUtil.setDefaultComponent(myComponent); ‐ or ‐ binding = MyLayoutBinding.inflate(layoutInflater, myComponent); In Activity In Application

Slide 36

Slide 36 text

Daggerification // Create BindingComponent @Singleton public class BindingComponent implements DataBindingComponent { BindingAdapter bindingAdapter; @Inject public BindingComponent() { } public BindingAdapter getBindingAdapter() { return bindingAdapter; } } // Create getter of BindingComponent AppComponent @Singleton @Component(modules = {AppModule.class}) public interface AppComponent { void inject(MyApplication myApplication); BindingComponent getBindingComponent(); } // Set DefaultComponent in Application class DataBindingUtil.setDefaultComponent(component.getBindingComponent());

Slide 37

Slide 37 text

Rxification compile 'com.jakewharton.rxbinding2:rxbinding:2.0.0' Button b = (Button)findViewById(R.id.button); Subscription buttonSub = RxView.clicks(b).subscribe(new Action1() { @Override public void call(Void aVoid) { // do some work here } }); RxBinding is a set of libraries that allow you to react to user interface events via the RxJava paradigm.

Slide 38

Slide 38 text

Search using RxBinding RxTextView.textChanges(searchTextView) .filter(new Func1 (){ @Override public Boolean call(String s) { return s.length() > 2; } }) .debounce(100, TimeUnit.MILLISECONDS) .switchMap(new Func1>>() { makeApiCall(s); }) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(/* attach observer */);

Slide 39

Slide 39 text

Tools DataBinding Support Plugin Alt + Enter

Slide 40

Slide 40 text

References 1. https://academy.realm.io/posts/data-binding-android-boyar-mount/ 2. https://academy.realm.io/posts/droidkaigi-kevin-pelgrims-data-real-world- data-binding/ 3. https://nullpointer.wtf/android/mvvm-architecture-data-binding-library/ 4. https://medium.com/@chet.deva/boil-boilerplate-code-with-data-binding- bb0ed0d0ceb6

Slide 41

Slide 41 text

Thank you Chetan Sachdeva Android Dev at Fueled @chetsachdeva