├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── gradle.xml ├── misc.xml ├── modules.xml └── runConfigurations.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── heima │ │ └── rxjavademo │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── heima │ │ │ └── rxjavademo │ │ │ ├── MainActivity.java │ │ │ ├── RxJavaUtil.java │ │ │ └── WeatherData.java │ └── res │ │ ├── layout │ │ └── activity_main.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── heima │ └── rxjavademo │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RxjavaUtil 2 | 3 | ### Rxjava快速封装实现的示例工程,包括变换的使用以及与Retrofit联用 4 | 5 | * [配套视频](https://www.boxuegu.com/web/html/video.html?courseId=172§ionId=8a2c9bed5a3a4c7e015a3add4703037f&chapterId=8a2c9bed5a3a4c7e015a3add6c480380&vId=8a2c9bed5a3a4c7e015a3adda8f30381&videoId=0208419D0BB20CAB9C33DC5901307461) 6 | 7 | * 开始在build.gradle添加依赖 8 | 9 | compile 'io.reactivex:rxjava:1.0.9' 10 | compile 'io.reactivex:rxandroid:0.24.0' 11 | compile 'com.squareup.retrofit:retrofit:1.9.0' 12 | 13 | * 需要的权限 14 | 15 | 16 | 17 | 18 | * 使用RxjavaUtil请求数据时需要和Retrofit连用,第一步就是使用Retrofit定义所有功能接口的API服务类,以天气接口为例。, 19 | 20 | > 接口地址:http://api.openweathermap.org/data/2.5/weather?q=shenzhen&mode=json&APPID=6c113432fd84a6e28268af291821db16 21 | 22 | * 参数声明,Url都通过Annotation指定,接口定义如下: 23 | 24 | private interface AppApi { 25 | @GET("/weather") 26 | WeatherData getWeather(@Query("q") String city, @Query("mode") String mode, @Query("APPID") String APPID); 27 | } 28 | 29 | * 返回数据如下,可以使用GsonFormat自动生成javabean(即WeatherData): 30 | 31 | 32 | 33 | {"coord":{"lon":114.07,"lat":22.55},"weather":[{"id":800,"main":"Clear","description":"clear sky","icon":"01n"}],"base":"stations","main":{"temp":293.15,"pressure":1018,"humidity":72,"temp_min":293.15,"temp_max":293.15},"visibility":10000,"wind":{"speed":3.69,"deg":116.004},"clouds":{"all":0},"dt":1483538400,"sys":{"type":1,"id":7420,"message":0.0134,"country":"CN","sunrise":1483484686,"sunset":1483523588},"id":1795565,"name":"Shenzhen","cod":200} 34 | 35 | * 第二步是通过RestAdapter生成API接口服务的实现类(动态代理) 36 | 37 | 38 | 39 | private static final RestAdapter restAdapter = new RestAdapter.Builder().setEndpoint(ENDPOINT).setLogLevel(RestAdapter.LogLevel.FULL).build(); 40 | private static final AppApi appService = restAdapter.create(AppApi.class); 41 | 42 | * 第三步是关键的一步,将返回的数据类型包装到一个数据源(Observable)中。 43 | onNext是RxJava发送事件,即开始请求数据,onCompleted为结束任务的事件,subscribeOn为指定获取数据的线程为耗时线程。 44 | 45 | 46 | 47 | public static Observable getWeatherData(final String city) { 48 | return Observable.create(new Observable.OnSubscribe() { 49 | @Override 50 | public void call(Subscriber subscriber) { 51 | subscriber.onNext(appService.getWeather(city,"json", "6c113432fd84a6e28268af291821db16")); 52 | subscriber.onCompleted(); 53 | } 54 | }).subscribeOn(Schedulers.io()); 55 | } 56 | 57 | * 最后调用封装好的方法就可以了,拿到数据后,在主线程中回调(subscribeOn(Schedulers.io()),获取单个天气示例如下: 58 | 59 | RxJavaUtil.getWeatherData(cityName).subscribeOn(Schedulers.io()) 60 | .observeOn(AndroidSchedulers.mainThread()) 61 | .subscribe(new Action1() { 62 | @Override 63 | public void call(WeatherData weatherData) { 64 | Log.d(LOG_TAG, weatherData.toString()); 65 | switch (cityName){ 66 | case "beijing": 67 | mTv1.setText(weatherData.toString()); 68 | break; 69 | case "shenzhen": 70 | mTv2.setText(weatherData.toString()); 71 | break; 72 | case "shanghai": 73 | mTv3.setText(weatherData.toString()); 74 | break; 75 | } 76 | } 77 | }, new Action1() { 78 | @Override 79 | public void call(Throwable throwable) { 80 | Log.e(LOG_TAG, throwable.getMessage(), throwable); 81 | } 82 | }); 83 | 84 | * 当获取多个天气时候,要使用到Rxjava的变换,简单点理解,就是一个数据源变成多个数据源,一对多的映射关系。 85 | 86 | Observable.from(cities).flatMap(new Func1>() { 87 | @Override 88 | public Observable call(String city) { 89 | return RxJavaUtil.getWeatherData(city); 90 | } 91 | }).subscribeOn(Schedulers.io()) 92 | .observeOn(AndroidSchedulers.mainThread()) 93 | .subscribe(/*onNext*/new Action1() { 94 | @Override 95 | public void call(WeatherData weatherData) { 96 | String cityName = weatherData.name.toLowerCase(); 97 | switch (cityName){ 98 | case "beijing": 99 | mTv1.setText(weatherData.toString()); 100 | break; 101 | case "shenzhen": 102 | mTv2.setText(weatherData.toString()); 103 | break; 104 | case "shanghai": 105 | mTv3.setText(weatherData.toString()); 106 | break; 107 | } 108 | } 109 | }, /*onError*/new Action1() { 110 | @Override 111 | public void call(Throwable throwable) { 112 | 113 | } 114 | });} 115 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 24 5 | buildToolsVersion "25.0.1" 6 | defaultConfig { 7 | applicationId "com.heima.rxjavademo" 8 | minSdkVersion 15 9 | targetSdkVersion 24 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 25 | exclude group: 'com.android.support', module: 'support-annotations' 26 | }) 27 | compile 'com.android.support:appcompat-v7:24.2.1' 28 | testCompile 'junit:junit:4.12' 29 | 30 | compile 'io.reactivex:rxjava:1.0.9' 31 | compile 'io.reactivex:rxandroid:0.24.0' 32 | compile 'com.squareup.retrofit:retrofit:1.9.0' 33 | } 34 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:\Android\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/heima/rxjavademo/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.heima.rxjavademo; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.heima.rxjavademo", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/heima/rxjavademo/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.heima.rxjavademo; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.app.AppCompatActivity; 5 | import android.util.Log; 6 | import android.view.View; 7 | import android.widget.Button; 8 | import android.widget.TextView; 9 | 10 | import rx.Observable; 11 | import rx.android.schedulers.AndroidSchedulers; 12 | import rx.functions.Action1; 13 | import rx.functions.Func1; 14 | import rx.schedulers.Schedulers; 15 | 16 | public class MainActivity extends AppCompatActivity implements View.OnClickListener { 17 | 18 | private static final String LOG_TAG = "MainActivity"; 19 | private String[] cities = new String[]{"beijing", "shenzhen", "shanghai"}; 20 | private TextView mTv1; 21 | private TextView mTv2; 22 | private TextView mTv3; 23 | private Button mMBtn; 24 | private Button mBtn; 25 | 26 | @Override 27 | protected void onCreate(Bundle savedInstanceState) { 28 | super.onCreate(savedInstanceState); 29 | setContentView(R.layout.activity_main); 30 | 31 | mTv1 = (TextView) findViewById(R.id.text); 32 | mTv2 = (TextView) findViewById(R.id.text2); 33 | mTv3 = (TextView) findViewById(R.id.text3); 34 | mTv1.setOnClickListener(this); 35 | mTv2.setOnClickListener(this); 36 | mTv3.setOnClickListener(this); 37 | 38 | mBtn = (Button) findViewById(R.id.btn); 39 | mBtn.setOnClickListener(this); 40 | } 41 | 42 | @Override 43 | public void onClick(View v) { 44 | switch (v.getId()){ 45 | case R.id.text: 46 | getCityWeather(cities[0]); 47 | break; 48 | case R.id.text2: 49 | getCityWeather(cities[1]); 50 | break; 51 | case R.id.text3: 52 | getCityWeather(cities[2]); 53 | break; 54 | case R.id.btn: 55 | getAllWeather(); 56 | break; 57 | } 58 | } 59 | 60 | private void getAllWeather() { 61 | /** 62 | * 多个 city 请求 63 | * map,flatMap 对 Observable进行变换 64 | */ 65 | Observable.from(cities).flatMap(new Func1>() { 66 | @Override 67 | public Observable call(String city) { 68 | return RxJavaUtil.getWeatherData(city); 69 | } 70 | }).subscribeOn(Schedulers.io()) 71 | .observeOn(AndroidSchedulers.mainThread()) 72 | .subscribe(/*onNext*/new Action1() { 73 | @Override 74 | public void call(WeatherData weatherData) { 75 | String cityName = weatherData.name.toLowerCase(); 76 | switch (cityName){ 77 | case "beijing": 78 | mTv1.setText(weatherData.toString()); 79 | break; 80 | case "shenzhen": 81 | mTv2.setText(weatherData.toString()); 82 | break; 83 | case "shanghai": 84 | mTv3.setText(weatherData.toString()); 85 | break; 86 | } 87 | } 88 | }, /*onError*/new Action1() { 89 | @Override 90 | public void call(Throwable throwable) { 91 | 92 | } 93 | }); 94 | } 95 | 96 | // /** 97 | // * 单个 city 请求 98 | // */ 99 | public void getCityWeather(final String cityName){ 100 | RxJavaUtil.getWeatherData(cityName).subscribeOn(Schedulers.io()) 101 | .observeOn(AndroidSchedulers.mainThread()) 102 | .subscribe(new Action1() { 103 | @Override 104 | public void call(WeatherData weatherData) { 105 | Log.d(LOG_TAG, weatherData.toString()); 106 | switch (cityName){ 107 | case "beijing": 108 | mTv1.setText(weatherData.toString()); 109 | break; 110 | case "shenzhen": 111 | mTv2.setText(weatherData.toString()); 112 | break; 113 | case "shanghai": 114 | mTv3.setText(weatherData.toString()); 115 | break; 116 | } 117 | } 118 | }, new Action1() { 119 | @Override 120 | public void call(Throwable throwable) { 121 | Log.e(LOG_TAG, throwable.getMessage(), throwable); 122 | } 123 | }); 124 | } 125 | 126 | 127 | } 128 | -------------------------------------------------------------------------------- /app/src/main/java/com/heima/rxjavademo/RxJavaUtil.java: -------------------------------------------------------------------------------- 1 | package com.heima.rxjavademo; 2 | 3 | import retrofit.RestAdapter; 4 | import retrofit.http.GET; 5 | import retrofit.http.Query; 6 | import rx.Observable; 7 | import rx.Subscriber; 8 | import rx.schedulers.Schedulers; 9 | 10 | 11 | public class RxJavaUtil { 12 | 13 | private static final String ENDPOINT = "http://api.openweathermap.org/data/2.5"; 14 | //http://api.openweathermap.org/data/2.5/weather?q=shenzhen&mode=json&APPID=6c113432fd84a6e28268af291821db16 15 | private interface AppApi { 16 | @GET("/weather") 17 | WeatherData getWeather(@Query("q") String city, @Query("mode") String mode, @Query("APPID") String APPID); 18 | } 19 | 20 | private static final RestAdapter restAdapter = new RestAdapter.Builder().setEndpoint(ENDPOINT).setLogLevel(RestAdapter.LogLevel.FULL).build(); 21 | private static final AppApi appService = restAdapter.create(AppApi.class); 22 | 23 | /** 24 | * 将服务接口返回的数据,封装成{@link rx.Observable} 25 | * @param city 26 | * @return 27 | */ 28 | public static Observable getWeatherData(final String city) { 29 | return Observable.create(new Observable.OnSubscribe() { 30 | @Override 31 | public void call(Subscriber subscriber) { 32 | subscriber.onNext(appService.getWeather(city,"json", "6c113432fd84a6e28268af291821db16")); 33 | subscriber.onCompleted(); 34 | } 35 | }).subscribeOn(Schedulers.io()); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/com/heima/rxjavademo/WeatherData.java: -------------------------------------------------------------------------------- 1 | package com.heima.rxjavademo; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * 天气数据javabean 7 | */ 8 | 9 | public class WeatherData { 10 | 11 | /** 12 | * coord : {"lon":114.07,"lat":22.55} 13 | * weather : [{"id":800,"main":"Clear","description":"clear sky","icon":"01n"}] 14 | * base : stations 15 | * main : {"temp":293.15,"pressure":1018,"humidity":72,"temp_min":293.15,"temp_max":293.15} 16 | * visibility : 10000 17 | * wind : {"speed":3.69,"deg":116.004} 18 | * clouds : {"all":0} 19 | * dt : 1483538400 20 | * sys : {"type":1,"id":7420,"message":0.0134,"country":"CN","sunrise":1483484686,"sunset":1483523588} 21 | * id : 1795565 22 | * name : Shenzhen 23 | * cod : 200 24 | */ 25 | 26 | public CoordBean coord; 27 | public String base; 28 | public MainBean main; 29 | public int visibility; 30 | public WindBean wind; 31 | public CloudsBean clouds; 32 | public int dt; 33 | public SysBean sys; 34 | public int id; 35 | public String name; 36 | public int cod; 37 | public List weather; 38 | 39 | public static class CoordBean { 40 | /** 41 | * lon : 114.07 42 | * lat : 22.55 43 | */ 44 | 45 | public double lon; 46 | public double lat; 47 | 48 | @Override 49 | public String toString() { 50 | return "CoordBean{" + 51 | "lon=" + lon + 52 | ", lat=" + lat + 53 | '}'; 54 | } 55 | } 56 | 57 | public static class MainBean { 58 | /** 59 | * temp : 293.15 60 | * pressure : 1018 61 | * humidity : 72 62 | * temp_min : 293.15 63 | * temp_max : 293.15 64 | */ 65 | 66 | public double temp; 67 | public int pressure; 68 | public int humidity; 69 | public double temp_min; 70 | public double temp_max; 71 | 72 | @Override 73 | public String toString() { 74 | return "MainBean{" + 75 | "temp=" + temp + 76 | ", pressure=" + pressure + 77 | ", humidity=" + humidity + 78 | ", temp_min=" + temp_min + 79 | ", temp_max=" + temp_max + 80 | '}'; 81 | } 82 | } 83 | 84 | public static class WindBean { 85 | /** 86 | * speed : 3.69 87 | * deg : 116.004 88 | */ 89 | 90 | public double speed; 91 | public double deg; 92 | 93 | @Override 94 | public String toString() { 95 | return "WindBean{" + 96 | "speed=" + speed + 97 | ", deg=" + deg + 98 | '}'; 99 | } 100 | } 101 | 102 | public static class CloudsBean { 103 | /** 104 | * all : 0 105 | */ 106 | 107 | public int all; 108 | 109 | @Override 110 | public String toString() { 111 | return "CloudsBean{" + 112 | "all=" + all + 113 | '}'; 114 | } 115 | } 116 | 117 | public static class SysBean { 118 | /** 119 | * type : 1 120 | * id : 7420 121 | * message : 0.0134 122 | * country : CN 123 | * sunrise : 1483484686 124 | * sunset : 1483523588 125 | */ 126 | 127 | public int type; 128 | public int id; 129 | public double message; 130 | public String country; 131 | public int sunrise; 132 | public int sunset; 133 | 134 | @Override 135 | public String toString() { 136 | return "SysBean{" + 137 | "type=" + type + 138 | ", id=" + id + 139 | ", message=" + message + 140 | ", country='" + country + '\'' + 141 | ", sunrise=" + sunrise + 142 | ", sunset=" + sunset + 143 | '}'; 144 | } 145 | } 146 | 147 | public static class WeatherBean { 148 | /** 149 | * id : 800 150 | * main : Clear 151 | * description : clear sky 152 | * icon : 01n 153 | */ 154 | 155 | public int id; 156 | public String main; 157 | public String description; 158 | public String icon; 159 | 160 | @Override 161 | public String toString() { 162 | return "WeatherBean{" + 163 | "id=" + id + 164 | ", main='" + main + '\'' + 165 | ", description='" + description + '\'' + 166 | ", icon='" + icon + '\'' + 167 | '}'; 168 | } 169 | } 170 | 171 | @Override 172 | public String toString() { 173 | return "WeatherData{" + 174 | "coord=" + coord + 175 | ", base='" + base + '\'' + 176 | ", main=" + main + 177 | ", visibility=" + visibility + 178 | ", wind=" + wind + 179 | ", clouds=" + clouds + 180 | ", dt=" + dt + 181 | ", sys=" + sys + 182 | ", id=" + id + 183 | ", name='" + name + '\'' + 184 | ", cod=" + cod + 185 | ", weather=" + weather + 186 | '}'; 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 17 | 18 |