原文出處: C.L. Wang(@SpikeKing ) java
RxAndroid是RxJava的擴展, 優雅地處理異步請求. RxAndroid配合Lambda表達式, 精簡處理回調, 使程序更具備可讀性. Rx做爲Android最優秀的開源庫之一, 極大地提升生產力, 咱們須要掌握. 本文由淺入深, 介紹一些常見的使用方法, 並附有源碼.react
更多: http://www.wangchenlong.org/android
本文代碼的GitHub下載地址.git
要點包含:
(1) 鏈式表達式的使用方式.
(2) Lambda的應用.
(3) Rx處理網絡請求.
(4) 線程自動管理, 防止內存泄露.
(5) RxBinding綁定控件的異步事件.github
固然, 從一個嶄新的HelloWorld項目開始.json
添加Gradle配置.api
Java數組
1安全 2網絡 3 |
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表達式, 是寫出優雅代碼的關鍵, 參考.
Java
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
.
Java
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 |
/** * 主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
中, 建立一個觀察者, 收到字符串的返回.
Java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// 觀察事件發生 Observable.OnSubscribe mObservableAction = new Observable.OnSubscribe<String>() { @Override public void call(Subscriber<? super String> subscriber) { subscriber.onNext(sayMyName()); // 發送事件 subscriber.onCompleted(); // 完成事件 } };
...
// 建立字符串 private String sayMyName() { return "Hello, I am your friend, Spike!"; } |
建立兩個訂閱者, 使用字符串輸出信息.
Java
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 |
// 訂閱者, 接收字符串, 修改控件 Subscriber<String> mTextSubscriber = new Subscriber<String>() { @Override public void onCompleted() {
}
@Override public void onError(Throwable e) {
}
@Override public void onNext(String s) { mTvText.setText(s); // 設置文字 } };
// 訂閱者, 接收字符串, 提示信息 Subscriber<String> mToastSubscriber = new Subscriber<String>() { @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()
, 再傳遞給訂閱者, 由訂閱者最終處理消息. 接收信息能夠是同步, 也能夠是異步.
Java
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);
// 註冊觀察活動 @SuppressWarnings("unchecked") Observable<String> observable = Observable.create(mObservableAction);
// 分發訂閱信息 observable.observeOn(AndroidSchedulers.mainThread()); observable.subscribe(mTextSubscriber); observable.subscribe(mToastSubscriber); } |
咱們已經熟悉了初步的使用方式, 在接着學習一些其餘方法, 如
just
: 獲取輸入數據, 直接分發, 更加簡潔, 省略其餘回調.from
: 獲取輸入數組, 轉變單個元素分發.map
: 映射, 對輸入數據進行轉換, 如大寫.flatMap
: 增大, 本意就是增肥, 把輸入數組映射多個值, 依次分發.reduce
: 簡化, 正好相反, 把多個數組的值, 組合成一個數據.
來看看這個示例, 設置兩個不一樣類型數組, 做爲輸入源, 根據不一樣狀況分發數據.
Java
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 |
/** * 更多的RxAndroid的使用方法. * <p> * 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<String> mManyWordList = Arrays.asList(mManyWords);
// Action相似訂閱者, 設置TextView private Action1<String> mTextViewAction = new Action1<String>() { @Override public void call(String s) { mTvText.setText(s); } };
// Action設置Toast private Action1<String> mToastAction = new Action1<String>() { @Override public void call(String s) { Toast.makeText(MoreActivity.this, s, Toast.LENGTH_SHORT).show(); } };
// 設置映射函數 private Func1<List<String>, Observable<String>> mOneLetterFunc = new Func1<List<String>, Observable<String>>() { @Override public Observable<String> call(List<String> strings) { return Observable.from(strings); // 映射字符串 } };
// 設置大寫字母 private Func1<String, String> mUpperLetterFunc = new Func1<String, String>() { @Override public String call(String s) { return s.toUpperCase(); // 大小字母 } };
// 鏈接字符串 private Func2<String, String, String> mMergeStringFunc = new Func2<String, String, String>() { @Override public String call(String s, String s2) { return String.format("%s %s", s, s2); // 空格鏈接字符串 } };
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_simple); ButterKnife.bind(this);
// 添加字符串, 省略Action的其餘方法, 只使用一個onNext. Observable<String> obShow = Observable.just(sayMyName());
// 先映射, 再設置TextView obShow.observeOn(AndroidSchedulers.mainThread()) .map(mUpperLetterFunc).subscribe(mTextViewAction);
// 單獨顯示數組中的每一個元素 Observable<String> obMap = Observable.from(mManyWords);
// 映射以後分發 obMap.observeOn(AndroidSchedulers.mainThread()) .map(mUpperLetterFunc).subscribe(mToastAction);
// 優化過的代碼, 直接獲取數組, 再分發, 再合併, 再顯示toast, Toast順次執行. Observable.just(mManyWordList) .observeOn(AndroidSchedulers.mainThread()) .flatMap(mOneLetterFunc) .reduce(mMergeStringFunc) .subscribe(mToastAction); }
// 建立字符串 private String sayMyName() { return "Hello, I am your friend, Spike!"; } } |
此次簡化調用代碼, 由於有時候咱們對異常並非很關心,
只要能catch
異常便可, 所以流僅僅關注真正須要的部分.
輸入字符串, 變換大寫, 輸出至控件中顯示.
Java
1 2 3 4 5 6 |
// 添加字符串, 省略Action的其餘方法, 只使用一個onNext. Observable<String> obShow = Observable.just(sayMyName());
// 先映射, 再設置TextView obShow.observeOn(AndroidSchedulers.mainThread()) .map(mUpperLetterFunc).subscribe(mTextViewAction); |
just
能夠很是簡單的獲取任何數據, 分發時, 選擇使用的線程.map
是對輸入數據加工, 轉換類型, 輸入Func1
, 準換大寫字母.Func1
表明使用一個參數的函數, 前面是參數, 後面是返回值.Action1
表明最終動做, 於是不須要返回值, 而且一個參數.
輸入數組, 單獨分發數組中每個元素, 轉換大寫, 輸入Toast連續顯示.
Java
1 2 3 4 5 6 |
// 單獨顯示數組中的每一個元素 Observable<String> obMap = Observable.from(mManyWords);
// 映射以後分發 obMap.observeOn(AndroidSchedulers.mainThread()) .map(mUpperLetterFunc).subscribe(mToastAction); |
from
是讀取數組中的值, 每次單獨分發, 並分發屢次, 其他相似.
輸入數組, 映射爲單獨分發, 並組合到一塊兒, 集中顯示.
Java
1 2 3 4 5 6 |
// 優化過的代碼, 直接獲取數組, 再分發, 再合併, 再顯示toast, Toast順次執行. Observable.just(mManyWordList) .observeOn(AndroidSchedulers.mainThread()) .flatMap(mOneLetterFunc) .reduce(mMergeStringFunc) .subscribe(mToastAction); |
此次是使用
just
分發數組, 則分發數據就是數組, 並非數組中的元素.flatMap
把數組轉換爲單獨分發,Func1
內部使用from
拆分數組.reduce
把單獨分發數據集中到一塊兒, 再統一分發, 使用Func2
.
最終使用Action1
顯示得到數據. 本次代碼也更加簡潔.
由此咱們能夠觀察到, Rx的寫法能夠是多種多樣, 合理的寫法會更加優雅.
Lambda表達式和Rx很是契合, 能夠省略大量的內部類, 如Func和Action.
咱們把上個示例, 用Lambda再寫一次, 功能相同.
Java
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表達式寫法 * <p> * 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<String> mManyWordList = Arrays.asList(mManyWords);
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_simple); ButterKnife.bind(this);
// 添加字符串, 省略Action的其餘方法, 只使用一個onNext. Observable<String> obShow = Observable.just(sayMyName());
// 先映射, 再設置TextView obShow.observeOn(AndroidSchedulers.mainThread()) .map(String::toUpperCase).subscribe(mTvText::setText);
// 單獨顯示數組中的每一個元素 Observable<String> obMap = Observable.from(mManyWords);
// 映射以後分發 obMap.observeOn(AndroidSchedulers.mainThread()) .map(String::toUpperCase) .subscribe(this::showToast);
// 優化過的代碼, 直接獲取數組, 再分發, 再合併, 再顯示toast, Toast順次執行. Observable.just(mManyWordList) .observeOn(AndroidSchedulers.mainThread()) .flatMap(Observable::from) .reduce(this::mergeString) .subscribe(this::showToast); }
// 建立字符串 private String sayMyName() { return "Hello, I am your friend, Spike!"; }
// 顯示Toast private void showToast(String s) { Toast.makeText(LambdaActivity.this, s, Toast.LENGTH_SHORT).show(); }
// 合併字符串 private String mergeString(String s1, String s2) { return String.format("%s %s", s1, s2); } } |
此次沒有使用常規的Lambda表達式, 而是更簡單的
方法引用(Method References)
.
方法引用: 方法參數和返回值與Lambda表達式相同時, 使用方法名代替.
Retrofit是網絡請求庫, 剛推出2.0版本. Rx的一個核心應用就是處理異步網絡請求, 結合Retrofit, 會更加方便和簡潔. 參考.
引入庫
Java
1 2 3 4 5 6 7 |
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的用戶信息.
Java
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 |
/** * Rx的網絡請求方式 * <p> * 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類和數據類.
Java
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 |
/** * 顯示列表 * <p> * Created by wangchenlong on 15/12/31. */ public class UserListAdapter extends RecyclerView.Adapter<UserListAdapter.UserViewHolder> {
private List<GitHubUser> mUsers; // 用戶名集合
private NetworkActivity.UserClickCallback mCallback; // 用戶點擊項的回調
public UserListAdapter(NetworkActivity.UserClickCallback callback) { mUsers = new ArrayList<>(); mCallback = callback; }
public void addUser(GitHubUser user) { mUsers.add(user); notifyItemInserted(mUsers.size() - 1); // 最後一位 }
@Override public UserViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View item = LayoutInflater.from(parent.getContext()) .inflate(R.layout.item_network_user, parent, false); return new UserViewHolder(item, mCallback); }
@Override public void onBindViewHolder(UserViewHolder holder, int position) { holder.bindTo(mUsers.get(position)); }
@Override public int getItemCount() { return mUsers.size(); }
// Adapter的ViewHolder public static class UserViewHolder extends RecyclerView.ViewHolder {
@Bind(R.id.network_item_iv_user_picture) ImageView mIvUserPicture; @Bind(R.id.network_item_tv_user_name) TextView mTvUserName; @Bind(R.id.network_item_tv_user_login) TextView mTvUserLogin; @Bind(R.id.network_item_tv_user_page) TextView mTvUserPage;
public UserViewHolder(View itemView, NetworkActivity.UserClickCallback callback) { super(itemView); ButterKnife.bind(this, itemView); // 綁定點擊事件 itemView.setOnClickListener(v -> callback.onItemClicked(mTvUserLogin.getText().toString())); }
// 綁定數據 public void bindTo(GitHubUser user) { mTvUserName.setText(user.name); mTvUserLogin.setText(user.login); mTvUserPage.setText(user.repos_url);
Picasso.with(mIvUserPicture.getContext()) .load(user.avatar_url) .placeholder(R.drawable.ic_person_black_24dp) .into(mIvUserPicture); } }
// 用戶類, 名稱必須與Json解析相同 public static class GitHubUser { public String login; public String avatar_url; public String name; public String repos_url; } } |
添加數據
addUser
, 其中notifyItemInserted
通知更新.
能夠自動生成Json解析類的網站.
首先建立Retrofit
`服務, 經過服務獲取數據, 再依次分發給適配器.
Java
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 |
/** * 用戶獲取類 * <p> * 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
服務的工廠類.
Java
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 |
/** * 用戶獲取類 * <p> * 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); } } |
這是Retrofit 2.0的寫法, 注意須要添加Rx和Gson的解析.
設置網絡請求的Url.
Java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
/** * GitHub的服務 * <p> * Created by wangchenlong on 15/12/31. */ public interface GitHubService { String ENDPOINT = "https://api.github.com";
// 獲取我的信息 @GET("/users/{user}") Observable<UserListAdapter.GitHubUser> getUserData(@Path("user") String user);
// 獲取庫, 獲取的是數組 @GET("/users/{user}/repos") Observable<RepoListAdapter.GitHubRepo[]> getRepoData(@Path("user") String user); } |
詳情頁面與主頁相似, 參考代碼, 不作細說.
Rx的好處之一就是能夠防止內存泄露, 即根據頁面生命週期, 處理異步線程的結束. 可使用RxLifecycle庫處理生命週期.
Activity
類繼承RxAppCompatActivity
, 替換AppCompatActivity
.
啓動一個循環線程.
Java
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 |
/** * Rx的線程安全 * <p> * 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
時, 會自動結束循環線程. 若是註釋這句代碼, 則會致使內存泄露.
RxBinding是Rx中處理控件異步調用的方式, 也是由Square公司開發, Jake負責編寫. 經過綁定組件, 異步獲取事件, 並進行處理. 編碼風格很是優雅.
除了RxJava, 再添加RxBinding的依賴.
Java
1 2 3 4 |
// RxBinding compile 'com.jakewharton.rxbinding:rxbinding:0.3.0' compile 'com.jakewharton.rxbinding:rxbinding-appcompat-v7:0.3.0' compile 'com.jakewharton.rxbinding:rxbinding-design:0.3.0' |
Toolbar和Fab, 兩個較新的控件.
Java
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方法.
Java
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方式綁定控件, 異步監聽事件.
Java
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!