android 积累一些关于rxjava的知识点
2016-12-23 13:50
881 查看
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+"???"); } });当然被观察者还可以使用固定的方法来“发送数据给观察者”just(传入要发送的数据序列并用逗号隔开);
/** * 此方法默认在执行结束加上onCompleted(); */ Observable<String> observable = Observable.just("hasaki","mianduijifengba");from(可传入对象数组);
String[] requestArray={"hasaki","mianduijifengba"}; /** * 此方法默认在执行结束加上onCompleted(); */ Observable<String> observable = Observable.from(requestArray);订阅:“被观察者去订阅观察者”:原因是:流式API设计(什么鬼?)
//订阅 observable.subscribe(subscriber);
取消订阅:(对于异步请求结束后,要解除引用关系,避免内存泄漏)一般订阅之后都会产生一个Subscription对象
//订阅 Subscription subscribe = observable.subscribe(subscriber); if(subscribe.isUnsubscribed()){ //判断是否解除订阅 Log.i("rxjava","没有解除订阅"); subscribe.unsubscribe();//解除订阅 }else{ Log.i("rxjava","解除订阅"); }初级进阶(线程控制)因为被观察者是"事件的产生者",而观察者是"事件的消费者",通常在网络请求中,被观察者里开启子线程做网络请求,观察者里要在UI线程中跟新UI,主要运用到两个方法:
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>>() {@Overridepublic Observable<Card> call(Person person) {Log.i("rxjava::", person.getName());return Observable.from(person.getCards());}}).subscribe(new Subscriber<Card>() {@Overridepublic void onCompleted() {}@Overridepublic void onError(Throwable e) {}@Overridepublic void onNext(Card card) {Log.i("rxjava::", card.toString());}});
flatMap:对象转新的事件序列,注意func1返回值的变换,他返回的是一个被观察者对象,然后又拿着这个对象去
请求新的序列。
这里的应用环境究竟是什么样的呢,假设你要读取列表中的某个key,然后拿着这key读取新的列表
会用到吧?我也没用过啊,我是边看别人的博客,写下自己的理解。
我的理解:将一堆事件序列转成一个Observerble再统一发出去
flatMap的交叉问题:假设现有一个数组person[3]{校长,老师,学生},经过flatMap要求得到每个人身上的钱,
也许取的第一个对象是校长,第二个是老师,也许取的第一个对象是校长,第二个对象是学生。也就是说只
保证铺平序列,不能保证发送序列的顺序。
问题:我写的例子里,都是正常发送的顺序未发现错乱,也许是数据源基数太小。
3.contatMap(转换类操作符)
作用类似于flatMap但不会产生交叉问题,也就是正常按发送顺序发送User[] users=new User[]{new User("张三","22"),new User("李四","23"),new User("老王","24")};Observable.from(users).concatMap(new Func1<User, Observable<String>>() {@Overridepublic Observable<String> call(User user) {return Observable.just(user.getFirstName());}}).subscribe(new Action1<String>() {@Overridepublic void call(String s) {Log.i("YYYYTTT::",s);}});4.scan(转换类操作符)
Observable.just(1, 2, 3, 4, 5).scan(new Func2<Integer, Integer, Integer>() {@Overridepublic Integer call(Integer integer, Integer integer2) {Log.i("YYYYTTT????", integer+"/"+integer2);return integer + integer2;}}).subscribe(new Action1<Integer>() {@Overridepublic 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>() {@Overridepublic Boolean call(User user) {if (user.getFirstName().equals("张三")){return false;//过滤掉}else{return true;//留着}}}).subscribe(new Action1<User>() {@Overridepublic void call(User user) {Log.i("GGGDDD::",user.toString());}});6.take(过滤操作符)//找出数据序列前三个数据
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>() {@Overridepublic void call(User user) {Log.i("GGGDDD::",user.toString());}});//找出第一项数据 first == take(1)
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>() {@Overridepublic 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>() {@Overridepublic 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>() {@Overridepublic Boolean call(User user) {if (user.getFirstName().equals("大锤")){return true;//读到此处不再读取}else{return false;}}}).subscribe(new Action1<User>() {@Overridepublic 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>() {@Overridepublic 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>() {@Overridepublic 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>() {@Overridepublic void call(User user) {Log.i("GGGDDD::",user.toString());}});9.distinct(过滤操作符)过滤掉重复的元素
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>() {@Overridepublic 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>() {@Overridepublic String call(User user) {return user.getFirstName();//过滤掉重名}}).subscribe(new Action1<User>() {@Overridepublic void call(User user) {Log.i("GGGDDD::",user.toString());}});10.last last == takeLast(1)最后一项
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>() {@Overridepublic 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>() {@Overridepublic void onCompleted() {}@Overridepublic void onError(Throwable e) {}@Overridepublic void onNext(Object o) {Log.i("TTGGG:::",o.toString());}});???说好无序的呢?难道测试数据过小?12.startWith(组合操作符)发射数据之前插入一条相同类型的新数据或者相同类型的新发射序列
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>() {@Overridepublic void call(User user) {Log.i("TTTDDDD::",user.toString());}});13.concat(组合操作符)多个发射序列,逐个序列数据发出,接收的数据一定是顺序的
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>() {@Overridepublic void call(Object o) {Log.i("TTGGGD:",o.toString());}});14.zip(组合操作符)1+1组合,
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>() {@Overridepublic String call(User user, Integer integer) {return user.getFirstName()+integer;}}).subscribe(new Action1<String>() {@Overridepublic void call(String s) {Log.i("TGGDD::",s);}});15.combineLatest(组合操作符)第一个发射序列的最后一个元素与第二个发射序列的所有元素组合
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>() {@Overridepublic String call(User user, Integer integer) {return user.getFirstName()+integer;}}).subscribe(new Action1<String>() {@Overridepublic 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>() {@Overridepublic void onCompleted() {Log.i("网络请求的数据::", "onCompleted");}@Overridepublic void onError(Throwable e) {Log.i("网络请求的数据::", "onError" + e.getMessage());}@Overridepublic void onNext(String s) {Log.i("网络请求的数据::", s);tv.setText(s);}});}public interface HttpUser {@POST("/api/index/posttest")@FormUrlEncodedObservable<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()@Overridepublic void call(String s) {Log.i("onNext:::",s);}};Action1<Throwable> onErrorAction = new Action1<Throwable>() {// onError()@Overridepublic void call(Throwable throwable) {Log.i("onError:::",throwable.getMessage());}};Action0 onCompletedAction = new Action0() {// onCompleted()@Overridepublic 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@MultipartObservable<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>>() {@Overridepublic 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>() {@Overridepublic void onCompleted() {Log.i("rxjava::onCompleted:", "onCompleted");}@Overridepublic void onError(Throwable e) {Log.i("rxjava::onError:", e.getMessage());}@Overridepublic 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//必须补0sb.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() {}@Overridepublic 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>() {@Overridepublic 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>() {@Overridepublic 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>() {@Overridepublic void call(String s) {tv_countTime.setText(s);}});
相关文章推荐
- 百度地图路径规划时找不到DrivingRouteOverlay(overlayutil工具包)
- Android 简单的自定义dialog
- AndroidStudio之如何生成aar包
- android获取MP3文件的歌曲信息
- android 实现关机
- Android中的View
- Android 离线语音(讯飞语音)封装工具类
- Android NDK 编译出现 string:No such file or directory
- 关于Android中使用SVG特性的探索与总结
- Bmob后端云短信验证最新版Android studio集成登录演示
- Android四种点击事件和五中存储方式
- Android EditText 让编辑框只能输入汉字
- 自定义Log日志
- Android应用开发之图片(Bitmap)压缩(三)---------采样率压缩
- 隐式Intent 使用的之一
- Couldn't load XXX indLibrary returned null
- Android 真机调试
- Android bitmap 释放 解决Error create Hprof file问题
- QGIS 的安卓应用
- Android自定义View之常用工具源码分析