各位好,寫這篇文章主要是我在工作時發現了一個問題,現在使用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,就是模拟登入操作。
結構如下:
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIyVGduV2QvwVe0lmdhJ3ZvwFM38CXlZHbvN3cpR2Lc1TPB10QGtWUCpEMJ9CXsxWam9CXwADNvwVZ6l2c052bm9CXUJDT1wkNhVzLcRnbvZ2LcZXUYpVd1kmYr50MZV3YyI2cKJDT29GRjBjUIF2LcRHelR3LcJzLctmch1mclRXY39jMwkTNykzM5ADNwQDM2EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
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;
}
LoginBiz代碼:
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試試,下面是本文的源碼,可下載下傳下來運作試試
點選下載下傳源碼