文档章节

详细解析 RxAndroid 的使用方式

 刘星石
发布于 2016/04/01 17:10
字数 4278
阅读 164
收藏 4

原文出处: C.L. Wang(@SpikeKing )   

RxAndroid是RxJava的扩展, 优雅地处理异步请求. RxAndroid配合Lambda表达式, 精简处理回调, 使程序更具有可读性. Rx作为Android最优秀的开源库之一, 极大地提高生产力, 我们需要掌握. 本文由浅入深, 介绍一些常见的使用方法, 并附有源码.

更多: http://www.wangchenlong.org/

本文代码的GitHub下载地址.

要点包含:
(1) 链式表达式的使用方式.
(2) Lambda的应用.
(3) Rx处理网络请求.
(4) 线程自动管理, 防止内存泄露.
(5) RxBinding绑定控件的异步事件.

Rx

基础

当然, 从一个崭新的HelloWorld项目开始.

添加Gradle配置.

Java

1

2

3

compile 'com.jakewharton:butterknife:7.0.1'

compile 'io.reactivex:rxandroid:1.1.0' // RxAndroid

compile 'io.reactivex:rxjava:1.1.0' // 推荐同时加载RxJava

RxAndroid是本文的核心依赖, 同时添加RxJava. 还有ButterKnife注解库.

Lambda表达式, 是写出优雅代码的关键, 参考.

Java

1

2

3

4

5

6

7

8

9

10

11

12

plugins {

    id "me.tatarka.retrolambda" version "3.2.4"

}

 

android {

...

 

    compileOptions {

        sourceCompatibility JavaVersion.VERSION_1_8

        targetCompatibility JavaVersion.VERSION_1_8

    }

}

Gradle 2.1+以上, 配置非常简单, 添加一个plugin和一个Java1.8兼容即可.

从主MainActivity跳转至SimpleActivity.

Java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

/**

* 主Activity, 用于跳转各个模块.

*

* @author wangchenlong

*/

public class MainActivity extends AppCompatActivity {

 

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

    }

 

    // 跳转简单的页面

    public void gotoSimpleModule(View view) {

        startActivity(new Intent(this, SimpleActivity.class));

    }

 

    // 跳转复杂的页面

    public void gotoMoreModule(View view) {

        startActivity(new Intent(this, MoreActivity.class));

    }

 

    // 跳转Lambda的页面

    public void gotoLambdaModule(View view) {

        startActivity(new Intent(this, LambdaActivity.class));

    }

 

    // 跳转网络的页面

    public void gotoNetworkModule(View view) {

        startActivity(new Intent(this, NetworkActivity.class));

    }

 

    // 跳转线程安全的页面

    public void gotoSafeModule(View view) {

        startActivity(new Intent(this, SafeActivity.class));

    }

}

SimpleActivity中, 创建一个观察者, 收到字符串的返回.

Java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

// 观察事件发生

    Observable.OnSubscribe mObservableAction = new Observable.OnSubscribe<String>() {

        @Override public void call(Subscriber<? super String> subscriber) {

            subscriber.onNext(sayMyName()); // 发送事件

            subscriber.onCompleted(); // 完成事件

        }

    };

 

...

 

    // 创建字符串

    private String sayMyName() {

        return "Hello, I am your friend, Spike!";

    }

创建两个订阅者, 使用字符串输出信息.

Java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

// 订阅者, 接收字符串, 修改控件

Subscriber<String> mTextSubscriber = new Subscriber<String>() {

    @Override public void onCompleted() {

 

    }

 

    @Override public void onError(Throwable e) {

 

    }

 

    @Override public void onNext(String s) {

        mTvText.setText(s); // 设置文字

    }

};

 

// 订阅者, 接收字符串, 提示信息

Subscriber<String> mToastSubscriber = new Subscriber<String>() {

    @Override public void onCompleted() {

 

    }

 

    @Override public void onError(Throwable e) {

 

    }

 

    @Override public void onNext(String s) {

        Toast.makeText(SimpleActivity.this, s, Toast.LENGTH_SHORT).show();

    }

};

在页面中, 观察者接收信息, 发送至主线程AndroidSchedulers.mainThread(), 再传递给订阅者, 由订阅者最终处理消息. 接收信息可以是同步, 也可以是异步.

Java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

@Override protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_simple);

    ButterKnife.bind(this);

 

    // 注册观察活动

    @SuppressWarnings("unchecked")

    Observable<String> observable = Observable.create(mObservableAction);

 

    // 分发订阅信息

    observable.observeOn(AndroidSchedulers.mainThread());

    observable.subscribe(mTextSubscriber);

    observable.subscribe(mToastSubscriber);

}

最基础的RxAndroid使用.
基础

更多

我们已经熟悉了初步的使用方式, 在接着学习一些其他方法, 如

just: 获取输入数据, 直接分发, 更加简洁, 省略其他回调.
from: 获取输入数组, 转变单个元素分发.
map: 映射, 对输入数据进行转换, 如大写.
flatMap: 增大, 本意就是增肥, 把输入数组映射多个值, 依次分发.
reduce: 简化, 正好相反, 把多个数组的值, 组合成一个数据.

来看看这个示例, 设置两个不同类型数组, 作为输入源, 根据不同情况分发数据.

Java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

/**

* 更多的RxAndroid的使用方法.

* <p>

* Created by wangchenlong on 15/12/30.

*/

public class MoreActivity extends Activity {

 

    @Bind(R.id.simple_tv_text) TextView mTvText;

 

    final String[] mManyWords = {"Hello", "I", "am", "your", "friend", "Spike"};

    final List<String> mManyWordList = Arrays.asList(mManyWords);

 

    // Action类似订阅者, 设置TextView

    private Action1<String> mTextViewAction = new Action1<String>() {

        @Override public void call(String s) {

            mTvText.setText(s);

        }

    };

 

    // Action设置Toast

    private Action1<String> mToastAction = new Action1<String>() {

        @Override public void call(String s) {

            Toast.makeText(MoreActivity.this, s, Toast.LENGTH_SHORT).show();

        }

    };

 

    // 设置映射函数

    private Func1<List<String>, Observable<String>> mOneLetterFunc = new Func1<List<String>, Observable<String>>() {

        @Override public Observable<String> call(List<String> strings) {

            return Observable.from(strings); // 映射字符串

        }

    };

 

    // 设置大写字母

    private Func1<String, String> mUpperLetterFunc = new Func1<String, String>() {

        @Override public String call(String s) {

            return s.toUpperCase(); // 大小字母

        }

    };

 

    // 连接字符串

    private Func2<String, String, String> mMergeStringFunc = new Func2<String, String, String>() {

        @Override public String call(String s, String s2) {

            return String.format("%s %s", s, s2); // 空格连接字符串

        }

    };

 

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_simple);

        ButterKnife.bind(this);

 

        // 添加字符串, 省略Action的其他方法, 只使用一个onNext.

        Observable<String> obShow = Observable.just(sayMyName());

 

        // 先映射, 再设置TextView

        obShow.observeOn(AndroidSchedulers.mainThread())

                .map(mUpperLetterFunc).subscribe(mTextViewAction);

 

        // 单独显示数组中的每个元素

        Observable<String> obMap = Observable.from(mManyWords);

 

        // 映射之后分发

        obMap.observeOn(AndroidSchedulers.mainThread())

                .map(mUpperLetterFunc).subscribe(mToastAction);

 

        // 优化过的代码, 直接获取数组, 再分发, 再合并, 再显示toast, Toast顺次执行.

        Observable.just(mManyWordList)

                .observeOn(AndroidSchedulers.mainThread())

                .flatMap(mOneLetterFunc)

                .reduce(mMergeStringFunc)

                .subscribe(mToastAction);

    }

 

    // 创建字符串

    private String sayMyName() {

        return "Hello, I am your friend, Spike!";

    }

}

这次简化调用代码, 因为有时候我们对异常并不是很关心,
只要能catch异常即可, 因此流仅仅关注真正需要的部分.

输入字符串, 变换大写, 输出至控件中显示.

Java

1

2

3

4

5

6

// 添加字符串, 省略Action的其他方法, 只使用一个onNext.

Observable<String> obShow = Observable.just(sayMyName());

 

// 先映射, 再设置TextView

obShow.observeOn(AndroidSchedulers.mainThread())

        .map(mUpperLetterFunc).subscribe(mTextViewAction);

just可以非常简单的获取任何数据, 分发时, 选择使用的线程.
map是对输入数据加工, 转换类型, 输入Func1, 准换大写字母.
Func1代表使用一个参数的函数, 前面是参数, 后面是返回值.
Action1代表最终动作, 因而不需要返回值, 并且一个参数.

输入数组, 单独分发数组中每一个元素, 转换大写, 输入Toast连续显示.

Java

1

2

3

4

5

6

// 单独显示数组中的每个元素

Observable<String> obMap = Observable.from(mManyWords);

 

// 映射之后分发

obMap.observeOn(AndroidSchedulers.mainThread())

        .map(mUpperLetterFunc).subscribe(mToastAction);

from是读取数组中的值, 每次单独分发, 并分发多次, 其余类似.

输入数组, 映射为单独分发, 并组合到一起, 集中显示.

Java

1

2

3

4

5

6

// 优化过的代码, 直接获取数组, 再分发, 再合并, 再显示toast, Toast顺次执行.

Observable.just(mManyWordList)

        .observeOn(AndroidSchedulers.mainThread())

        .flatMap(mOneLetterFunc)

        .reduce(mMergeStringFunc)

        .subscribe(mToastAction);

这次是使用just分发数组, 则分发数据就是数组, 并不是数组中的元素.
flatMap把数组转换为单独分发, Func1内部使用from拆分数组.
reduce把单独分发数据集中到一起, 再统一分发, 使用Func2.
最终使用Action1显示获得数据. 本次代码也更加简洁.

由此我们可以观察到, Rx的写法可以是多种多样, 合理的写法会更加优雅.

效果
效果

Lambda

Lambda表达式和Rx非常契合, 可以省略大量的内部类, 如Func和Action.
我们把上个示例, 用Lambda再写一次, 功能相同.

Java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

/**

* Lambda表达式写法

* <p>

* Created by wangchenlong on 15/12/31.

*/

public class LambdaActivity extends Activity {

 

    @Bind(R.id.simple_tv_text) TextView mTvText;

 

    final String[] mManyWords = {"Hello", "I", "am", "your", "friend", "Spike"};

    final List<String> mManyWordList = Arrays.asList(mManyWords);

 

    @Override protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_simple);

        ButterKnife.bind(this);

 

        // 添加字符串, 省略Action的其他方法, 只使用一个onNext.

        Observable<String> obShow = Observable.just(sayMyName());

 

        // 先映射, 再设置TextView

        obShow.observeOn(AndroidSchedulers.mainThread())

                .map(String::toUpperCase).subscribe(mTvText::setText);

 

        // 单独显示数组中的每个元素

        Observable<String> obMap = Observable.from(mManyWords);

 

        // 映射之后分发

        obMap.observeOn(AndroidSchedulers.mainThread())

                .map(String::toUpperCase)

                .subscribe(this::showToast);

 

        // 优化过的代码, 直接获取数组, 再分发, 再合并, 再显示toast, Toast顺次执行.

        Observable.just(mManyWordList)

                .observeOn(AndroidSchedulers.mainThread())

                .flatMap(Observable::from)

                .reduce(this::mergeString)

                .subscribe(this::showToast);

    }

 

    // 创建字符串

    private String sayMyName() {

        return "Hello, I am your friend, Spike!";

    }

 

    // 显示Toast

    private void showToast(String s) {

        Toast.makeText(LambdaActivity.this, s, Toast.LENGTH_SHORT).show();

    }

 

    // 合并字符串

    private String mergeString(String s1, String s2) {

        return String.format("%s %s", s1, s2);

    }

}

这次没有使用常规的Lambda表达式, 而是更简单的方法引用(Method References).
方法引用: 方法参数和返回值与Lambda表达式相同时, 使用方法名代替.

网络请求

Retrofit是网络请求库, 刚推出2.0版本. Rx的一个核心应用就是处理异步网络请求, 结合Retrofit, 会更加方便和简洁. 参考.

引入库

Java

1

2

3

4

5

6

7

compile 'com.android.support:recyclerview-v7:23.1.1' // RecyclerView

 

compile 'com.squareup.retrofit:retrofit:2.0.0-beta2' // Retrofit网络处理

compile 'com.squareup.retrofit:adapter-rxjava:2.0.0-beta2' // Retrofit的rx解析库

compile 'com.squareup.retrofit:converter-gson:2.0.0-beta2' // Retrofit的gson库

 

compile 'com.squareup.picasso:picasso:2.5.2' // Picasso网络图片加载

recyclerviewpicasso为了显示. retrofit系列是网络请求.

主页使用一个简单的列表视图, 展示Github的用户信息.

Java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

/**

* Rx的网络请求方式

* <p>

* Created by wangchenlong on 15/12/31.

*/

public class NetworkActivity extends Activity {

 

    @Bind(R.id.network_rv_list) RecyclerView mRvList; // 列表

 

    @Override protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_network);

        ButterKnife.bind(this);

 

        // 设置Layout管理器

        LinearLayoutManager layoutManager = new LinearLayoutManager(this);

        layoutManager.setOrientation(LinearLayoutManager.VERTICAL);

        mRvList.setLayoutManager(layoutManager);

 

        // 设置适配器

        UserListAdapter adapter = new UserListAdapter(this::gotoDetailPage);

        NetworkWrapper.getUsersInto(adapter);

        mRvList.setAdapter(adapter);

    }

 

    // 点击的回调

    public interface UserClickCallback {

        void onItemClicked(String name);

    }

 

    // 跳转到库详情页面

    private void gotoDetailPage(String name) {

        startActivity(NetworkDetailActivity.from(NetworkActivity.this, name));

    }

}

在列表中提供点击用户信息跳转至用户详情.
NetworkWrapper.getUsersInto(adapter) 请求网络, 设置适配器信息.

关键部分, 适配器, 其中包含ViewHolder类和数据类.

Java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

/**

* 显示列表

* <p>

* Created by wangchenlong on 15/12/31.

*/

public class UserListAdapter extends RecyclerView.Adapter<UserListAdapter.UserViewHolder> {

 

    private List<GitHubUser> mUsers; // 用户名集合

 

    private NetworkActivity.UserClickCallback mCallback; // 用户点击项的回调

 

    public UserListAdapter(NetworkActivity.UserClickCallback callback) {

        mUsers = new ArrayList<>();

        mCallback = callback;

    }

 

    public void addUser(GitHubUser user) {

        mUsers.add(user);

        notifyItemInserted(mUsers.size() - 1); // 最后一位

    }

 

    @Override public UserViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

        View item = LayoutInflater.from(parent.getContext())

                .inflate(R.layout.item_network_user, parent, false);

        return new UserViewHolder(item, mCallback);

    }

 

    @Override public void onBindViewHolder(UserViewHolder holder, int position) {

        holder.bindTo(mUsers.get(position));

    }

 

    @Override public int getItemCount() {

        return mUsers.size();

    }

 

    // Adapter的ViewHolder

    public static class UserViewHolder extends RecyclerView.ViewHolder {

 

        @Bind(R.id.network_item_iv_user_picture) ImageView mIvUserPicture;

        @Bind(R.id.network_item_tv_user_name) TextView mTvUserName;

        @Bind(R.id.network_item_tv_user_login) TextView mTvUserLogin;

        @Bind(R.id.network_item_tv_user_page) TextView mTvUserPage;

 

        public UserViewHolder(View itemView, NetworkActivity.UserClickCallback callback) {

            super(itemView);

            ButterKnife.bind(this, itemView);

            // 绑定点击事件

            itemView.setOnClickListener(v ->

                    callback.onItemClicked(mTvUserLogin.getText().toString()));

        }

 

        // 绑定数据

        public void bindTo(GitHubUser user) {

            mTvUserName.setText(user.name);

            mTvUserLogin.setText(user.login);

            mTvUserPage.setText(user.repos_url);

 

            Picasso.with(mIvUserPicture.getContext())

                    .load(user.avatar_url)

                    .placeholder(R.drawable.ic_person_black_24dp)

                    .into(mIvUserPicture);

        }

    }

 

    // 用户类, 名称必须与Json解析相同

    public static class GitHubUser {

        public String login;

        public String avatar_url;

        public String name;

        public String repos_url;

    }

}

添加数据addUser, 其中notifyItemInserted通知更新.
可以自动生成Json解析类的网站.

首先创建Retrofit`服务, 通过服务获取数据, 再依次分发给适配器.

Java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

/**

* 用户获取类

* <p>

* Created by wangchenlong on 15/12/31.

*/

public class NetworkWrapper {

    private static final String[] mFamousUsers =

            {"SpikeKing", "JakeWharton", "rock3r", "Takhion", "dextorer", "Mariuxtheone"};

 

    // 获取用户信息

    public static void getUsersInto(final UserListAdapter adapter) {

        GitHubService gitHubService =

                ServiceFactory.createServiceFrom(GitHubService.class, GitHubService.ENDPOINT);

 

        Observable.from(mFamousUsers)

                .flatMap(gitHubService::getUserData)

                .subscribeOn(Schedulers.newThread())

                .observeOn(AndroidSchedulers.mainThread())

                .subscribe(adapter::addUser);

    }

 

    // 获取库信息

    public static void getReposInfo(final String username, final RepoListAdapter adapter) {

        GitHubService gitHubService =

                ServiceFactory.createServiceFrom(GitHubService.class, GitHubService.ENDPOINT);

 

        gitHubService.getRepoData(username)

                .flatMap(Observable::from)

                .subscribeOn(Schedulers.newThread())

                .observeOn(AndroidSchedulers.mainThread())

                .subscribe(adapter::addRepo);

    }

}

网络请求无法在主线程上执行, 需要启动异步线程, 如Schedulers.newThread().
使用工厂模式ServiceFactory创建服务, 也可以单独创建服务.

创建Retrofit服务的工厂类.

Java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

/**

* 用户获取类

* <p>

* Created by wangchenlong on 15/12/31.

*/

public class NetworkWrapper {

    private static final String[] mFamousUsers =

            {"SpikeKing", "JakeWharton", "rock3r", "Takhion", "dextorer", "Mariuxtheone"};

 

    // 获取用户信息

    public static void getUsersInto(final UserListAdapter adapter) {

        GitHubService gitHubService =

                ServiceFactory.createServiceFrom(GitHubService.class, GitHubService.ENDPOINT);

 

        Observable.from(mFamousUsers)

                .flatMap(gitHubService::getUserData)

                .subscribeOn(Schedulers.newThread())

                .observeOn(AndroidSchedulers.mainThread())

                .subscribe(adapter::addUser);

    }

 

    // 获取库信息

    public static void getReposInfo(final String username, final RepoListAdapter adapter) {

        GitHubService gitHubService =

                ServiceFactory.createServiceFrom(GitHubService.class, GitHubService.ENDPOINT);

 

        gitHubService.getRepoData(username)

                .flatMap(Observable::from)

                .subscribeOn(Schedulers.newThread())

                .observeOn(AndroidSchedulers.mainThread())

                .subscribe(adapter::addRepo);

    }

}

这是Retrofit 2.0的写法, 注意需要添加Rx和Gson的解析.

设置网络请求的Url.

Java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

/**

* GitHub的服务

* <p>

* Created by wangchenlong on 15/12/31.

*/

public interface GitHubService {

    String ENDPOINT = "https://api.github.com";

 

    // 获取个人信息

    @GET("/users/{user}")

    Observable<UserListAdapter.GitHubUser> getUserData(@Path("user") String user);

 

    // 获取库, 获取的是数组

    @GET("/users/{user}/repos")

    Observable<RepoListAdapter.GitHubRepo[]> getRepoData(@Path("user") String user);

}

显示用户
显示

详情页面与主页类似, 参考代码, 不做细说.

线程安全

Rx的好处之一就是可以防止内存泄露, 即根据页面生命周期, 处理异步线程的结束. 可以使用RxLifecycle库处理生命周期.

Activity类继承RxAppCompatActivity, 替换AppCompatActivity.

启动一个循环线程.

Java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

/**

* Rx的线程安全

* <p>

* Created by wangchenlong on 15/12/31.

*/

public class SafeActivity extends RxAppCompatActivity {

    private static final String TAG = "DEBUG-WCL: " + SafeActivity.class.getSimpleName();

 

    @Bind(R.id.simple_tv_text) TextView mTvText;

 

    @Override protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_simple);

        ButterKnife.bind(this);

 

        Observable.interval(1, TimeUnit.SECONDS)

                .observeOn(AndroidSchedulers.mainThread())

                .compose(bindToLifecycle()) // 管理生命周期, 防止内存泄露

                .subscribe(this::showTime);

    }

 

    private void showTime(Long time) {

        mTvText.setText(String.valueOf("时间计数: " + time));

        Log.d(TAG, "时间计数器: " + time);

    }

 

    @Override

    protected void onPause() {

        super.onPause();

        Log.w(TAG, "页面关闭!");

    }

}

继承RxAppCompatActivity, 添加bindToLifecycle方法管理生命周期. 当页面onPause时, 会自动结束循环线程. 如果注释这句代码, 则会导致内存泄露.

RxBinding

RxBinding是Rx中处理控件异步调用的方式, 也是由Square公司开发, Jake负责编写. 通过绑定组件, 异步获取事件, 并进行处理. 编码风格非常优雅.

除了RxJava, 再添加RxBinding的依赖.

Java

1

2

3

4

// RxBinding

compile 'com.jakewharton.rxbinding:rxbinding:0.3.0'

compile 'com.jakewharton.rxbinding:rxbinding-appcompat-v7:0.3.0'

compile 'com.jakewharton.rxbinding:rxbinding-design:0.3.0'

Toolbar和Fab, 两个较新的控件.

Java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

<?xml version="1.0" encoding="utf-8"?>

<android.support.design.widget.CoordinatorLayout

    xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:tools="http://schemas.android.com/tools"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:fitsSystemWindows="true"

    android:orientation="vertical"

    tools:context=".BindingActivity">

 

    <android.support.design.widget.AppBarLayout

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:theme="@style/AppTheme.AppBarOverlay">

 

        <android.support.v7.widget.Toolbar

            android:id="@+id/rxbinding_t_toolbar"

            android:layout_width="match_parent"

            android:layout_height="?attr/actionBarSize"

            android:background="?attr/colorPrimary"

            android:popupTheme="@style/AppTheme.PopupOverlay"

            tools:targetApi="21"/>

 

    </android.support.design.widget.AppBarLayout>

 

    <include layout="@layout/content_rxbinding"/>

 

    <android.support.design.widget.FloatingActionButton

        android:id="@+id/rxbinding_fab_fab"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_gravity="bottom|end"

        android:layout_margin="@dimen/fab_margin"

        android:src="@android:drawable/ic_dialog_email"/>

 

</android.support.design.widget.CoordinatorLayout>

两个EditText控件, 对比传统方法和RxBinding方法.

Java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

              xmlns:app="http://schemas.android.com/apk/res-auto"

              xmlns:tools="http://schemas.android.com/tools"

              android:layout_width="match_parent"

              android:layout_height="match_parent"

              android:orientation="vertical"

              android:padding="@dimen/activity_margin"

              app:layout_behavior="@string/appbar_scrolling_view_behavior"

              tools:context=".BindingActivity"

              tools:showIn="@layout/activity_binding">

 

    <TextView

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:text="@string/usual_approach"/>

 

    <EditText

        android:id="@+id/rxbinding_et_usual_approach"

        android:layout_width="match_parent"

        android:layout_height="48dp"

        android:hint="@null"/>

 

    <TextView

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:text="@string/reactive_approach"/>

 

    <EditText

        android:id="@+id/rxbinding_et_reactive_approach"

        android:layout_width="match_parent"

        android:layout_height="48dp"

        android:hint="@null"/>

 

    <TextView

        android:id="@+id/rxbinding_tv_show"

        android:layout_width="match_parent"

        android:layout_height="wrap_content"/>

 

</LinearLayout>

使用ButterKnife注入控件, 使用RxBinding方式绑定控件, 异步监听事件.

Java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

/**

* Rx绑定

* <p>

* Created by wangchenlong on 16/1/25.

*/

public class BindingActivity extends AppCompatActivity {

 

    @Bind(R.id.rxbinding_t_toolbar) Toolbar mTToolbar;

    @Bind(R.id.rxbinding_et_usual_approach) EditText mEtUsualApproach;

    @Bind(R.id.rxbinding_et_reactive_approach) EditText mEtReactiveApproach;

    @Bind(R.id.rxbinding_tv_show) TextView mTvShow;

    @Bind(R.id.rxbinding_fab_fab) FloatingActionButton mFabFab;

 

    @Override protected void onCreate(@Nullable Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_binding);

        ButterKnife.bind(this);

 

        initToolbar(); // 初始化Toolbar

        initFabButton(); // 初始化Fab按钮

        initEditText(); // 初始化编辑文本

    }

 

    // 初始化Toolbar

    private void initToolbar() {

        // 添加菜单按钮

        setSupportActionBar(mTToolbar);

        ActionBar actionBar = getSupportActionBar();

        // 添加浏览按钮

        if (actionBar != null) {

            actionBar.setDisplayHomeAsUpEnabled(true);

        }

 

        RxToolbar.itemClicks(mTToolbar).subscribe(this::onToolbarItemClicked);

 

        RxToolbar.navigationClicks(mTToolbar).subscribe(this::onToolbarNavigationClicked);

    }

 

    // 点击Toolbar的项

    private void onToolbarItemClicked(MenuItem menuItem) {

        String m = "点击\"" + menuItem.getTitle() + "\"";

        Toast.makeText(this, m, Toast.LENGTH_SHORT).show();

    }

 

    // 浏览点击

    private void onToolbarNavigationClicked(Void v) {

        Toast.makeText(this, "浏览点击", Toast.LENGTH_SHORT).show();

    }

 

    @Override public boolean onCreateOptionsMenu(Menu menu) {

        getMenuInflater().inflate(R.menu.menu_rxbinding, menu);

        return super.onCreateOptionsMenu(menu);

    }

 

    // 初始化Fab按钮

    private void initFabButton() {

        RxView.clicks(mFabFab).subscribe(this::onFabClicked);

    }

 

    // 点击Fab按钮

    private void onFabClicked(Void v) {

        Snackbar snackbar = Snackbar.make(findViewById(android.R.id.content), "点击Snackbar", Snackbar.LENGTH_SHORT);

        snackbar.show();

        RxSnackbar.dismisses(snackbar).subscribe(this::onSnackbarDismissed);

    }

 

    // 销毁Snackbar, event参考{Snackbar}

    private void onSnackbarDismissed(int event) {

        String text = "Snackbar消失代码:" + event;

        Toast.makeText(this, text, Toast.LENGTH_SHORT).show();

    }

 

    // 初始化编辑文本

    private void initEditText() {

        // 正常方式

        mEtUsualApproach.addTextChangedListener(new TextWatcher() {

            @Override

            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

 

            }

 

            @Override public void onTextChanged(CharSequence s, int start, int before, int count) {

                mTvShow.setText(s);

            }

 

            @Override public void afterTextChanged(Editable s) {

 

            }

 

        });

 

        // Rx方式

        RxTextView.textChanges(mEtReactiveApproach).subscribe(mTvShow::setText);

    }

}

Toolbar使用RxToolbar监听点击事件; Snackbar使用RxSnackbar监听;
EditText使用RxTextView监听; 其余使用RxView监听.

动画

OK, That’s all. Enjoy it!


本文转载自:http://cxy.liuzhihengseo.com/517.html

共有 人打赏支持
粉丝 16
博文 142
码字总数 13945
作品 0
天津
私信 提问
RxJava与RxAndroid的学习之路

RxJava 和 RxAndroid 四(RxBinding的使用) 对Rxjava不熟悉的同学可以先看我之前写的几篇文章 RxJava 和 RxAndroid 一 (基础) RxJava 和 RxAndroid 二(操作符的使用) RxJava 和 RxAndroi...

guozhendan
2018/06/26
0
0
RxAndroid之初体验——Create、From、interval、just、range操作符的基本使用

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/m366917/article/details/52801459 RxAndroid之初体验——Create、From、interval、just、range操作符的基本使...

Aduroidpc
2016/10/12
0
0
RxAndroid的简单应用——实现网络图片的下载

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/m366917/article/details/52802933 RxAndroid的简单应用——实现网络图片的下载 版权声明:转载必须注明本文转...

Aduroidpc
2016/10/13
0
0
使用聚合数据的接口进行的RxAndroid学习

Demo数据源是聚合数据的免费Api,地址:https://www.juhe.cn/ 配合Retrofit 完成数据请求 例子比较简单,没事使用什么复杂的操作符。 就是简单的网络数据获取。 一些常用的操作符大家可以参考...

白jian
2016/10/09
144
0
日新月异的Android新技术

学习Android技术开发已经很久啦,感觉Android技术开发太快,几乎每年都有很多新东西出现,想要覆盖所有新东西感觉也不太可能,我这里主要说一下主要的 Android 的主要新技术发展,其实了解 ...

crossmix
2015/11/09
0
0

没有更多内容

加载失败,请刷新页面

加载更多

关于C++ 容器的swap操作

一、swap操作交换两个相同类型的容器的内容,一般的容器(除array外),交换两个容器内容的操作会保证非常快,因为并没有交换元素本身,而只是交换了两个容器的内部数据结构。 拿vector做个例...

shzwork
30分钟前
1
0
程序员从宏观、微观角度浅析JVM虚拟机!

1.问题 1、JAVA文本文件如何被翻译成CLASS二进制文件? 2、如何理解CLASS文件的组成结构? 3、虚拟机如何加载使用类文件的生命周期? 4、虚拟机系列诊断工具如何使用? 5、虚拟机内存淘汰机制?...

我最喜欢三大框架
31分钟前
2
0
Choerodon猪齿鱼实践之应用生命周期管理

Choerodon平台中的开发和部署都是围绕应用来进行的,那Choerodon平台中的应用有什么样的特性?又是怎样来进行管理的呢?本文旨在深入地介绍Choerodon平台中应用的功能特性及其生命周期的管理...

Choerodon
51分钟前
0
0
Websocket之Jmeter压力测试

最近使用到Websocket进行聊天功能开发,用Jmeter进行压力测试,记录下。 使用的Jmeter版本5.1.1,自行从apache jmeter官网下载。 首先要添加Websocket的插件,网上有很多,我从百度网盘下载的...

克虏伯
52分钟前
2
0
作为Java程序员这些技术都不会,拿什么去涨薪跳槽?

引言 当下,正面临着近几年来的最严重的互联网寒冬,听得最多的一句话便是:相见于江湖~,缩减HC、裁员不绝于耳,大家都是人心惶惶,年前如此,年后想必肯定又是一场更为惨烈的江湖厮杀。但博...

别打我会飞
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部