本文所要介绍的简易天气app主要用rxandroid、mvp、retrofit实现,首先来看看效果:
主页内容:
右侧栏天气列表:
左侧栏城市列表
首先看看activity主要代码(使用mvp模式):
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
|
//调用presenter的方法获取数据
mmainpresenter = new mainpresenterimpl( this );
mmainpresenter.getplacedata();
mmainpresenter.getweatherdata( "成都" );
//显示主页和右侧栏天气数据
public void setupweatherdata(weatherresponse weatherresponse) {
if (weatherresponse == null ) return ;
settitletext(dateutils.getweekday(weatherresponse.date));
if (weatherresponse.results != null && weatherresponse.results.size() > 0 ) {
weatherresult result = weatherresponse.results.get( 0 );
mtvcity.settext(getstring(r.string.city, result.currentcity));
mtvpm25.settext(getstring(r.string.pm25, result.pm25));
mweatherdataadapter.setdata(result.weather_data);
mweatherdataadapter.notifydatasetchanged();
mweatherextraadapter.setdata(result.index);
mweatherextraadapter.notifydatasetchanged();
}
}
//显示左侧栏城市列表
@override
public void setupplacedata(list<place> placelist) {
if (placelist == null ) {
return ;
}
mplaceadapter.setdata(placelist);
mplaceadapter.notifydatasetchanged();
}
|
接下来看看如何在presenter中应用rxjava、rxandroid获取数据
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
|
//获取天气数据
@override
public void getweatherdata(string place) {
if (textutils.isempty(place)) {
return ;
}
mmainview.showprogress();
servicemanager.getinstance().getapiservice().getweatherinfo(place, constants.baidu_ak)
.subscribeon(schedulers.io())
.observeon(androidschedulers.mainthread())
.subscribe( new subscriber<weatherresponse>() {
@override
public void oncompleted() {
log.e(tag, "oncompleted" );
mmainview.hideprogress();
}
@override
public void onerror(throwable e) {
log.e(tag, e.getmessage(), e);
mmainview.hideprogress();
}
@override
public void onnext(weatherresponse weatherresponse) {
mmainview.setupweatherdata(weatherresponse);
}
});
}
public interface apiservice {
/*@get("service/getipinfo.php")
call<getipinforesponse> getipinfo(@query("ip") string ip);*/
@get ( "service/getipinfo.php" )
observable<getipinforesponse> getipinfo( @query ( "ip" ) string ip);
//http://api.map.baidu.com/telematics/v3/weather?location=%e6%88%90%e9%83%bd&output=json&ak=mpdgj92wuyvrmyaudqs1xwcf
@get ( "/telematics/v3/weather?output=json" )
observable<weatherresponse> getweatherinfo( @query ( "location" ) string location, @query ( "ak" ) string ak);
}
|
如上所述,我们通过百度api获取天气数据使用的是retrofit框架,它能自动的返回observable对象。
那么我们如何通过rxjava获取本地文件中的城市列表呢?(为了方便演示,我将城市列表作为一个json字符串放于文件中)
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
|
@override
public void getplacedata() {
placerepository repository = new placerepository();
repository.getplacelist(baseapplication.getinstance())
.subscribeon(schedulers.io())
.observeon(androidschedulers.mainthread())
.subscribe( new subscriber<list<place>>() {
@override
public void onnext(list<place> places) {
mmainview.setupplacedata(places);
}
@override
public void oncompleted() {
}
@override
public void onerror(throwable e) {
}
});
}
public class placerepository {
public observable<list<place>> getplacelist( final context context) {
return observable.create( new observable.onsubscribe<list<place>>() {
@override
public void call(subscriber<? super list<place>> subscriber) {
try {
assetmanager assertmanager = context.getassets();
inputstream inputstream = assertmanager.open( "place" );
bytearrayoutputstream outstream = new bytearrayoutputstream();
byte [] data = new byte [ 1024 ];
int count = - 1 ;
while ((count = inputstream.read(data, 0 , 1024 )) != - 1 ) {
outstream.write(data, 0 , count);
}
string json = new string(outstream.tobytearray(), "utf-8" );
gson gson = new gsonbuilder().create();
list<place> placelist = gson.fromjson(json, new typetoken<list<place>>() {}.gettype());
subscriber.onnext(placelist);
} catch (exception e) {
subscriber.onerror(e);
}
subscriber.oncompleted();
}
});
}
}
|
通过上述代码,我们就能完成界面所示功能了,是不是省去了handler callback,new thread()这些操作了,这就为什么说rxjava是用来解决callback hell的。
”在activity中分别调用了获取天气数据和城市列表的方法,那么问题来了,如果取数据的时候显示了process dialog, 我该在什么时候结束呢,写flag判断?“
最直接的最暴力的方法就是直接在一个方法里同步调用两个接口,那使用rxjava怎么实现呢?
这个问题可以使用rxjava的merge操作符实现,故名思议就是将两个接口observable合成一个,废话不说直接上代码:
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
|
@override
public void getplaceandweatherdata(string place) {
mmainview.showprogress();
placerepository repository = new placerepository();
context context = baseapplication.getinstance();
observable placeobservable = repository.getplacelist(context);
observable weatherobservable = servicemanager.getinstance().getapiservice().getweatherinfo(place, constants.baidu_ak);
observable.merge(placeobservable, weatherobservable)
.subscribeon(schedulers.io())
.observeon(androidschedulers.mainthread())
.subscribe( new subscriber<object>() {
@override
public void oncompleted() {
mmainview.hideprogress();
}
@override
public void onerror(throwable e) {
mlogger.error(e.getmessage(), e);
mmainview.hideprogress();
}
@override
public void onnext(object obj) {
if (obj instanceof list) {
mmainview.setupplacedata((list<place>) obj);
} else if (obj instanceof weatherresponse) {
mmainview.setupweatherdata((weatherresponse) obj);
}
}
});
}
|
这样就很巧妙的解决了如果取数据的时候显示process dialog、该在什么时候结束、写flag判断的问题。
如果这样的代码看着还不舒服,你完全可以使用lambda,这样可以让代码看起来少之又少,不过android studio目前还不支持lambda,如果想要使用请安装插件retrolambda 并且jdk 使用jdk 8以上版本.
github源码地址:https://github.com/mickyliu945/commonproj