rxjava在我看來就是一套比較先進的asynctask,用來處理異步請求的一種規範(得益於它的代碼思路清晰),在android中可以用來代替asynctask甚至是handler。常與當前流行網絡請求框架retrofit2一同使用。
rxjava的採用了觀察者模式:Observer/Subscriber(觀察者),Observable(主題)。個人喜歡把Observer/Subscriber當做事件的消費者,Observable當做是事件的產生者。
優點:線程切換(android 網絡請求與UI刷新),邏輯清晰
android-studio 環境配置:
compile 'io.reactivex:rxjava:1.0.14'
compile 'io.reactivex:rxandroid:1.0.1'
Observer/Subscriber(觀察者)
Observer<String> observer=new Observer<String>() {
@Override
public void onCompleted() {
Log.i("rxjava::","onCompleted::");
}
@Override
public void onError(Throwable e) {
Log.i("rxjava::","onError::"+e.getMessage());
}
@Override
public void onNext(String s) {
/**
* 被觀察者“發給” 觀察者的消息
* 可以理解成 事件在這裏消費
*/
Log.i("rxjava::","onNext::"+s);
}
};
Subscriber<String> subscriber=new Subscriber<String>() {
@Override
public void onCompleted() {
Log.i("rxjava::","onCompleted::");
}
@Override
public void onStart() {
super.onStart();
Log.i("rxjava::","onStart::");
}
@Override
public void onError(Throwable e) {
Log.i("rxjava::","onError::"+e.getMessage());
}
@Override
public void onNext(String s) {
Log.i("rxjava::","onNext::"+s);
}
};
觀察者兩種寫法的區別:
1.Subscriber
對 Observer
接口進行了一些擴展,即Subscriber
裏可以重寫一個onstart的方法
2.onstart方法:在被觀察者“發送”消息之前。我也不知道有什麼軟用,不能加載進度條(因爲不在UI線程)
Observable(被觀察者)
Observable<String> observable = Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
//事件中心
subscriber.onNext("hasaki");
subscriber.onNext("mianduijifengba");
subscriber.onCompleted();//此句話要是不調用 觀察者裏的oncompleted方法就不會調用
}
});
Subject:也是一種事件的產生與發送者,可替代Observable
PublishSubject.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
subscriber.onNext("nihao");
}
}).subscribe(new Subscriber<String>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(String s) {
Log.i("TTTTT:::",s+"???");
}
});
/**
* 此方法默認在執行結束加上onCompleted();
*/
Observable<String> observable = Observable.just("hasaki","mianduijifengba");
from(可傳入對象數組);
String[] requestArray={"hasaki","mianduijifengba"};
/**
* 此方法默認在執行結束加上onCompleted();
*/
Observable<String> observable = Observable.from(requestArray);
//訂閱
observable.subscribe(subscriber);
取消訂閱:(對於異步請求結束後,要解除引用關係,避免內存泄漏)
一般訂閱之後都會產生一個Subscription對象
//訂閱
Subscription subscribe = observable.subscribe(subscriber);
if(subscribe.isUnsubscribed()){
//判斷是否解除訂閱
Log.i("rxjava","沒有解除訂閱");
subscribe.unsubscribe();//解除訂閱
}else{
Log.i("rxjava","解除訂閱");
}
observable.subscribeOn();//設置被觀察者裏事件產生所處的線程,即:調用call方法所處的線程
observable.observeOn();//觀察者,事件消費所處的線程即:onNext
Schedulers.immediate()//當前線程,即默認
Schedulers.newThread()//顧名思義,開啓新線程
Schedulers.io()//相當於cacheThreadPool 維護一個不定數量的線程池,還可重複利用
AndroidSchedulers.mainThread()//android 專利,顧名思義,即主線程。
example:開啓線程讀取數據,UI線程跟新數據::
String[] requestArray = {"hasaki", "面對疾風吧"};
Observable.from(requestArray)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<String>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(String s) {
tv.setText(s);
}
});
中級進階(變換)
所謂變換,就是將事件序列中的對象或整個序列進行加工處理,轉換成不同的事件或事件序列。
1.Map(轉換類操作符)單個轉換
什麼是轉成不同的事件?
說白了就是我要把現金存入支付寶,我的事件隊列是現金,我最後想要的事件結果是支付寶裏有錢,可是現金不能直接存支付寶,得先變換一下
,即先存銀行卡轉成電子貨幣,最後支付寶轉賬。(轉單個事件)
/**
* 假設字符串格式爲現金
* int格式爲電子貨幣
* func:字符串轉int
*/
Observable.just("100").map(new Func1<String, Integer>() {
@Override
public Integer call(String s) {
//先轉電子貨幣
return Integer.valueOf(s);
}
}).subscribe(new Subscriber<Integer>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(Integer integer) {
Log.i("電子貨幣轉支付寶::", integer + "");
}
});
map的功能:即對象的一對一轉換,當被觀察者事件產生了,先執行map裏的方法,再到觀察者消費事件(對象的直接變換)
func1:提供了一個有形參和返回值的call方法(call方法?秀等麻袋,請自行對比一下之前被觀察者裏產生事件的call方法,先埋一個坑)
2.flatMap(轉換類操作符)
那轉不同的事件序列呢?(也就是轉一堆)
example:假設一天馬雲爸爸閒的蛋疼,他想看看他的支付寶後臺,他想知道每個人的名字,以及每個人都綁定了什麼樣的銀行卡。就是循環打印人名和循環
打印card名,假設類該這麼寫:Person類裏維護了一個name和card數組,card類裏維護了cardname和cardmoney
Person[] persons = {new Person("張三", new Card[]{new Card("工商", "100"), new Card("農行", "200")}),
new Person("亞索", new Card[]{new Card("工商", "300"), new Card("農行", "400")})
};
Observable.from(persons).flatMap(new Func1<Person, Observable<Card>>() {
@Override
public Observable<Card> call(Person person) {
Log.i("rxjava::", person.getName());
return Observable.from(person.getCards());
}
}).subscribe(new Subscriber<Card>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(Card card) {
Log.i("rxjava::", card.toString());
}
});
flatMap:對象轉新的事件序列,注意func1返回值的變換,他返回的是一個被觀察者對象,然後又拿着這個對象去
請求新的序列。
這裏的應用環境究竟是什麼樣的呢,假設你要讀取列表中的某個key,然後拿着這key讀取新的列表
會用到吧?我也沒用過啊,我是邊看別人的博客,寫下自己的理解。
我的理解:將一堆事件序列轉成一個Observerble再統一發出去
flatMap的交叉問題:假設現有一個數組person[3]{校長,老師,學生},經過flatMap要求得到每個人身上的錢,
也許取的第一個對象是校長,第二個是老師,也許取的第一個對象是校長,第二個對象是學生。也就是說只
保證鋪平序列,不能保證發送序列的順序。
問題:我寫的例子裏,都是正常發送的順序未發現錯亂,也許是數據源基數太小。
3.contatMap(轉換類操作符)
User[] users=new User[]{new User("張三","22"),new User("李四","23"),new User("老王","24")};
Observable.from(users).concatMap(new Func1<User, Observable<String>>() {
@Override
public Observable<String> call(User user) {
return Observable.just(user.getFirstName());
}
}).subscribe(new Action1<String>() {
@Override
public void call(String s) {
Log.i("YYYYTTT::",s);
}
});
Observable.just(1, 2, 3, 4, 5)
.scan(new Func2<Integer, Integer, Integer>() {
@Override
public Integer call(Integer integer, Integer integer2) {
Log.i("YYYYTTT????", integer+"/"+integer2);
return integer + integer2;
}
}).subscribe(new Action1<Integer>() {
@Override
public void call(Integer integer) {
Log.i("YYYYTTT::", integer+"");
}
});
5.filter(過濾操作符)
List<User> users=new ArrayList<User>();
users.add(new User("張三", "22"));
users.add(new User("李四", "24"));
users.add(new User("老王", "25"));
users.add(new User("大錘", "22"));
users.add(new User("大錘", "25"));
Observable.from(users).filter(new Func1<User, Boolean>() {
@Override
public Boolean call(User user) {
if (user.getFirstName().equals("張三")){
return false;//過濾掉
}else{
return true;//留着
}
}
}).subscribe(new Action1<User>() {
@Override
public void call(User user) {
Log.i("GGGDDD::",user.toString());
}
});
List<User> users=new ArrayList<User>();
users.add(new User("張三", "22"));
users.add(new User("李四", "24"));
users.add(new User("老王", "25"));
users.add(new User("大錘", "22"));
users.add(new User("大錘", "25"));
Observable.from(users).take(3).subscribe(new Action1<User>() {
@Override
public void call(User user) {
Log.i("GGGDDD::",user.toString());
}
});
List<User> users = new ArrayList<User>();
users.add(new User("張三", "22"));
users.add(new User("李四", "24"));
users.add(new User("老王", "25"));
users.add(new User("大錘", "25"));
users.add(new User("大錘", "25"));
Observable.from(users).first().subscribe(new Action1<User>() {
@Override
public void call(User user) {
Log.i("GGGDDD::",user.toString());
}
});
List<User> users=new ArrayList<User>();
users.add(new User("張三", "22"));
users.add(new User("李四", "24"));
users.add(new User("老王", "25"));
users.add(new User("大錘", "22"));
users.add(new User("大錘", "25"));
Observable.from(users).takeLast(3).subscribe(new Action1<User>() {
@Override
public void call(User user) {
Log.i("GGGDDD::",user.toString());
}
});
List<User> users=new ArrayList<User>();
users.add(new User("張三", "22"));
users.add(new User("李四", "24"));
users.add(new User("老王", "25"));
users.add(new User("大錘", "22"));
users.add(new User("大錘", "25"));
Observable.from(users).takeUntil(new Func1<User, Boolean>() {
@Override
public Boolean call(User user) {
if (user.getFirstName().equals("大錘")){
return true;//讀到此處不再讀取
}else{
return false;
}
}
}).subscribe(new Action1<User>() {
@Override
public void call(User user) {
Log.i("GGGDDD::",user.toString());
}
});
7.skip(過濾操作符)
List<User> users=new ArrayList<User>();
users.add(new User("張三", "22"));
users.add(new User("李四", "24"));
users.add(new User("老王", "25"));
users.add(new User("大錘", "22"));
users.add(new User("大錘", "25"));
Observable.from(users).skip(3).subscribe(new Action1<User>() {
@Override
public void call(User user) {
Log.i("GGGDDD::",user.toString());
}
});
//忽略後三項的數據
List<User> users=new ArrayList<User>();
users.add(new User("張三", "22"));
users.add(new User("李四", "24"));
users.add(new User("老王", "25"));
users.add(new User("大錘", "22"));
users.add(new User("大錘", "25"));
Observable.from(users).skipLast(3).subscribe(new Action1<User>() {
@Override
public void call(User user) {
Log.i("GGGDDD::",user.toString());
}
});
8.elementAt(過濾操作符)
List<User> users=new ArrayList<User>();
users.add(new User("張三", "22"));
users.add(new User("李四", "24"));
users.add(new User("老王", "25"));
users.add(new User("大錘", "22"));
users.add(new User("大錘", "25"));
Observable.from(users).elementAt(3).subscribe(new Action1<User>() {
@Override
public void call(User user) {
Log.i("GGGDDD::",user.toString());
}
});
List<User> users = new ArrayList<User>();
users.add(new User("張三", "22"));
users.add(new User("李四", "24"));
users.add(new User("老王", "25"));
users.add(new User("大錘", "25"));
users.add(new User("大錘", "25"));
Observable.from(users).distinct().subscribe(new Action1<User>() {
@Override
public void call(User user) {
Log.i("GGGDDD::", user.toString());
}
});
List<User> users = new ArrayList<User>();
users.add(new User("張三", "22"));
users.add(new User("李四", "24"));
users.add(new User("老王", "25"));
users.add(new User("大錘", "25"));
users.add(new User("大錘", "25"));
Observable.from(users).distinct(new Func1<User, String>() {
@Override
public String call(User user) {
return user.getFirstName();//過濾掉重名
}
}).subscribe(new Action1<User>() {
@Override
public void call(User user) {
Log.i("GGGDDD::",user.toString());
}
});
List<User> users = new ArrayList<User>();
users.add(new User("張三", "22"));
users.add(new User("李四", "24"));
users.add(new User("老王", "25"));
users.add(new User("大錘", "25"));
users.add(new User("大錘", "25"));
Observable.from(users).last().subscribe(new Action1<User>() {
@Override
public void call(User user) {
Log.i("GGGDDD::",user.toString());
}
});
11.merge(組合操作符)
List<User> users = new ArrayList<User>();
users.add(new User("張三", "22"));
users.add(new User("李四", "24"));
users.add(new User("老王", "25"));
users.add(new User("大錘", "25"));
users.add(new User("大錘", "25"));
Observable<User> ob1 = Observable.from(users);
Observable<Integer> ob2 = Observable.just(1, 2, 3, 4);
Observable.merge(ob1, ob2).subscribe(new Subscriber<Object>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(Object o) {
Log.i("TTGGG:::",o.toString());
}
});
List<User> users = new ArrayList<User>();
users.add(new User("張三", "22"));
users.add(new User("李四", "24"));
users.add(new User("老王", "25"));
users.add(new User("大錘", "25"));
users.add(new User("大錘", "25"));
Observable.from(users).startWith(new User("帥哥","18")).subscribe(new Action1<User>() {
@Override
public void call(User user) {
Log.i("TTTDDDD::",user.toString());
}
});
List<User> users = new ArrayList<User>();
users.add(new User("張三", "22"));
users.add(new User("李四", "24"));
users.add(new User("老王", "25"));
users.add(new User("大錘", "25"));
users.add(new User("大錘", "25"));
Observable<User> ob1 = Observable.from(users);
Observable<Integer> ob2 = Observable.just(1, 2, 3, 4, 5);
Observable.concat(ob1, ob2).subscribe(new Action1<Object>() {
@Override
public void call(Object o) {
Log.i("TTGGGD:",o.toString());
}
});
List<User> users = new ArrayList<User>();
users.add(new User("張三", "22"));
users.add(new User("李四", "24"));
users.add(new User("老王", "25"));
users.add(new User("大錘", "25"));
users.add(new User("大錘", "25"));
Observable<User> ob1 = Observable.from(users);
Observable<Integer> ob2 = Observable.just(1, 2, 3, 4, 5,6);
Observable.zip(ob1, ob2, new Func2<User, Integer, String>() {
@Override
public String call(User user, Integer integer) {
return user.getFirstName()+integer;
}
}).subscribe(new Action1<String>() {
@Override
public void call(String s) {
Log.i("TGGDD::",s);
}
});
List<User> users = new ArrayList<User>();
users.add(new User("張三", "22"));
users.add(new User("李四", "24"));
users.add(new User("老王", "25"));
users.add(new User("大錘", "25"));
users.add(new User("大錘", "25"));
Observable<User> ob1 = Observable.from(users);
Observable<Integer> ob2 = Observable.just(1, 2, 3, 4, 5,6);
Observable.combineLatest(ob1, ob2, new Func2<User, Integer, String>() {
@Override
public String call(User user, Integer integer) {
return user.getFirstName()+integer;
}
}).subscribe(new Action1<String>() {
@Override
public void call(String s) {
Log.i("TGGDD::",s);
}
});
總結:既然rxjava裏可以轉換,那麼轉換處在哪個線程裏呢,轉換通通處在觀察者的線程裏
即你在轉換之前observable.observeOn()設定的是什麼線程,它就處在什麼線程裏。
高級進階:
rxjava+retrofit2
關於retrofit2我也在學習中,先做簡單的使用:
導入:
compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.retrofit2:converter-scalars:2.0.0'
compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0'
別忘了添加網絡權限,切記要添加
addCallAdapterFactory(RxJavaCallAdapterFactory.create())//讓rxjava能使用retrofit2
private void initData() {
Retrofit retrofit = new Retrofit.Builder().baseUrl("http://fdj.abc5.cn")
.addConverterFactory(ScalarsConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
HttpUser httpUser = retrofit.create(HttpUser.class);
httpUser.getUsers("hcy", "1234")
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<String>() {
@Override
public void onCompleted() {
Log.i("網絡請求的數據::", "onCompleted");
}
@Override
public void onError(Throwable e) {
Log.i("網絡請求的數據::", "onError" + e.getMessage());
}
@Override
public void onNext(String s) {
Log.i("網絡請求的數據::", s);
tv.setText(s);
}
});
}
public interface HttpUser {
@POST("/api/index/posttest")
@FormUrlEncoded
Observable<String> getUsers(@Field("username") String username, @Field("password") String password);
}
小結:
關於Action1,Action0,Func1使用與區別:
Func1:有形參,有返回
Func2:多個形參,有返回
Action1:有形參,無返回
Action0:無形參,無返回
Action1,Action0可以代替觀察者裏的三個方法,OnNext,OnError,OnCompleted;
Action1<String> onNextAction = new Action1<String>() {
// onNext()
@Override
public void call(String s) {
Log.i("onNext:::",s);
}
};
Action1<Throwable> onErrorAction = new Action1<Throwable>() {
// onError()
@Override
public void call(Throwable throwable) {
Log.i("onError:::",throwable.getMessage());
}
};
Action0 onCompletedAction = new Action0() {
// onCompleted()
@Override
public void call() {
Log.i("onCompleted","");
}
};
Observable.just("hasaki","posigei").subscribe(onNextAction,onErrorAction,onCompletedAction);
如何多次切換線程::(線程切換容易出現的異常::java.lang.IllegalStateException: Fatal Exception thrown on Scheduler.Worker thread.
找到異常的最後一般又可以看到::Caused by: android.os.NetworkOnMainThreadException)
example:像我所在的公司要強求服務器的一條連接,要請求兩次,第一次請求服務器的時間,然後按
字母順序將請求的參數排序在最後加載請求的時間和appkey字段形成sign,再把sign和時間放入
參數map中請求第二個連接才能得到想要的數據,是不是賊幾把麻煩,以前封裝的時候因爲要考慮到
其實是兩次網絡請求(不能放在主線程中,android基礎),但請求得到的數據我又想能切換到主線程
跟新UI,以前的代碼一大堆,現在貼出我第一次封裝的代碼,感受下rxjava切換線程的好處
package utils;
import android.util.Log;
import com.alibaba.fastjson.JSON;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import contact.Contact;
import okhttp3.RequestBody;
import retrofit2.Call;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
import retrofit2.converter.scalars.ScalarsConverterFactory;
import retrofit2.http.GET;
import retrofit2.http.Multipart;
import retrofit2.http.POST;
import retrofit2.http.PartMap;
import retrofit2.http.Url;
import rx.Observable;
import rx.Subscriber;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Func1;
import rx.schedulers.Schedulers;
/**
* Created by hcy on 2016/12/24.
*/
public class WytHttpUtils {
public interface HttpServerTime {
@GET("/api/getservicetime.php")
Observable<HttpTime> HttpTime();
}
public interface HttpResult {
@POST
@Multipart
Observable<String> httpResult(@Url String url, @PartMap Map<String, RequestBody> params);
}
private Map<String, String> map;
public WytHttpUtils(Map<String, String> map) {
this.map = map;
}
public void HttpRequest(String url) {
ServiceFactory.createServiceFrom(HttpServerTime.class, "http://iexue.quxue100.cn")
.HttpTime()
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.flatMap(new Func1<HttpTime, Observable<String>>() {
@Override
public Observable<String> call(HttpTime httpTime) {
Log.i("DDDSSS222::", httpTime.toString());
if (httpTime.getStatus() == 1) {
//時間獲取成功
String sign = getValueFromMap(map).append(httpTime.getResult()).append(Contact.APPKEY).toString();
map.put("time", httpTime.getResult() + "");
map.put("sign", md5Encode(sign));
getValueFromMap2(map);
Observable<String> observable1 = ServiceFactory.createServiceFrom(HttpResult.class,"http://iexue.quxue100.cn").httpResult(url, getValueFromMap2(map));
return observable1;
} else {
return null;
}
}
}).observeOn(AndroidSchedulers.mainThread())//切換到主線程
.subscribe(new Subscriber<String>() {
@Override
public void onCompleted() {
Log.i("rxjava::onCompleted:", "onCompleted");
}
@Override
public void onError(Throwable e) {
Log.i("rxjava::onError:", e.getMessage());
}
@Override
public void onNext(String s) {
Log.i("rxjava::onNext:", s);
}
});
//return observable;
}
private String md5Encode(String content) {
//選擇摘要算法
MessageDigest md = null;
try {
md = MessageDigest.getInstance("md5");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
//設置要摘要的內容:
md.update(content.getBytes());
//生成摘要
byte[] value = md.digest();
//轉16進制
String md5Value = toHexString(value);
return md5Value;
}
private String toHexString(byte[] value) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < value.length; i++) {
//消除負數 我們認爲每一個byte都是正數
int values = value[i] & 255;
if (values < 16) {
//如果值小於16 那麼使用Integer.toHexString算出來的值是0-f
//必須補0
sb.append("0");
}
sb.append(Integer.toHexString(values));
}
return sb.toString();
}
private StringBuffer getValueFromMap(Map<String, String> map) {
Iterator iter = map.entrySet().iterator();
StringBuffer buffer = new StringBuffer();
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next();
Object val = entry.getValue();
buffer.append(val + "");
}
return buffer;
}
private Map<String, RequestBody> getValueFromMap2(Map<String, String> map) {
Iterator iter = map.entrySet().iterator();
Map<String, RequestBody> requestBodyMap = new HashMap<String, RequestBody>();
Log.i("DSDSDS::", map.size() + "");
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next();
String val = (String) entry.getValue();
String key = (String) entry.getKey();
Log.i("rxjava::", key + "???" + val);
requestBodyMap.put(key, RequestBody.create(null, val));
//photos.put("password", RequestBody.create(null, "123456"));
}
return requestBodyMap;
}
private class HttpTime {
public HttpTime(int status, String msg, int result) {
this.status = status;
this.msg = msg;
this.result = result;
}
public HttpTime() {
}
@Override
public String toString() {
return "HttpTime{" +
"status=" + status +
", msg='" + msg + '\'' +
", result=" + result +
'}';
}
/**
* status : 1
* msg : 獲取成功
* result : 1482549878
*/
private int status;
private String msg;
private int result;
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public int getResult() {
return result;
}
public void setResult(int result) {
this.result = result;
}
}
}
附錄:
rxjava 正計時 與 倒計時
package utils; import android.content.Context; import com.orhanobut.logger.Logger; import java.text.SimpleDateFormat; import java.util.TimeZone; import java.util.concurrent.TimeUnit; import lessonmodule.LessonActivity; import rx.Observable; import rx.Subscription; import rx.android.schedulers.AndroidSchedulers; import rx.functions.Func1; import wytnewhttp.WytHttpUtils; /** * Created by hcy on 2017/2/24. */ public class RxUtils { //倒計時 public static Observable<String> countDownTime(int time) { if (time < 0) { time = 0; } final int countTime = time; return Observable.interval(0,1, TimeUnit.SECONDS) .observeOn(AndroidSchedulers.mainThread()) .map(new Func1<Long, String>() { @Override public String call(Long aLong) { //解決八小時的時區問題 String format = new SimpleDateFormat("HH:mm:ss").format((countTime - aLong.intValue()) * 1000- TimeZone.getDefault().getRawOffset()); Logger.i("倒計時::"+format); return format; } }) .take(countTime + 1); } //正計時 public static Observable<String> countUpTime() { final int countTime = 0; return Observable.interval(0,1, TimeUnit.SECONDS) .observeOn(AndroidSchedulers.mainThread()) .map(new Func1<Long, String>() { @Override public String call(Long aLong) { return new SimpleDateFormat("HH:mm:ss").format((countTime + aLong.intValue())*1000); } }); } public static void unsubscribe(Subscription subscription) { if (subscription != null && !subscription.isUnsubscribed()) { subscription.unsubscribe(); } } }
countTimeSubscription = RxUtils.countDownTime(60).subscribe(new Action1<String>() {
@Override
public void call(String s) {
tv_countTime.setText(s);
}
});