各位好,写这篇文章主要是我在工作时发现了一个问题,现在使用RxAndroid解决了。
问题是:
我工作的项目是使用mvp模式写的,(关于什么是mvp,可参考:http://blog.csdn.net/lmj623565791/article/details/46596109)
而大家应该都知道,如果我们没有开启线程,则你代码里写的所有的任务将都在主线程中执行。
而主线程是不能执行耗时操作的(如:网络操作、访问数据库等)。
如果我们需要请求网络获取了数据之后更新ui界面,我们就必须开启一个线程来访问网络,获取了数据之后更新界面元素。
Activity中有个runOnUiThread的方法,可以使其在ui线程中运行。
而问题在于我的项目是使用mvp模式,m:处理逻辑,然后将处理的逻辑交给p层,p:是m层与v层的纽带。
而我执行网络操作是放在m层处理的,如果要用runOnUiThread这个方法就得把activity传进来,或者最后传到activity去,这都会乱了结构,使代码凌乱不堪。
在找解决办法时,我遇见了RxAndroid。(关于RxAndroid的基本使用,可参考:http://www.jianshu.com/p/51a8d2ff8697)
RxAndroid是RxJava的一个变体,它们都属于函数响应式编程
RxAndroid有什么作用呢?
1、函数响应式编程
2、异步
3、事件驱动(事件作为可观察序列)
4、基于观察者模式
5、组合式
6、专门出错处理
7、适用于处理并发问题
这不是我所注重,我最注重的是:提供了可设置计算的所在线程以及更新 UI 时可在主线程更新。
这里关于mvp模式与RxAndroid使用啥的就不说了,我主要将它们两者结合。
下面demo环节:
一个很简单的demo,就是模拟登录操作。
结构如下:
biz:数据处理层
ApiData:模拟后台数据
LoginBiz:mvp中的m层,用于处理登录逻辑
User:用户实体对象
view:界面层
ILoginView:登录界面,是一个接口,如:展示进度条、隐藏进度条、展示数据等
MainActivity:ILoginView的实现类
persenter:连接view与biz的纽带
LoginPersenter:请求LoginBiz获取数据,使用ILoginView层更新界面。
代码环节:
MainActivity代码:
public class MainActivity extends Activity implements ILoginView {
private EditText editText;
private TextView textView;
private LoginPresenter loginPresenter;
private ProgressBar progressBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editText = (EditText) findViewById(R.id.editText);
textView = (TextView) findViewById(R.id.textView);
progressBar = (ProgressBar) findViewById(R.id.progressBar);
loginPresenter = new LoginPresenter(this);
}
public void onClick(View view){
String userName = editText.getText().toString();
loginPresenter.doLogin(userName);
}
@Override
public void showView(String userName) {
textView.setText(userName);
}
@Override
public void showLoadding() {
progressBar.setVisibility(View.VISIBLE);
}
@Override
public void hideLoadding() {
progressBar.setVisibility(View.GONE);
}
}
ILoginView代码:
public interface ILoginView {
void showView(String userName);
void showLoadding();
void hideLoadding();
}
layout代码:
<LinearLayout 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:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical"
tools:context=".MainActivity">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="用户名"/>
<EditText
android:id="@+id/editText"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="DO"
android:onClick="onClick"/>
<ProgressBar
style="?android:attr/progressBarStyleLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/progressBar"
android:layout_gravity="center_horizontal"
android:visibility="gone"/>
</LinearLayout>
实体类User代码:
public class User {
public String name;
public String pwd;
}
public class LoginBiz {
private String TAG = "loginBiz";
public void doLogin(final OnGetDataListener<User> listener, final User user){
rx.Observable.create(new Observable.OnSubscribe<User>() {
@Override
public void call(Subscriber<? super User> subscriber) {
// 模拟执行网络操作
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
User user2 = new ApiData().doLogin(user);
subscriber.onNext(user2);
Log.e(TAG, "------->call线程:" + Thread.currentThread().getName());
}
}).subscribeOn(Schedulers.newThread()) // 子线程执行网络操作
.observeOn(AndroidSchedulers.mainThread()) // 转回主线程
.subscribe(new Subscriber<User>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable throwable) {
}
@Override
public void onNext(User user) {
if (user != null) {
listener.success(user);
}else{
listener.fail(user,"用户名错误");
}
}
});
}
}
可见使用 Schedulers.newThread() 是新见了一个线程执行的网络操作,使用observeOn(AndroidSchedulers.manThread())又切换到了主线程。
解决了线程来回切换问题,同时代码逻辑也十分清晰。
OnGetDataListener代码:
public interface OnGetDataListener<T> {
void success(T response); // 网络操作成功
void fail(T response, String msg); // 网络操作失败
}
LoginPresenter代码:
public class LoginPresenter {
private ILoginView loginView;
private LoginBiz loginBiz;
public LoginPresenter(ILoginView loginView) {
this.loginView = loginView;
this.loginBiz = new LoginBiz();
}
public void doLogin(String userName){
loginView.showLoadding(); // 展示加载条
User user = new User();
user.name = userName;
loginBiz.doLogin(new OnGetDataListener<User>() {
@Override
public void success(User response) {
loginView.hideLoadding(); // 隐藏加载条
loginView.showView(response.name); // 展示数据
}
@Override
public void fail(User response, String msg) {
loginView.hideLoadding();
loginView.showView(msg);
}
},user);
}
}
最后看下Log日志:
确实是开启的新线程,放心了。
看官可以自己写个demo试试,下面是本文的源码,可下载下来运行试试