RxAndroid是RxJava的擴展, 優雅地處理異步請求. RxAndroid配合Lambda表達式, 精簡處理回調, 使程序更具備可讀性. Rx做爲Android最優秀的開源庫之一, 極大地提升生產力, 咱們須要掌握. 本文由淺入深, 介紹一些常見的使用方法, 並附有源碼.java
更多: http://www.wangchenlong.org/react
本文代碼的GitHub下載地址.android
要點包含:
(1) 鏈式表達式的使用方式.
(2) Lambda的應用.
(3) Rx處理網絡請求.
(4) 線程自動管理, 防止內存泄露.
(5) RxBinding綁定控件的異步事件.git
基礎
固然, 從一個嶄新的HelloWorld項目開始.github
添加Gradle配置.json
1 2 3
|
compile 'com.jakewharton:butterknife:7.0.1' compile 'io.reactivex:rxandroid:1.1.0' |
RxAndroid是本文的核心依賴, 同時添加RxJava. 還有ButterKnife註解庫.api
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+
以上, 配置很是簡單, 添加一個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
|
|
在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
|
|
在頁面中, 觀察者接收信息, 發送至主線程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);
|
最基礎的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
|
|
此次簡化調用代碼, 由於有時候咱們對異常並非很關心,
只要能catch
異常便可, 所以流僅僅關注真正須要的部分.
輸入字符串, 變換大寫, 輸出至控件中顯示.
just
能夠很是簡單的獲取任何數據, 分發時, 選擇使用的線程.
map
是對輸入數據加工, 轉換類型, 輸入Func1
, 準換大寫字母.
Func1
表明使用一個參數的函數, 前面是參數, 後面是返回值.
Action1
表明最終動做, 於是不須要返回值, 而且一個參數.
輸入數組, 單獨分發數組中每個元素, 轉換大寫, 輸入Toast連續顯示.
from
是讀取數組中的值, 每次單獨分發, 並分發屢次, 其他相似.
輸入數組, 映射爲單獨分發, 並組合到一塊兒, 集中顯示.
此次是使用just
分發數組, 則分發數據就是數組, 並非數組中的元素.
flatMap
把數組轉換爲單獨分發, Func1
內部使用from
拆分數組.
reduce
把單獨分發數據集中到一塊兒, 再統一分發, 使用Func2
.
最終使用Action1
顯示得到數據. 本次代碼也更加簡潔.
由此咱們能夠觀察到, Rx的寫法能夠是多種多樣, 合理的寫法會更加優雅.
效果
Lambda
Lambda表達式和Rx很是契合, 能夠省略大量的內部類, 如Func和Action.
咱們把上個示例, 用Lambda再寫一次, 功能相同.
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
|
|
此次沒有使用常規的Lambda表達式, 而是更簡單的方法引用(Method References)
.
方法引用: 方法參數和返回值與Lambda表達式相同時, 使用方法名代替.
網絡請求
Retrofit是網絡請求庫, 剛推出2.0版本. Rx的一個核心應用就是處理異步網絡請求, 結合Retrofit, 會更加方便和簡潔. 參考.
引入庫
1 2 3 4 5 6 7
|
compile 'com.android.support:recyclerview-v7:23.1.1' |
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
|
|
在列表中提供點擊用戶信息跳轉至用戶詳情.
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
|
|
添加數據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
|
|
網絡請求沒法在主線程上執行, 須要啓動異步線程, 如Schedulers.newThread()
.
使用工廠模式ServiceFactory
建立服務, 也能夠單首創建服務.
建立Retrofit
服務的工廠類.
這是Retrofit 2.0的寫法, 注意須要添加Rx和Gson的解析.
設置網絡請求的Url.
顯示用戶
詳情頁面與主頁相似, 參考代碼, 不作細說.
線程安全
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
|
|
繼承RxAppCompatActivity
, 添加bindToLifecycle
方法管理生命週期. 當頁面onPause
時, 會自動結束循環線程. 若是註釋這句代碼, 則會致使內存泄露.
RxBinding
RxBinding是Rx中處理控件異步調用的方式, 也是由Square公司開發, Jake負責編寫. 經過綁定組件, 異步獲取事件, 並進行處理. 編碼風格很是優雅.
除了RxJava, 再添加RxBinding的依賴.
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
|
<?xml version="1.0" encoding="utf-8"?> <android.support.design.widget.CoordinatorLayout 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.support.design.widget.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar 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.support.design.widget.AppBarLayout>
<include layout="@layout/content_rxbinding"/>
<android.support.design.widget.FloatingActionButton 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"/>
</android.support.design.widget.CoordinatorLayout>
|
兩個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
|
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 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">
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/usual_approach"/>
<EditText android:id="@+id/rxbinding_et_usual_approach" android:layout_width="match_parent" android:layout_height="48dp" android:hint="@null"/>
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/reactive_approach"/>
<EditText android:id="@+id/rxbinding_et_reactive_approach" android:layout_width="match_parent" android:layout_height="48dp" android:hint="@null"/>
<TextView android:id="@+id/rxbinding_tv_show" android:layout_width="match_parent" android:layout_height="wrap_content"/>
</LinearLayout>
|
使用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綁定 * <p> * 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(); // 初始化Fab按鈕 initEditText(); // 初始化編輯文本 }
// 初始化Toolbar private void initToolbar() { // 添加菜單按鈕 setSupportActionBar(mTToolbar); ActionBar actionBar = getSupportActionBar(); // 添加瀏覽按鈕 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); }
// 初始化Fab按鈕 private void initFabButton() { RxView.clicks(mFabFab).subscribe(this::onFabClicked); }
// 點擊Fab按鈕 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.我已委託「維權騎士」爲個人文章進行維權行動. 未經受權, 禁止轉載, 受權或合做請留言.