一.场景
在普通操作的代码中,如果我们想要实现登录功能,那么势必要请求后台服务,获取登录的结果,然后根据结果做不同的更新UI
的操作。由于主线程不能执行耗时操作,所以网络请求正常情况下都要放在子线程执行,然后需要借助Handler
将在子线程获得的结果返回到主线程中,并更新UI
。RxJava
之所以强大,我们在使用他进行线程切换时,不需要自己去创建Handler
,只需要一句代码就能完成线程切换,这是为什么要进行线程切换的原因。
我们先通过一个例子学习在RxJava中如何切换线程。
Observable observable = Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> e) throws Exception {
e.onNext(1);
Log.d(TAG, "subscribe: "+Thread.currentThread().getName());
}
});
Observer observer = new Observer<Integer>() {
Disposable d;
@Override
public void onSubscribe(Disposable d) {
this.d=d;
}
@Override
public void onNext(Integer o) {
Log.d(TAG, "onNext: "+Thread.currentThread().getName());
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
};
observable.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(observer);
log日志如图
其中用来指定线程的就是
observable.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(observer);
2.1 Schedulers
-
Schedulers.newThread()
:一个常规的子线程 -
AndroidSchedulers.mainThread()
:Activity所在的主线程 -
Schedulers.io()
:适合IO密集型的操作 -
Schedulers.computation()
:适合计算密集型的操作
2.2 subscribeOn
用来指定被观察者所在的线程,一般来说,我们在被观察者的内部执行网络请求或者IO
操作,所以放在子线程去执行。
注意一点,subscribeOn
方法如果被调用多次,以第一次调用时指定的线程为准,看如下代码
observable.subscribeOn(Schedulers.computation())
.subscribeOn(Schedulers.io())
.subscribeOn(Schedulers.newThread())
这上面上次调用了subscribeOn
方法,最后Observable
会依照第一次调用时指定的线程运行。
2.3 observerOn
它用来指定观察者所在的线程,由于观察者接受了被观察者操作的结果,有可能需要更新UI
,所以大部分情况下,我们都会将它指定在主线程之中。
同样需要注意一点,observerOn
方法多次被调用时,以最后一次指定的线程为准,即调用一次observerOn
方法,线程便会切换一次。
下面我们实战一个登录场景,观察RxJava切换线程的详细操作。
步骤一:先定义一个接口,这个接口就是登录接口,接口内有一个登录方法,该登录方法返回一个Observable对象,并且通过retrofit的注解,添加用户名和密码。
import io.reactivex.Observable;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.POST;
public interface LoginService {
//FormUrlEncoded表明这是一个表单请求
@FormUrlEncoded
@POST("login")
Observable<Result> userLogin(@Field("userAccount") String userAccount, @Field("userPwd") String userPwd);
}
步骤二:定义好接口,我们需要创建网络请求
private void userLogin(String userAccount,String userPwd){
String baseUrl = "http://10.138.51.142:8080/user/";
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
LoginService loginService = retrofit.create(LoginService.class);
loginService.userLogin(userAccount,userPwd)
.subscribeOn(Schedulers.io())//网络请求在子线程中执行
.observeOn(AndroidSchedulers.mainThread())//observer在主线程中执行,可以直接更新UI
.subscribe(new Observer<Result>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(Result result) {
Log.d(TAG, "onSubscribe: "+result.getMsg()+"---"+result.getRes()+"---"+result.getType());
if(result.getRes().equals("success")){
Toast.makeText(getApplicationContext(), "登录成功", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onError(Throwable e) {
Log.d(TAG, "onSubscribe: "+e.getMessage());
}
@Override
public void onComplete() {
Log.d(TAG, "onSubscribe: ");
}
});
}
结果显示:
四.总结RxJava执行线程切换有多么方便,终于不用再自己写handler了,并且使用retrofit+RaJava使网络请求更加简单了!