RxAndroid使用方法介绍
RxAndroid使用方法介绍
熟悉RxAndroid的使用方法.
要点包含:
(1) 链式表达式的使用方式.
(2) Lambda的应用.
(3) Rx处理网络请求.
(4) 线程自动管理, 防止内存泄露.
GitHub下载地址.
1. 基础
当然, 从一个崭新的HelloWorld项目开始.
添加Gradle配置.
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表达式, 是写出优雅代码的关键, 参考.
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
.
/**
* 主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
中, 创建一个观察者, 收到字符串的返回.
// 观察事件发生
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!";
}
创建两个订阅者, 使用字符串输出信息.
// 订阅者, 接收字符串, 修改控件
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()
, 再传递给订阅者, 由订阅者最终处理消息. 接收信息可以是同步, 也可以是异步.
@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使用.
2. 更多
我们已经熟悉了初步的使用方式, 在接着学习一些其他方法, 如
just
: 获取输入数据, 直接分发, 更加简洁, 省略其他回调.
from
: 获取输入数组, 转变单个元素分发.
map
: 映射, 对输入数据进行转换, 如大写.
flatMap
: 增大, 本意就是增肥, 把输入数组映射多个值, 依次分发.
reduce
: 简化, 正好相反, 把多个数组的值, 组合成一个数据.
来看看这个示例, 设置两个不同类型数组, 作为输入源, 根据不同情况分发数据.
/**
* 更多的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
, Observable
, Observable
这次简化调用代码, 因为有时候我们对异常并不是很关心,
只要能catch
异常即可, 因此流仅仅关注真正需要的部分.
输入字符串, 变换大写, 输出至控件中显示.
// 添加字符串, 省略Action的其他方法, 只使用一个onNext.
Observable obShow = Observable.just(sayMyName());
// 先映射, 再设置TextView
obShow.observeOn(AndroidSchedulers.mainThread())
.map(mUpperLetterFunc).subscribe(mTextViewAction);
just
可以非常简单的获取任何数据, 分发时, 选择使用的线程.
map
是对输入数据加工, 转换类型, 输入Func1
, 准换大写字母.
Func1
代表使用一个参数的函数, 前面是参数, 后面是返回值.
Action1
代表最终动作, 因而不需要返回值, 并且一个参数.
输入数组, 单独分发数组中每一个元素, 转换大写, 输入Toast连续显示.
// 单独显示数组中的每个元素
Observable obMap = Observable.from(mManyWords);
// 映射之后分发
obMap.observeOn(AndroidSchedulers.mainThread())
.map(mUpperLetterFunc).subscribe(mToastAction);
from
是读取数组中的值, 每次单独分发, 并分发多次, 其余类似.
输入数组, 映射为单独分发, 并组合到一起, 集中显示.
// 优化过的代码, 直接获取数组, 再分发, 再合并, 再显示toast, Toast顺次执行.
Observable.just(mManyWordList)
.observeOn(AndroidSchedulers.mainThread())
.flatMap(mOneLetterFunc)
.reduce(mMergeStringFunc)
.subscribe(mToastAction);
这次是使用
just
分发数组, 则分发数据就是数组, 并不是数组中的元素.
flatMap
把数组转换为单独分发,Func1
内部使用from
拆分数组.
reduce
把单独分发数据集中到一起, 再统一分发, 使用Func2
.
最终使用Action1
显示获得数据. 本次代码也更加简洁.
由此我们可以观察到, Rx的写法可以是多种多样, 合理的写法会更加优雅.
效果
3. Lambda
Lambda表达式和Rx非常契合, 可以省略大量的内部类, 如Func和Action.
我们把上个示例, 用Lambda再写一次, 功能相同.
/**
* Lambda表达式写法
*
* 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
这次没有使用常规的Lambda表达式, 而是更简单的
方法引用(Method References)
.
方法引用: 方法参数和返回值与Lambda表达式相同时, 使用方法名代替.
4. 网络请求
Retrofit是网络请求库, 刚推出2.0版本. Rx的一个核心应用就是处理异步网络请求, 结合Retrofit, 会更加方便和简洁. 参考.
引入库
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的用户信息.
/**
* 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类和数据类.
/**
* 显示列表
*
* Created by wangchenlong on 15/12/31. */ public class UserListAdapter extends RecyclerView.Adapter
添加数据
addUser
, 其中notifyItemInserted
通知更新.
可以自动生成Json解析类的网站.
首先创建`Retrofit“服务, 通过服务获取数据, 再依次分发给适配器.
/**
* 用户获取类
*
* 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
服务的工厂类.
/**
* 工厂模式
*
* Created by wangchenlong on 15/12/31. */ public class ServiceFactory { public static
这是Retrofit 2.0的写法, 注意需要添加Rx和Gson的解析.
设置网络请求的Url.
/**
* GitHub的服务
*
* Created by wangchenlong on 15/12/31. */ public interface GitHubService { String ENDPOINT = "https://api.github.com"; // 获取个人信息 @GET("/users/{user}") Observable
显示用户
详情页面与主页类似, 参考代码, 不做细说.
5. 线程安全
Rx的好处之一就是可以防止内存泄露, 即根据页面生命周期, 处理异步线程的结束. 可以使用RxLifecycle库处理生命周期.
Activity
类继承RxAppCompatActivity
, 替换AppCompatActivity
.
启动一个循环线程.
/**
* 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
时, 会自动结束循环线程. 如果注释这句代码, 则会导致内存泄露.
OK, That’s all! Enjoy It!
用户评论