Android data-binding & RxJava

   2016-10-17 0
核心提示:Tango 公司的开发团队,把Android Data Binding 和RxJava 结合到一起。 下面来看看他们是如何使用的。 比如下面是一个按钮中使用的 binding 表达式:Buttonandroid:layout_width=wrap_contentandroid:layout_height=wrap_contentandroid:enabled=@{StringUtil

Tango 公司的开发团队,把Android Data Binding 和RxJava 结合到一起。 下面来看看他们是如何使用的。

比如下面是一个按钮中使用的 binding 表达式:

<Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:enabled="@{StringUtils.isNotNullOrEmpty(viewModel.firstName) && StringUtils.isNotNullOrEmpty(viewModel.lastName)}"
    android:onClick="@{() -> viewModel.buttonClicked()}"
    android:text="@string/btn_hello"/>

上面使用一个表达式来确定 enabled 的状态。但是上面的表达式虽然可以正常工作,但是还是有些缺陷的:

  1. 无法针对这个表达式编写单元测试
  2. 在其他的 XML 布局文件中无法重用这个表达式
  3. 表达式太复杂了,不太容易理解

因此可以把上面的表达式优化为下面这样:

<Button
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:enabled="@{viewModel.helloButtonEnabled}"
  android:onClick="@{() -> viewModel.buttonClicked()}"
  android:text="@string/btn_hello_rx"/>

在 ViewModel 中创建一个类型为 ObservableField 的 helloButtonEnabled 变量,该变量绑定到 View 的enabled 属性。下面是 MainViewModel 类的代码:

public static class MainViewModel {
 
    public ObservableField<String> firstName = new ObservableField<>();
    public ObservableField<String> lastName = new ObservableField<>();
    public ObservableField<String> helloText = new ObservableField<>();
    public ObservableBooleanhelloButtonEnabled = new ObservableBoolean(false);
 
    public MainViewModel() {
 
        Observable.combineLatest(toObservable(firstName), toObservable(lastName), (firstName, lastName) -> StringUtils.isNotNullOrEmpty(firstName) && StringUtils.isNotNullOrEmpty(lastName))
                .subscribe(result -> {
                    helloButtonEnabled.set(result);
                    if (!result) {
                        helloText.set(StringUtils.EMPTY);
                    }
                }, Throwable::printStackTrace);
    }
 
    public void buttonClicked() {
        helloText.set(String.format("Hello %s %s !", firstName.get(), lastName.get()));
    }
}
 

注意上面的代码在构造函数中, 使用 combineLatest 把 firstName 和 lastName 组合起来来判断 helloButtonEnabled 的值。如果 firstName 或者 lastName 为 空 则设置按钮不可以点击,并且清空 helloText 的文本。

单元测试也很方便编写:

public class MainViewModelTests {
 
    @Test
    public void mainViewModel_firstName_lastName_helloButtonEnabledSetToTrue() throws Exception {
        MainViewModelmainViewModel = new MainViewModel();
 
        assertFalse(mainViewModel.helloButtonEnabled.get());
 
        mainViewModel.firstName.set("a");
        mainViewModel.lastName.set("b");
 
        assertTrue(mainViewModel.helloButtonEnabled.get());
    }
 
    @Test
    public void mainViewModel_firstName_lastNameEmpty_helloButtonEnabledSetToFalse() throws Exception {
        MainViewModelmainViewModel = new MainViewModel();
 
        mainViewModel.firstName.set("a");
        mainViewModel.lastName.set("");
 
        assertFalse(mainViewModel.helloButtonEnabled.get());
    }
}
 

上面这种方式的好处:

  1. 业务逻辑封装到 ViewModel 中
  2. 业务逻辑可以测试
  3. XML 布局文件可读性更好
  4. 没有重复的代码

下图为示例应用的效果,代码位于 github: https://github.com/TangoAgency/android-data-binding-rxjava

如何做到的呢?

上面的代码核心点在于 toObservable 这个函数的实现。该函数使用 ObservableField 的 addOnPropertyChangedCallback 函数把异步回调函数封装为 RxJava 的 Observable。代码如下:

import android.databinding.ObservableField;
import android.support.annotation.NonNull;
 
import rx.AsyncEmitter;
import rx.Observable;
 
import static android.databinding.Observable.OnPropertyChangedCallback;
 
public class RxUtils {
 
    private RxUtils() {
    }
 
    public static <T> Observable<T> toObservable(@NonNull final ObservableField<T> observableField) {
        return Observable.fromEmitter(asyncEmitter -> {
 
            final OnPropertyChangedCallbackcallback = new OnPropertyChangedCallback() {
                @Override
                public void onPropertyChanged(android.databinding.ObservabledataBindingObservable, int propertyId) {
                    if (dataBindingObservable == observableField) {
                        asyncEmitter.onNext(observableField.get());
                    }
                }
            };
 
            observableField.addOnPropertyChangedCallback(callback);
 
            asyncEmitter.setCancellation(() -> observableField.removeOnPropertyChangedCallback(callback));
 
        }, AsyncEmitter.BackpressureMode.LATEST);
    }
}
 

参考 把异步回调操作转换到 RxJava 中 来了解如何封装 Observable。

 
标签: RxJava 安卓开发
反对 0举报 0 评论 0
 

免责声明:本文仅代表作者个人观点,与乐学笔记(本网)无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
    本网站有部分内容均转载自其它媒体,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责,若因作品内容、知识产权、版权和其他问题,请及时提供相关证明等材料并与我们留言联系,本网站将在规定时间内给予删除等相关处理.

  • RxJava系列番外篇:一个RxJava解决复杂业务逻辑
    之前写过一系列RxJava1的文章,也承诺过会尽快有RxJava2的介绍。无奈实际项目中还未真正的使用RxJava2,不敢妄动笔墨。所以这次还是给大家分享一个使用RxJava1解决问题的案例,希望对大家在使用RxJava的时候有一点点启发。对RxJava还不了解的同学可以先去看看
  • 第151期:一个RxJava解决复杂业务逻辑的案例
    第151期:一个RxJava解决复杂业务逻辑的案例
    第151期:一个RxJava解决复杂业务逻辑的案例深度讨论 基本特效:饿了么丝滑无缝过度搜索栏的实现 diycode 帖子优先,就给上个头条吧。Android开发 一个RxJava解决复杂业务逻辑的案例 本文给大家分享一个使用RxJava解决问题的案例,希望对大家在使用RxJava的时
  • [原]打造RxJava生命周期管理框架RxLife
    在前边RxJava实战技巧大全一文中,我们介绍了RxJava使用过程中常见的应用场景和可能遇到的问题,其中我们谈到利用RxLifeCycle来管理RxJava的生命周期,避免内存泄漏问题,今天自己动手打生命周期管理框RxLife来加深对RxJava的认识。详解Subject什么是Subject
  • 实践!业余时间做的一款阅读类App (MVP + RxJava + Retrofit)
    实践!业余时间做的一款阅读类App (MVP + RxJa
    整体项目基于 MVP + RxJava + Retrofit 通过 Retrofit 实现了无网缓存 基于 MVP 模式对 Activity 和 Fragment 封装了两个基类,同样适用于非 MVP 的实现。 运用 RecyclerView 加载了多种复杂布局 用到了一些很棒的第三方库GitHub 项目地址 : https://github.c
  • Android 网络请求框架之Rxjava+Retrofit
    Android 网络请求框架之Rxjava+Retrofit
    前言RxJava和Retrofit也火了一段时间了,不过最近一直在学习ReactNative和Node相关的姿势,一直没有时间研究这些新东西,最近有个项目准备写,打算先用 Android 写一个Demo出来,却发现Android的世界发生了天翻地覆的变化,EventBus和OKHttp啥的都不见了,RxJ
点击排行