柚子快报邀请码778899分享:<html>

http://www.51969.com/

原文链接

在第1,2,3篇中,我大概介绍了RxJava是怎么使用的。以下我会介绍怎样在Android中使用RxJava.

RxAndroid

RxAndroid是RxJava的一个针对Android平台的扩展。它包括了一些可以简化Android开发的工具。

首先。AndroidSchedulers提供了针对Android的线程系统的调度器。须要在UI线程中执行某些代码?非常easy,仅仅须要使用AndroidSchedulers.mainThread():

retrofitService.getImage(url)

.subscribeOn(Schedulers.io())

.observeOn(AndroidSchedulers.mainThread())

.subscribe(bitmap -> myImageView.setImageBitmap(bitmap));

假设你已经创建了自己的Handler,你能够使用HandlerThreadScheduler1将一个调度器链接到你的handler上。

接着要介绍的就是AndroidObservable,它提供了跟多的功能来配合Android的生命周期。bindActivity()和bindFragment()方法默认使用AndroidSchedulers.mainThread()来运行观察者代码,这两个方法会在Activity或者Fragment结束的时候通知被观察者停止发出新的消息。

AndroidObservable.bindActivity(this, retrofitService.getImage(url))

.subscribeOn(Schedulers.io())

.subscribe(bitmap -> myImageView.setImageBitmap(bitmap);我自己也非常喜欢AndroidObservable.fromBroadcast()方法。它同意你创建一个类似BroadcastReceiver的Observable对象。以下的样例展示了怎样在网络变化的时候被通知到:IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);

AndroidObservable.fromBroadcast(context, filter)

.subscribe(intent -> handleConnectivityChange(intent));

最后要介绍的是ViewObservable,使用它能够给View加入了一些绑定。假设你想在每次点击view的时候都收到一个事件,能够使用ViewObservable.clicks(),或者你想监听TextView的内容变化。能够使用ViewObservable.text()。ViewObservable.clicks(mCardNameEditText, false)

.subscribe(view -> handleClick(view));

Retrofit

大名鼎鼎的Retrofit库内置了对RxJava的支持。通常调用发能够通过使用一个Callback对象来获取异步的结果:

@GET("/user/{id}/photo")

void getUserPhoto(@Path("id") int id, Callback cb);

使用RxJava,你能够直接返回一个Observable对象。@GET("/user/{id}/photo")

Observable getUserPhoto(@Path("id") int id);

如今你能够任意使用Observable对象了。你不仅能够获取数据,还能够进行变换。 

Retrofit对Observable的支持使得它能够非常easy的将多个REST请求结合起来。比方我们有一个请求是获取照片的,另一个请求是获取元数据的。我们就能够将这两个请求并发的发出,而且等待两个结果都返回之后再做处理:

Observable.zip(

service.getUserPhoto(id),

service.getPhotoMetadata(id),

(photo, metadata) -> createPhotoWithData(photo, metadata))

.subscribe(photoWithData -> showPhoto(photoWithData));

在第二篇里我展示过一个类似的样例(使用flatMap())。这里我仅仅是想展示下面使用RxJava+Retrofit能够多么简单地组合多个REST请求。

遗留代码。执行极慢的代码

Retrofit能够返回Observable对象,可是假设你使用的别的库并不支持这样怎么办?或者说一个内部的内码,你想把他们转换成Observable的?有什么简单的办法没?

绝大多数时候Observable.just() 和 Observable.from() 可以帮助你从遗留代码中创建 Observable 对象:

private Object oldMethod() { ... }

public Observable newMethod() {

return Observable.just(oldMethod());

}

上面的样例中假设oldMethod()足够快是没有什么问题的,可是假设非常慢呢?调用oldMethod()将会堵塞住他所在的线程。 

为了解决问题,能够參考我一直使用的方法–使用defer()来包装缓慢的代码:

private Object slowBlockingMethod() { ... }

public Observable newMethod() {

return Observable.defer(() -> Observable.just(slowBlockingMethod()));

}

如今,newMethod()的调用不会堵塞了。除非你订阅返回的observable对象。

生命周期

我把最难的不分留在了最后。怎样处理Activity的生命周期?主要就是两个问题: 

1.在configuration改变(比方转屏)之后继续之前的Subscription。

比方你使用Retrofit发出了一个REST请求,接着想在listview中展示结果。假设在网络请求的时候用户旋转了屏幕怎么办?你当然想继续刚才的请求。可是怎么搞?

2.Observable持有Context导致的内存泄露

这个问题是由于创建subscription的时候,以某种方式持有了context的引用。尤其是当你和view交互的时候,这太easy发生!假设Observable没有及时结束,内存占用就会越来越大。 

不幸的是,没有银弹来解决这两个问题。可是这里有一些指导方案你能够參考。

第一个问题的解决方式就是使用RxJava内置的缓存机制,这样你就能够对同一个Observable对象运行unsubscribe/resubscribe,却不用反复运行得到Observable的代码。cache() (或者 replay())会继续运行网络请求(甚至你调用了unsubscribe也不会停止)。这就是说你能够在Activity又一次创建的时候从cache()的返回值中创建一个新的Observable对象。

Observable request = service.getUserPhoto(id).cache();

Subscription sub = request.subscribe(photo -> handleUserPhoto(photo));

// ...When the Activity is being recreated...

sub.unsubscribe();

// ...Once the Activity is recreated...

request.subscribe(photo -> handleUserPhoto(photo));

注意。两次sub是使用的同一个缓存的请求。当然在哪里去存储请求的结果还是要你自己来做,和全部其它的生命周期相关的解决方式一延虎,必须在生命周期外的某个地方存储。(retained fragment或者单例等等)。

第二个问题的解决方式就是在生命周期的某个时刻取消订阅。一个非经常见的模式就是使用CompositeSubscription来持有全部的Subscriptions,然后在onDestroy()或者onDestroyView()里取消全部的订阅。

private CompositeSubscription mCompositeSubscription

= new CompositeSubscription();

private void doSomething() {

mCompositeSubscription.add(

AndroidObservable.bindActivity(this, Observable.just("Hello, World!"))

.subscribe(s -> System.out.println(s)));

}

@Override

protected void onDestroy() {

super.onDestroy();

mCompositeSubscription.unsubscribe();

}

你能够在Activity/Fragment的基类里创建一个CompositeSubscription对象,在子类中使用它。

注意! 一旦你调用了 CompositeSubscription.unsubscribe()。这个CompositeSubscription对象就不可用了, 假设你还想使用CompositeSubscription,就必须在创建一个新的对象了。

两个问题的解决方式都须要加入额外的代码。假设谁有更好的方案,欢迎告诉我。

总结

RxJava还是一个非常新的项目,RxAndroid更是。RxAndroid眼下还在活跃开发中。也没有多少好的样例。我打赌一年之后我的一些建议就会被看做过时了。

深入浅出RxJava四-在Android中使用响应式编程

RxAndroid是RxJava的扩展,

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

很多其它: http://www.wangchenlong.org/

本文代码的GitHub下载地址.

要点包括:

(1) 链式表达式的使用方式.

(2) Lambda的应用.

(3) Rx处理网络请求.

(4) 线程自己主动管理, 防止内存泄露.

(5) RxBinding绑定控件的异步事件.

基础

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

加入Gradle配置.

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表达式, 是写出优雅代码的关键, 參考.

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+以上, 配置很easy, 加入一个plugin和一个Java1.8兼容就可以.

从主MainActivity跳转至SimpleActivity.

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中, 创建一个观察者, 收到字符串的返回.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

// 观察事件发生

Observable.OnSubscribe mObservableAction = new Observable.OnSubscribe() {

@Override public void call(Subscriber subscriber) {

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

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

}

};

...

// 创建字符串

private String sayMyName() {

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

}

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

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 mTextSubscriber = new Subscriber() {

@Override public void onCompleted() {

}

@Override public void onError(Throwable e) {

}

@Override public void onNext(String s) {

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

}

};

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

Subscriber mToastSubscriber = new Subscriber() {

@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(), 再传递给订阅者, 由订阅者终于处理消息. 接收信息能够是同步,

也能够是异步.

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 observable = Observable.create(mObservableAction);

// 分发订阅信息

observable.observeOn(AndroidSchedulers.mainThread());

observable.subscribe(mTextSubscriber);

observable.subscribe(mToastSubscriber);

}

最基础的RxAndroid使用.

很多其它

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

just: 获取输入数据, 直接分发, 更加简洁, 省略其它回调.

from: 获取输入数组, 转变单个元素分发.

map: 映射, 对输入数据进行转换, 如大写.

flatMap: 增大, 本意就是增肥, 把输入数组映射多个值, 依次分发.

reduce: 简化, 正好相反, 把多个数组的值, 组合成一个数据.

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

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的用法.

*

* 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 mManyWordList = Arrays.asList(mManyWords);

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

private Action1 mTextViewAction = new Action1() {

@Override public void call(String s) {

mTvText.setText(s);

}

};

// Action设置Toast

private Action1 mToastAction = new Action1() {

@Override public void call(String s) {

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

}

};

// 设置映射函数

private Func1, Observable> mOneLetterFunc = new Func1, Observable>() {

@Override public Observable call(List strings) {

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

}

};

// 设置大写字母

private Func1 mUpperLetterFunc = new Func1() {

@Override public String call(String s) {

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

}

};

// 连接字符串

private Func2 mMergeStringFunc = new Func2() {

@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 obShow = Observable.just(sayMyName());

// 先映射, 再设置TextView

obShow.observeOn(AndroidSchedulers.mainThread())

.map(mUpperLetterFunc).subscribe(mTextViewAction);

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

Observable 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异常就可以, 因此流只关注真正须要的部分.

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

1

2

3

4

5

6

// 加入字符串, 省略Action的其它方法, 仅仅使用一个onNext.

Observable obShow = Observable.just(sayMyName());

// 先映射, 再设置TextView

obShow.observeOn(AndroidSchedulers.mainThread())

.map(mUpperLetterFunc).subscribe(mTextViewAction);

just能够很easy的获取不论什么数据, 分发时, 选择使用的线程.

map是对输入数据加工, 转换类型, 输入Func1,

准换大写字母.

Func1代表使用一个參数的函数, 前面是參数, 后面是返回值.

Action1代表终于动作, 因而不须要返回值, 而且一个參数.

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

1

2

3

4

5

6

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

Observable obMap = Observable.from(mManyWords);

// 映射之后分发

obMap.observeOn(AndroidSchedulers.mainThread())

.map(mUpperLetterFunc).subscribe(mToastAction);

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

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

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的写法能够是多种多样, 合理的写法会更加优雅.

效果

网络请求

Retrofit是网络请求库,

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

引入库

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网络图片载入

recyclerview和picasso为了显示. retrofit系列是网络请求.

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

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的网络请求方式

*

* 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类和数据类.

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

/**

* 显示列表

*

* Created by wangchenlong on 15/12/31.

*/

public class UserListAdapter extends RecyclerView.Adapter {

private List mUsers; // username集合

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``服务, 通过服务获取数据, 再依次分发给适配器.

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

/**

* 用户获取类

*

* 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服务的工厂类.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

/**

* 工厂模式

*

* Created by wangchenlong on 15/12/31.

*/

public class ServiceFactory {

public static T createServiceFrom(final Class serviceClass, String endpoint) {

Retrofit adapter = new Retrofit.Builder()

.baseUrl(endpoint)

.addCallAdapterFactory(RxJavaCallAdapterFactory.create()) // 加入Rx适配器

.addConverterFactory(GsonConverterFactory.create()) // 加入Gson转换器

.build();

return adapter.create(serviceClass);

}

}

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

设置网络请求的Url.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

/**

* GitHub的服务

*

* Created by wangchenlong on 15/12/31.

*/

public interface GitHubService {

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

// 获取个人信息

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

Observable getUserData(@Path("user") String user);

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

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

Observable getRepoData(@Path("user") String user);

}

显示用户

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

线程安全

Rx的优点之中的一个就是能够防止内存泄露, 即依据页面生命周期, 处理异步线程的结束. 能够使用RxLifecycle库处理生命周期.

Activity类继承RxAppCompatActivity,

替换AppCompatActivity.

启动一个循环线程.

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的线程安全

*

* 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的依赖.

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, 两个较新的控件.

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

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:layout_width="match_parent"

android:layout_height="wrap_content"

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

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: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"/>

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

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

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">

android:layout_width="match_parent"

android:layout_height="wrap_content"

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

android:id="@+id/rxbinding_et_usual_approach"

android:layout_width="match_parent"

android:layout_height="48dp"

android:hint="@null"/>

android:layout_width="match_parent"

android:layout_height="wrap_content"

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

android:id="@+id/rxbinding_et_reactive_approach"

android:layout_width="match_parent"

android:layout_height="48dp"

android:hint="@null"/>

android:id="@+id/rxbinding_tv_show"

android:layout_width="match_parent"

android:layout_height="wrap_content"/>

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

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绑定

*

* 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(); // 初始化Fabbutton

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

}

// 初始化Toolbar

private void initToolbar() {

// 加入菜单button

setSupportActionBar(mTToolbar);

ActionBar actionBar = getSupportActionBar();

// 加入浏览button

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);

}

// 初始化Fabbutton

private void initFabButton() {

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

}

// 点击Fabbutton

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://www.wangchenlong.org/2016/03/20/1603/207-rxjava-first/

欢迎Follow我的GitHub,

关注我的简书, 微博, CSDN, 掘金, Slides.

我已托付“维权骑士”为我的文章进行维权行动. 未经授权, 禁止转载, 授权或合作请留言.

阅读全文

举报

标签:

本文已收录于下面专栏:

0条评论

发表评论

HTML/XML

objective-c

Delphi

Ruby

PHP

C#

C++

JavaScript

Visual Basic

Python

Java

CSS

SQL

其他

相关文章推荐

Android开发相关——Retrofit+RxJava+OkHttp(下)使用

上一篇闲扯过后。算是将我为什么会把Retrofit说出来了吧(尽管好像什么都没说),当然还有其它框架,作为一个懒人,我这里就不加以阐述了,还是进入总体,開始进入我们的使用的部分。

还是先上我的Git...

u010513377

2017-07-21 17:45

147

深入浅出RxJava (一:基础篇)

RxJava正在Android开发人员中变的越来越流行。唯一的问题就是上手不easy,尤其是大部分人之前都是使用命令式编程语言。可是一旦你弄明确了,你就会发现RxJava真是太棒了。

这里不过帮助你了解RxJava,整个系列共同拥有四篇文章。希望你看完这四篇文章之后可以了解RxJava背后的思想。而且喜欢上RxJava。

[b]基础[/b]

RxJava最核心的两个东西是Observables(被观察者,事件源)和Subscribers(观察者)。Observables发出一系列事件,Subscribers处理这些事件。这里的事件能够是不论什么你感兴趣的东西(触摸事件,web接口调用返回的数

iaiai

2015-12-17 13:52

287

Android 教你一步步搭建MVP+Retrofit+RxJava网络请求框架

之前公司的项目用到了MVP+Retrofit+RxJava的框架进行网络请求。所以今天特此写一篇文章以做总结。相信非常多人都听说过MVP、Retrofit、以及RxJava,有的人已经開始用了,有的人可...

yangyuscript

2017-08-08 10:04

58

深入浅出RxJava (三:响应式的优点)

[url=http://blog.danlew.net/2014/09/30/grokking-rxjava-part-3/]原文链接[/url]

在第一篇中,我介绍了RxJava的基础知识。第二篇中。我向你展示了操作符的强大。可是你可能仍然没被说服。这篇里面,我讲向你展示RxJava的其它的一些优点,相信这篇足够让你去使用Rxjava.

[b]错误处理[/b]

到眼下为止。我们都没怎么介绍onComplete()和onError()函数。这两个函数用来通知订阅者。被观察的对象将停止发送数据以及为什么停止(成功的完毕或者出错了)。

以下的代码展示了怎么使用这两个函数:

iaiai

2015-12-17 14:03

332

给 Android 开发人员的 RxJava 具体解释

前言

我从去年開始使用 RxJava ,到如今一年多了。今年增加了 Flipboard 后,看到 Flipboard 的 Android 项目也在使用 RxJava ,而且使用的场景越来越多 。...

weixin_36924912

3天前 09:34

12

rabbit_in_android的博客

+关注

原创

39

粉丝

32

喜欢

0

Android App总体架构设计的思考

Android性能优化典范

知乎安卓client关注和取消关注的这个button点击特效是怎么实现的?

ART、JIT、AOT、Dalvik之间有什么关系?

很多其它文章

在线课程

【直播】计算机视觉原理及实战—屈教授

【套餐】Spark+Scala课程包--陈超

文件夹

喜欢

取消喜欢

收藏

分享

微博

微信

QQ

收藏助手

不良信息举报

您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导

举报原因:

色情

政治

抄袭

广告

招聘

骂人

其它

原文地址:

原因补充:

(最多仅仅同意输入30个字)

柚子快报邀请码778899分享:<html>

http://www.51969.com/

查看原文

发表评论

返回顶部暗黑模式