<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
為了模擬實際場景,從wanandroid網站找了二個介面,如下:(對Wanandroid表示感謝!)
public interface ApiServer { /** * 介面一 * 獲取文章列表 * @return */ @GET("article/list/1/json") Observable<BaseResponse<ArticleListResp>> getArticleList(); /** * 介面二 * 獲取熱詞 * @return */ @GET("hotkey/json") Observable<BaseResponse<List<HotKeyResp.DataBean>>> getHotKey(); }
場景:比如呼叫介面一有回撥後才能呼叫介面二,如果介面一呼叫失敗不再呼叫介面二。下面是二種寫法。
寫法一,程式碼如下:
//為了看清楚程式碼,沒有使用lambda簡化 //介面一 Observable<BaseResponse<ArticleListResp>> articleList = ApiManager.getInstance().getApiService().getArticleList(); //介面二 Observable<BaseResponse<List<HotKeyResp.DataBean>>> hotKey = ApiManager.getInstance().getApiService().getHotKey(); Observable.just(articleList) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .map(new Function<Observable<BaseResponse<ArticleListResp>>, Observable<BaseResponse<List<HotKeyResp.DataBean>>>>() { @Override public Observable<BaseResponse<List<HotKeyResp.DataBean>>> apply(Observable<BaseResponse<ArticleListResp>> baseResponseObservable) throws Throwable { //處理第一個請求返回的資料 if(baseResponseObservable!=null) mTv.setText(baseResponseObservable.blockingSingle().toString()); return hotKey; //發起第二次網路請求 } }).subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Consumer<Observable<BaseResponse<List<HotKeyResp.DataBean>>>>() { @Override public void accept(Observable<BaseResponse<List<HotKeyResp.DataBean>>> baseResponseObservable) throws Throwable { //處理第二次網路請求的結果 if(baseResponseObservable!=null) mTvTwo.setText(baseResponseObservable.blockingSingle().toString()); } }, new Consumer<Throwable>() { @Override public void accept(Throwable throwable) throws Throwable { //異常的處理:比如Dialog的Dismiss,預設頁展示等 //注意:如果第一個網路請求異常,整個事件會中斷,不會執行第二個網路請求,如果多個請求同理 //但是請求成功的還是能正常處理 LogUtil.e(throwable.toString()); } });
寫法二,程式碼如下:
//為了看清楚程式碼,沒有使用lambda簡化 //介面一 Observable<BaseResponse<ArticleListResp>> articleList = ApiManager.getInstance().getApiService().getArticleList(); //介面二 Observable<BaseResponse<List<HotKeyResp.DataBean>>> hotKey = ApiManager.getInstance().getApiService().getHotKey(); //請求第一個 articleList.subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .doOnNext(new Consumer<BaseResponse<ArticleListResp>>() { @Override public void accept(BaseResponse<ArticleListResp> articleListRespBaseResponse) throws Throwable { //處理第一個網路請求的結果 if(articleListRespBaseResponse!=null) mTv.setText(articleListRespBaseResponse.toString()); } }).observeOn(Schedulers.io()) .flatMap(new Function<BaseResponse<ArticleListResp>, ObservableSource<BaseResponse<List<HotKeyResp.DataBean>>>>() { @Override public ObservableSource<BaseResponse<List<HotKeyResp.DataBean>>> apply(BaseResponse<ArticleListResp> articleListRespBaseResponse) throws Throwable { return hotKey; //將第一個網路請求轉換為第二個網路請求 } }).observeOn(AndroidSchedulers.mainThread()) .subscribe(new Consumer<BaseResponse<List<HotKeyResp.DataBean>>>() { @Override public void accept(BaseResponse<List<HotKeyResp.DataBean>> listBaseResponse) throws Throwable { //處理第二次網路請求的結果 if(listBaseResponse!=null) mTvTwo.setText(listBaseResponse.toString()); } }, new Consumer<Throwable>() { @Override public void accept(Throwable throwable) throws Throwable { //注意:如果第一個網路請求異常,整個事件會中斷,不會執行第二個網路請求,多個請求同理 //但是在異常前面已經成功的網路請求還是能正常處理 //異常的處理:比如Dialog的Dismiss,預設頁展示等 LogUtil.e(throwable.toString()); } });
注意例外處理和執行緒切換,其他細節程式碼和註釋比較詳細。
場景:介面一和介面二返回資料後一起處理。
程式碼如下:
private void zipRequest() { //為了看清楚程式碼,沒有使用lambda簡化 //介面一 Observable<BaseResponse<ArticleListResp>> articleList = ApiManager.getInstance().getApiService().getArticleList(); //介面二 Observable<BaseResponse<List<HotKeyResp.DataBean>>> hotKey = ApiManager.getInstance().getApiService().getHotKey(); Observable.zip(articleList, hotKey, this::combiNotification) //傳入方法定義合併規則 .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer<String>() { @Override public void onSubscribe(@NonNull Disposable d) { } @Override public void onNext(@NonNull String msg) { if(!TextUtils.isEmpty(msg)){ mTv.setText(msg); } } @Override public void onError(@NonNull Throwable e) { } @Override public void onComplete() { } }); } //合併的規則,以及定義合併的返回值 public String combiNotification(BaseResponse<ArticleListResp> articleListRespBaseResponse, BaseResponse<List<HotKeyResp.DataBean>> hotkeyResponse) { //比如這裡取二個介面資料toString返回 if (articleListRespBaseResponse != null && hotkeyResponse != null) { return articleListRespBaseResponse.toString() + hotkeyResponse.toString(); } return null; }
場景一:輪詢固定的次數(間隔一定的時間),可以提前退出輪詢,也可以等輪詢到指定次數後自動退出,每次輪詢必須等上一次輪詢有結果後才能開始下一次輪詢。
特別注意repeatWhen操作符,只有在repeatWhen的Function方法中發射onNext事件,重複(repeat)才能觸發,發射onError或者onComplite都會結束重複(repeat),基於這一點,通過flatMap操作符將事件轉化為延遲一定時間的onNext事件,就達到了延時輪詢的目的。至於onNext事件發射的什麼不重要。
延伸:retryWhen的Function方法發射onError事件才會重試(retry)。
takeUntil操作符可以定義一定的條件,當達到條件時自動結束整個事件的目的,事件結束時會回撥subscribe。
程式碼如下:
/** * 輪詢 * @param pollingTimes 輪詢的次數 */ private void timedPolling(int pollingTimes) { AtomicInteger times = new AtomicInteger(); Observable<BaseResponse<ArticleListResp>> articleList = ApiManager.getInstance().getApiService().getArticleList(); articleList.repeatWhen(new Function<Observable<Object>, ObservableSource<?>>() { @Override public ObservableSource<?> apply(Observable<Object> objectObservable) throws Throwable { return objectObservable.flatMap(new Function<Object, ObservableSource<?>>() { //轉換事件 @Override public ObservableSource<?> apply(Object o) throws Throwable { //這裡發射延時的onNext事件,觸發repeat動作,發射的0不會回撥到下面的subscribe return Observable.just(0).delay(2, TimeUnit.SECONDS); } }); } }).subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) //takeUntil定義了二個結束條件:前面是達到了輪詢的次數,後面是網路請求返回了成功,當然也可以寫成程式碼塊做其他的返回判斷 .takeUntil(response -> times.incrementAndGet() >= pollingTimes || response.getErrorCode() == 0) .subscribe(new Observer<BaseResponse<ArticleListResp>>() { @Override public void onSubscribe(@NonNull Disposable d) { } @Override public void onNext(@NonNull BaseResponse<ArticleListResp> articleListRespBaseResponse) { } @Override public void onError(@NonNull Throwable e) { } @Override public void onComplete() { } }); }
如果想改成不限制次數的也比較簡單。
場景二:輪詢固定的次數(間隔一定的時間),可以提前退出輪詢,也可以等輪詢到指定次數後自動退出,這裡的輪詢不關心上次請求的結果。
程式碼如下:
/** * 輪詢一定的次數 * @param pollTimes 輪詢次數 */ private void timedPolling(int pollTimes) { //網路請求 Observable<BaseResponse<ArticleListResp>> articleList = ApiManager.getInstance().getApiService().getArticleList(); //返回值用於取消輪詢 mSubscribe = Observable.intervalRange(0, pollTimes, 0, 2000, TimeUnit.MILLISECONDS) .flatMap(new Function<Long, ObservableSource<BaseResponse<ArticleListResp>>>() { @Override public ObservableSource<BaseResponse<ArticleListResp>> apply(Long aLong) throws Throwable { return articleList; //轉換事件 } }).subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Consumer<BaseResponse<ArticleListResp>>() { @Override public void accept(BaseResponse<ArticleListResp> listBaseResponse) throws Throwable { //如果滿足了退出輪詢的條件,可以呼叫下面的方法退出輪詢 //mSubscribe.dispose(); } }); }
思路是定時發射事件,然後將事件轉化為網路請求。同理可以寫出不限次數的輪詢。
場景三:不限次數輪詢(間隔一定的時間),不關心上次請求的結果。
假如介面返回的code為0時需要取消輪詢,程式碼如下:
Observable<BaseResponse<ArticleListResp>> articleList = ApiManager.getInstance().getApiService().getArticleList(); //返回值用於取消輪詢 mSubscribe = Observable.interval(0, 2000, TimeUnit.MILLISECONDS) .flatMap(new Function<Long, ObservableSource<BaseResponse<ArticleListResp>>>() { @Override public ObservableSource<BaseResponse<ArticleListResp>> apply(Long aLong) throws Throwable { return articleList; } }) .takeUntil(response -> response.getErrorCode() == 0) //使用takeUntil自動取消發射 .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Consumer<BaseResponse<ArticleListResp>>() { @Override public void accept(BaseResponse<ArticleListResp> articleListRespBaseResponse) throws Throwable { //處理回撥 } }, new Consumer<Throwable>() { @Override public void accept(Throwable throwable) throws Throwable { //處理異常 } });
如果是其他取消條件,也可以寫在程式碼塊裡:
.takeUntil(response -> { //處理介面資料,然後判斷是返回true還是false,true:停止發射,false:繼續發射 return false; }) //使用takeUntil自動取消發射
不管何種輪詢,注意在OnDestroy中取消。
驗證碼的倒計時功能,程式碼如下:
/** * 倒計時 * @param countDownSeconds 倒計時的秒數 */ private void countDown(int countDownSeconds) { Observable.intervalRange(0, countDownSeconds, 0, 1000, TimeUnit.MILLISECONDS) .map(new Function<Long, String>() { @Override public String apply(Long aLong) throws Throwable { return (countDownSeconds - aLong) + "s後重新獲取"; } }).observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer<String>() { @Override public void onSubscribe(@NonNull Disposable d) { mTv.setEnabled(false); } @Override public void onNext(@NonNull String s) { mTv.setText(s); } @Override public void onError(@NonNull Throwable e) { mTv.setEnabled(true); mTv.setText("獲取驗證碼"); } @Override public void onComplete() { mTv.setText("獲取驗證碼"); mTv.setEnabled(true); } }); }
效果
幾行程式碼實現打字機效果:
@RequiresApi(api = Build.VERSION_CODES.M) //6.0 public class DaziView extends View { private TextPaint mTextPaint; private StaticLayout mStaticLayout; public DaziView(Context context) { super(context,null); } public DaziView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); initTextPaint(); } /** * 初始化畫筆 */ private void initTextPaint() { mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); mTextPaint.setTextSize(48); mTextPaint.setColor(Color.parseColor("#000000")); } /** * 繪製 * @param content */ public void drawText(String content){ if(!TextUtils.isEmpty(content)){ Observable.intervalRange(0,content.length()+1,0,150, TimeUnit.MILLISECONDS) .subscribe(new Consumer<Long>() { @Override public void accept(Long aLong) throws Throwable { //動態改變文字長度 mStaticLayout = StaticLayout.Builder.obtain(content, 0, aLong.intValue(), mTextPaint, getWidth()) .build(); invalidate(); } }); } } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //繪製文字 mStaticLayout.draw(canvas); } }
效
文字
<string name="dazi_content">u3000u3000你好,這是一個打字機,這是一個打字機這是一個打字機這是一個打字機。nu3000u3000換行空格繼續列印。</string>
RxBinding 提供的繫結能夠將任何 Android View 事件轉換為 Observable。
一旦將 View 事件轉換為 Observable ,將發射資料流形式的 UI 事件,我們就可以訂閱這個資料流,這與訂閱其他 Observable 方式相同。
引入下面的庫:
implementation 'com.jakewharton.rxbinding4:rxbinding:4.0.0'
點選事件的寫法:
RxView.clicks(button) //button為控制元件 .subscribe(new Consumer<Unit>() { @Override public void accept(Unit unit) throws Throwable { //點選事件 } });
長點選事件的寫法:
RxView.longClicks(button) .subscribe(new Consumer<Unit>() { @Override public void accept(Unit unit) throws Throwable { //長點選自動響應,不需要等放開手指 } });
點選防抖事件的寫法:
RxView.clicks(button) .throttleFirst(1000, TimeUnit.MILLISECONDS) //一秒以內第一次點選事件有效 .subscribe(new Consumer<Unit>() { @Override public void accept(Unit unit) throws Throwable { //點選事件 } });
RxTextView.textChanges(editText) //傳入EditText控制元件 .debounce(1000,TimeUnit.MILLISECONDS) //一秒內沒有新的事件時,取最後一次事件發射 .skip(1) //跳過第一次EditText的空內容 .subscribeOn(AndroidSchedulers.mainThread()) .subscribe(new Consumer<CharSequence>() { @Override public void accept(CharSequence charSequence) throws Throwable { //EditText的內容 } }, new Consumer<Throwable>() { @Override public void accept(Throwable throwable) throws Throwable { } });
combineLatest 操作符將多個 Observable 發射的事件組裝起來,然後再發射組裝後的新事件。
Observable<CharSequence> observableEdittext = RxTextView.textChanges(editText).skip(1); Observable<CharSequence> observableEdittextTwo = RxTextView.textChanges(editText_two).skip(1); Observable.combineLatest(observableEdittext, observableEdittextTwo, new BiFunction<CharSequence, CharSequence, Boolean>() { @Override public Boolean apply(CharSequence charSequence, CharSequence charSequence2) throws Throwable { if(!TextUtils.isEmpty(charSequence)&&!TextUtils.isEmpty(charSequence2)){ return true; } return false; } }).subscribe(new Consumer<Boolean>() { @Override public void accept(Boolean aBoolean) throws Throwable { //TODO 其他處理 } });
Observable<Integer> just = Observable.just(0); just.subscribeOn(Schedulers.io()).unsubscribeOn(Schedulers.io()); //取消事件,防止洩漏
這個比較常用。
對訂閱事件統一管理
CompositeDisposable compositeDisposable = new CompositeDisposable(); compositeDisposable.add(disposableOne); compositeDisposable.add(disposableTwo); compositeDisposable.clear();
到此這篇關於Android Rxjava3 使用場景詳解的文章就介紹到這了,更多相關Android Rxjava3 使用場景內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45