├── .gitignore ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── assets │ ├── four │ │ ├── 00.jpg │ │ ├── 132.jpg │ │ └── guangtouge04.png │ ├── one │ │ ├── 00.jpg │ │ └── guangtouge01.png │ ├── three │ │ ├── 132.jpg │ │ └── guangtouge03.png │ └── two │ │ ├── 40.jpg │ │ └── guangtouge02.png │ ├── java │ └── com │ │ └── malin │ │ └── rxjava │ │ ├── activity │ │ └── MainActivity.java │ │ ├── application │ │ └── RxJavaApplication.java │ │ ├── constant │ │ └── Constant.java │ │ ├── factory │ │ ├── DataFactory.java │ │ └── ImageNameFactory.java │ │ ├── githubapi │ │ └── GitHubApi.java │ │ ├── model │ │ ├── Contributor.java │ │ ├── Course.java │ │ ├── Student.java │ │ └── User.java │ │ ├── service │ │ └── RetrofitService.java │ │ └── utils │ │ ├── ClickUtils.java │ │ ├── DeviceInfo.java │ │ ├── ImageUtils.java │ │ ├── RecycleBitmap.java │ │ ├── RxUtils.java │ │ └── ToastUtil.java │ └── res │ ├── layout │ ├── activity_main.xml │ └── item_log.xml │ ├── mipmap-xhdpi │ └── malin.jpg │ ├── values-w820dp │ └── dimens.xml │ ├── values-zh │ └── strings.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── qrcode └── dowload_qrcode.png └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /products 3 | .gradle 4 | /.idea/workspace.xml 5 | .idea 6 | /.idea/ 7 | /local.properties 8 | *.iml 9 | /modules 10 | .settings.gradle 11 | 12 | 13 | # built application files 14 | *.ap_ 15 | 16 | # files for the dex VM 17 | *.dex 18 | # Java class files 19 | *.class 20 | 21 | # generated files 22 | bin/ 23 | gen/ 24 | *target/ 25 | *build/ 26 | .gradle/ 27 | .idea/ 28 | RengwuxianRxjava.iml 29 | gradle.properties 30 | /gradle.properties 31 | gen-external-apklibs/ 32 | 33 | # Eclipse project files 34 | .classpath 35 | .project 36 | 37 | # Mac os 38 | .DS_Store 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 malin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## RxJava 2 | RxJava之扔物线[给Android开发者的RxJava详解](http://gank.io/post/560e15be2dca930e00da1083)文章中的例子 3 | 4 | ### Build 5 | 6 | To build: 7 | >$ git clone https://github.com/androidmalin/RengwuxianRxjava.git
8 | >$ cd RengwuxianRxjava/
9 | >$ gradle clean --stacktrace(./gradlew clean --stacktrace )
10 | 11 | 12 | ### Bugs and Feedback 13 | 14 | For bugs, questions and discussions please use the [Github Issues](https://github.com/androidmalin/RengwuxianRxjava/issues). 15 | 16 | 17 | ### 项目依赖 18 | 19 | 项目名称 | 项目信息 20 | ------- | ------- 21 | [android.support.*](https://developer.android.com/tools/support-library/index.html) | Android Support Library 22 | [RxJava](https://github.com/ReactiveX/RxJava) | 一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库 23 | [RxAndroid](https://github.com/ReactiveX/RxAndroid) | RxAndroid 是 RxJava 的一个针对 Android 平台的扩展 24 | [RxBinding](https://github.com/JakeWharton/RxBinding) | JakeWharton Android函数式相应编程(FRP)框架 25 | [logger](https://github.com/orhanobut/logger) | 一个简洁,优雅,功能强大的Android日志输出工具 26 | 27 | 28 | ### 参考的文章 29 | 作者 | 文章| 参考的地方 30 | ------- | -------| ------- 31 | [扔物线](https://github.com/rengwuxian) | [给Android开发者的RxJava详解](http://gank.io/post/560e15be2dca930e00da1083) | 示例代码 32 | [胡凯](https://github.com/kesenhoo) | [ 高效加载大图](http://hukai.me/android-training-course-in-chinese/graphics/displaying-bitmaps/load-bitmap.html) | Bitmap压缩算法 33 | [intbird](http://blog.csdn.net/intbird) | [Android OOM ,回收布局文件中ImageView占用的内存.Bitmap OOM回收解决.](http://blog.csdn.net/intbird/article/details/19905549) | Bitmap回收 34 | [任玉刚](https://github.com/singwhatiwanna)|[Android开发艺术探索](https://item.jd.com/11760209.html) | BitmapFactory解析的配置 35 | [徐宜生](https://github.com/xuyisheng)|[Android群英传](https://item.jd.com/11758334.html)| Canvas的使用 36 | [shwenzhang](https://github.com/shwenzhang)|[Android内存优化杂谈](http://mp.weixin.qq.com/s?__biz=MzAwNDY1ODY2OQ==&mid=400656149&idx=1&sn=122b4f4965fafebf78ec0b4fce2ef62a&3rd=MzA3MDU4NTYzMw==&scene=6#rd)| 内存优化 37 | 38 | 39 | ### About me 40 | 41 | [我的CSDN博客](http://blog.csdn.net/androidmalin):[http://blog.csdn.net/androidmalin](http://blog.csdn.net/androidmalin)
42 | [我的微博](http://weibo.com/androidmalin):[http://weibo.com/androidmalin](http://weibo.com/androidmalin)
43 | 44 | 45 | ### License 46 |
47 | The MIT License (MIT)
48 | 
49 | Copyright (c) 2015 malin
50 | 
51 | Permission is hereby granted, free of charge, to any person obtaining a copy
52 | of this software and associated documentation files (the "Software"), to deal
53 | in the Software without restriction, including without limitation the rights
54 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
55 | copies of the Software, and to permit persons to whom the Software is
56 | furnished to do so, subject to the following conditions:
57 | 
58 | The above copyright notice and this permission notice shall be included in all
59 | copies or substantial portions of the Software.
60 | 
61 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
62 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
63 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
64 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
65 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
66 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
67 | SOFTWARE.
68 | 
69 | 
-------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /app.iml -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | android { 3 | compileSdkVersion 23 4 | buildToolsVersion '23.0.3' 5 | 6 | 7 | defaultConfig { 8 | applicationId "com.malin.rengwuxianrxjava" 9 | minSdkVersion 16 10 | targetSdkVersion 23 11 | versionCode 16 12 | versionName "1.16" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | 21 | lintOptions { 22 | abortOnError false 23 | } 24 | 25 | compileOptions { 26 | sourceCompatibility JavaVersion.VERSION_1_7 27 | targetCompatibility JavaVersion.VERSION_1_7 28 | } 29 | } 30 | 31 | //add for logger 32 | repositories { 33 | jcenter() 34 | maven { url "https://jitpack.io" } 35 | mavenCentral() 36 | } 37 | dependencies { 38 | 39 | compile 'com.android.support:design:23.4.0' 40 | compile 'com.android.support:appcompat-v7:23.4.0' 41 | compile 'com.github.orhanobut:logger:1.12' 42 | compile 'com.jakewharton.rxbinding:rxbinding:0.3.0' 43 | compile 'com.squareup.retrofit2:retrofit:2.0.2' 44 | compile 'com.squareup.retrofit2:retrofit:2.0.2' 45 | compile 'com.squareup.retrofit2:converter-gson:2.0.2' 46 | compile 'com.squareup.retrofit2:adapter-rxjava:2.0.2' 47 | compile 'io.reactivex:rxandroid:1.1.0' 48 | 49 | } 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /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 /home/malin/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/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/assets/four/00.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidmalin/RxjavaSample/3a13759b2db1105024b94be75ad81906a00b59c8/app/src/main/assets/four/00.jpg -------------------------------------------------------------------------------- /app/src/main/assets/four/132.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidmalin/RxjavaSample/3a13759b2db1105024b94be75ad81906a00b59c8/app/src/main/assets/four/132.jpg -------------------------------------------------------------------------------- /app/src/main/assets/four/guangtouge04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidmalin/RxjavaSample/3a13759b2db1105024b94be75ad81906a00b59c8/app/src/main/assets/four/guangtouge04.png -------------------------------------------------------------------------------- /app/src/main/assets/one/00.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidmalin/RxjavaSample/3a13759b2db1105024b94be75ad81906a00b59c8/app/src/main/assets/one/00.jpg -------------------------------------------------------------------------------- /app/src/main/assets/one/guangtouge01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidmalin/RxjavaSample/3a13759b2db1105024b94be75ad81906a00b59c8/app/src/main/assets/one/guangtouge01.png -------------------------------------------------------------------------------- /app/src/main/assets/three/132.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidmalin/RxjavaSample/3a13759b2db1105024b94be75ad81906a00b59c8/app/src/main/assets/three/132.jpg -------------------------------------------------------------------------------- /app/src/main/assets/three/guangtouge03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidmalin/RxjavaSample/3a13759b2db1105024b94be75ad81906a00b59c8/app/src/main/assets/three/guangtouge03.png -------------------------------------------------------------------------------- /app/src/main/assets/two/40.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidmalin/RxjavaSample/3a13759b2db1105024b94be75ad81906a00b59c8/app/src/main/assets/two/40.jpg -------------------------------------------------------------------------------- /app/src/main/assets/two/guangtouge02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidmalin/RxjavaSample/3a13759b2db1105024b94be75ad81906a00b59c8/app/src/main/assets/two/guangtouge02.png -------------------------------------------------------------------------------- /app/src/main/java/com/malin/rxjava/activity/MainActivity.java: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * The MIT License (MIT) 4 | * 5 | * Copyright (c) 2015 malin 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | 26 | package com.malin.rxjava.activity; 27 | 28 | import android.content.Context; 29 | import android.graphics.Bitmap; 30 | import android.graphics.Canvas; 31 | import android.graphics.Paint; 32 | import android.graphics.PorterDuff; 33 | import android.graphics.PorterDuffXfermode; 34 | import android.graphics.drawable.Drawable; 35 | import android.os.Bundle; 36 | import android.support.v4.content.ContextCompat; 37 | import android.support.v7.app.AppCompatActivity; 38 | import android.text.TextUtils; 39 | import android.util.Log; 40 | import android.view.View; 41 | import android.view.ViewGroup; 42 | import android.widget.AdapterView; 43 | import android.widget.ArrayAdapter; 44 | import android.widget.EditText; 45 | import android.widget.ImageView; 46 | import android.widget.ListView; 47 | import android.widget.ProgressBar; 48 | import android.widget.TextView; 49 | import android.widget.Toast; 50 | 51 | import com.jakewharton.rxbinding.view.RxView; 52 | import com.jakewharton.rxbinding.widget.RxTextView; 53 | import com.jakewharton.rxbinding.widget.TextViewTextChangeEvent; 54 | import com.malin.rxjava.R; 55 | import com.malin.rxjava.application.RxJavaApplication; 56 | import com.malin.rxjava.constant.Constant; 57 | import com.malin.rxjava.factory.DataFactory; 58 | import com.malin.rxjava.factory.ImageNameFactory; 59 | import com.malin.rxjava.githubapi.GitHubApi; 60 | import com.malin.rxjava.model.Contributor; 61 | import com.malin.rxjava.model.Course; 62 | import com.malin.rxjava.model.Student; 63 | import com.malin.rxjava.model.User; 64 | import com.malin.rxjava.service.RetrofitService; 65 | import com.malin.rxjava.utils.ClickUtils; 66 | import com.malin.rxjava.utils.DeviceInfo; 67 | import com.malin.rxjava.utils.ImageUtils; 68 | import com.malin.rxjava.utils.RecycleBitmap; 69 | import com.malin.rxjava.utils.RxUtils; 70 | import com.malin.rxjava.utils.ToastUtil; 71 | import com.orhanobut.logger.LogLevel; 72 | import com.orhanobut.logger.Logger; 73 | 74 | import java.io.IOException; 75 | import java.text.SimpleDateFormat; 76 | import java.util.ArrayList; 77 | import java.util.Date; 78 | import java.util.List; 79 | import java.util.Locale; 80 | import java.util.concurrent.TimeUnit; 81 | 82 | import okhttp3.ResponseBody; 83 | import retrofit2.Call; 84 | import retrofit2.Callback; 85 | import retrofit2.Response; 86 | import rx.Observable; 87 | import rx.Observer; 88 | import rx.Subscriber; 89 | import rx.android.schedulers.AndroidSchedulers; 90 | import rx.functions.Action0; 91 | import rx.functions.Action1; 92 | import rx.functions.Func1; 93 | import rx.schedulers.Schedulers; 94 | import rx.subscriptions.CompositeSubscription; 95 | 96 | 97 | /** 98 | * 类描述:活动主页面 99 | * 创建人:malin.myemail@gmail.com 100 | * 创建时间:15-11-10. 101 | * 备注: 102 | */ 103 | public class MainActivity extends AppCompatActivity { 104 | private static final String TAG = "MainActivity"; 105 | private static final String TAG_FOR_LOGGER = "MainActivity_I_LOVE_RXJAVA"; 106 | private static final String ERROR = "故意让程序出错"; 107 | private static final String JPG = ".jpg"; 108 | private int mCounter;//循环的计数器 109 | private ImageView mImageView; 110 | private Bitmap mManyBitmapSuperposition = null; 111 | private Canvas mCanvas = null; 112 | private ProgressBar mProgressBar; 113 | private EditText mSearchEditText; 114 | private TextView mResultTextView; 115 | private Context mContext; 116 | 117 | @Override 118 | protected void onCreate(Bundle savedInstanceState) { 119 | super.onCreate(savedInstanceState); 120 | setContentView(R.layout.activity_main); 121 | initializeLogAndDeviceInfo(); 122 | initView(); 123 | initData(); 124 | testFuncation(9);//RxJava基础概念的练习 125 | } 126 | 127 | /** 128 | * 初始化Logger日志输出配置和获取手机尺寸信息 129 | */ 130 | private void initializeLogAndDeviceInfo() { 131 | Logger.init(TAG_FOR_LOGGER).logLevel(LogLevel.FULL);//Use LogLevel.NONE for the release versions. 132 | DeviceInfo.getInstance().initializeScreenInfo(this); 133 | } 134 | 135 | /** 136 | * 用于显示图片的初始化 137 | */ 138 | private void initView() { 139 | mContext = this; 140 | mImageView = (ImageView) findViewById(R.id.iv_image); 141 | mResultTextView = (TextView) findViewById(R.id.tv_result); 142 | mSearchEditText = (EditText) findViewById(R.id.ed_search); 143 | mProgressBar = (ProgressBar) findViewById(R.id.progressbar); 144 | } 145 | 146 | private void initData() { 147 | mContext = this; 148 | } 149 | 150 | /** 151 | * 故意让程序出现异常,可以用来测试 152 | */ 153 | private void getException() { 154 | int errorCode = Integer.valueOf(ERROR); 155 | } 156 | 157 | //-----------------------------------------------0:RxJava基础练习----------------------------------------------------------- 158 | //概念解释 159 | //1:被观察者,事件源:它决定什么时候触发事件以及触发怎样的事件 160 | //2:观察者:它决定事件触发的时候将有怎样的行为 161 | //3:订阅 162 | private void method0() { 163 | 164 | //1:被观察者,事件源 165 | //概念解释:RxJava 使用 Observable.create() 方法来创建一个 Observable ,并为它定义事件触发规则 166 | Observable observable = Observable.create(new Observable.OnSubscribe() { 167 | @Override 168 | public void call(Subscriber subscriber) { 169 | subscriber.onNext("Hello"); 170 | subscriber.onNext("World"); 171 | subscriber.onNext("!"); 172 | subscriber.onCompleted(); 173 | subscriber.onError(new Throwable()); 174 | Logger.d("被观察者-observable->call()->onCompleted()之后是否还有输出"); 175 | } 176 | }); 177 | 178 | /** 179 | * 可以看到,这里传入了一个 OnSubscribe 对象作为参数。 180 | * OnSubscribe 会被存储在返回的 Observable 对象中,它的作用相当于一个计划表, 181 | * 当Observable 被订阅的时候,OnSubscribe 的 call() 方法会自动被调用,事件序列就会依照设定依次触发 182 | * (对于上面的代码,就是观察者subscriber 将会被调用三次 onNext() 和一次 onCompleted())。 183 | * 这样,由被观察者调用了观察者的回调方法,就实现了由被观察者向观察者的事件传递,即观察者模式。 184 | */ 185 | //2:观察者 186 | Observer observer = new Observer() { 187 | @Override 188 | public void onCompleted() { 189 | Logger.d("观察者-observer:onCompleted()"); 190 | } 191 | 192 | @Override 193 | public void onError(Throwable e) { 194 | Logger.d("观察者-observer:onError" + e.getMessage()); 195 | } 196 | 197 | @Override 198 | public void onNext(String s) { 199 | Logger.d("观察者-observer:onNext():" + s); 200 | // getException();//故意让程序出现异常,用于测试onError()方法的执行.... 201 | } 202 | }; 203 | 204 | //3:订阅--被观察者被观察者订阅 205 | observable.subscribe(observer); 206 | } 207 | 208 | 209 | //---------------------------------------1:快捷创建事件队列 Observable.just(T...)-------------------------------------------------------------- 210 | 211 | // create() 方法是 RxJava 最基本的创造事件序列的方法。基于这个方法, RxJava 还提供了一些方法用来快捷创建事件队列, 212 | // 例如just(T...): 将传入的参数依次发送出来. 213 | 214 | //简化:观察者的创建,RxJava快捷创建事件队列的方法:just(T...): 215 | 216 | /** 217 | * 简化:观察者的创建 218 | * {@link #method0()} 219 | */ 220 | private void method1() { 221 | 222 | 223 | //实现步骤 224 | //1:被观察者: 225 | //2:观察者: 226 | //3:订阅-被观察者被观察者订阅 227 | 228 | 229 | //1:被观察者: 230 | //just(T...): 将传入的参数依次发送出来 231 | Observable observable = Observable.just("Hello", "World", "!"); 232 | // 将会依次调用: 233 | // onNext("Hello"); 234 | // onNext("World"); 235 | // onNext("!"); 236 | // onCompleted(); 237 | 238 | 239 | //2:观察者: 240 | Observer observer = new Observer() { 241 | @Override 242 | public void onCompleted() { 243 | Logger.d("观察者-observer:onCompleted()"); 244 | } 245 | 246 | @Override 247 | public void onError(Throwable e) { 248 | Logger.d("观察者-observer:onError()"); 249 | } 250 | 251 | @Override 252 | public void onNext(String s) { 253 | Logger.d("观察者-observer:onNext():" + s); 254 | //getException();//故意让程序出现异常,用于测试onError()方法的执行.... 255 | } 256 | }; 257 | 258 | //3:订阅:被观察者被观察者订阅 259 | observable.subscribe(observer); 260 | } 261 | 262 | 263 | //---------------------------------------2:快捷创建事件队列 Observable.from(T[]) / from(Iterable-------------------------------------------------------------- 264 | 265 | /** 266 | * 简化:观察者的创建: RxJava快捷创建事件队列的方法:just(String[] array) 将传入的数组或 Iterable 拆分成具体对象后,依次发送出来 267 | * {@link #method1()} 268 | */ 269 | private void method2() { 270 | 271 | //实现步骤 272 | //1:被观察者 273 | //2:观察者 274 | //3:订阅-被观察者被观察者订阅 275 | 276 | 277 | String[] array = new String[]{"Hello", "World", "!"}; 278 | //1:被观察者: 279 | //just(String[] array) 将传入的数组或 Iterable 拆分成具体对象后,依次发送出来。 280 | Observable observable = Observable.from(array); 281 | // 将会依次调用: 282 | // onNext("Hello"); 283 | // onNext("World"); 284 | // onNext("!"); 285 | // onCompleted(); 286 | 287 | 288 | //2:观察者 289 | Observer observer = new Observer() { 290 | @Override 291 | public void onCompleted() { 292 | Logger.d("观察者-observer:onCompleted()"); 293 | } 294 | 295 | @Override 296 | public void onError(Throwable e) { 297 | Logger.d("观察者-observer:onError()"); 298 | } 299 | 300 | @Override 301 | public void onNext(Object o) { 302 | String str = (String) o; 303 | Logger.d("观察者-observer:onNext():" + str); 304 | // getException();//故意让程序出现异常,用于测试onError()方法的执行.... 305 | } 306 | }; 307 | 308 | //3:订阅: 被观察者被观察者订阅 309 | observable.subscribe(observer); 310 | 311 | } 312 | 313 | //---------------------------------------3: subscribe()支持不完整定义的回调-------------------------------------------------------------- 314 | 315 | /** 316 | * 对观察者的简化 317 | * {@link #method2()} 318 | * subscribe一个参数的不完整定义的回调 319 | * subscribe(final Action1 onNext) 320 | */ 321 | private void method3() { 322 | 323 | String[] array = new String[]{"Hello", "World", "!"}; 324 | //1:被观察者 325 | Observable observable = Observable.from(array); 326 | 327 | //2:观察者 328 | Action1 onNextAction = new Action1() { 329 | @Override 330 | public void call(Object o) { 331 | String str = (String) o; 332 | Logger.d("观察者:call(Object o):" + str); 333 | } 334 | }; 335 | 336 | //3:订阅-被观察者被观察者订阅 337 | //subscribe(final Action1 onNext) 338 | //自动创建 Subscriber ,并使用 onNextAction 来定义 onNext() 339 | observable.subscribe(onNextAction); 340 | } 341 | 342 | /** 343 | * 对观察者的简化 344 | * subscribe两个参数的不完整定义的回调 345 | * {@link #method3()} 346 | * subscribe(final Action1 onNext, final Action1 onError) 347 | */ 348 | private void method4() { 349 | 350 | //1:被观察者 351 | Observable observable = Observable.from(new String[]{"Hello", "World", "!"}); 352 | 353 | //2:观察者 354 | Action1 onNextAction = new Action1() { 355 | @Override 356 | public void call(Object o) { 357 | String str = (String) o; 358 | Logger.d("观察者:onNextAction:call(Object o):o:" + str); 359 | } 360 | }; 361 | 362 | 363 | Action1 onErrorAction = new Action1() { 364 | @Override 365 | public void call(Throwable throwable) { 366 | Logger.d("观察者:onErrorAction:call(Throwable throwable):" + throwable.getMessage()); 367 | } 368 | }; 369 | 370 | 371 | //3:订阅 372 | //subscribe(final Action1 onNext, final Action1 onError) 373 | // 自动创建 Subscriber ,并使用 onNextAction 和 onErrorAction 来定义 onNext() 和 onError() 374 | observable.subscribe(onNextAction, onErrorAction); 375 | 376 | 377 | } 378 | 379 | /** 380 | * subscribe三个参数的不完整定义的回调 381 | * subscribe(final Action1 onNext, final Action1 onError, final Action0 onComplete) 382 | */ 383 | private void method5() { 384 | //1:被观察者 385 | Observable observable = Observable.from(new String[]{"Hello", "World", "!"}); 386 | 387 | 388 | //2:观察者 389 | Action1 onNextAction = new Action1() { 390 | @Override 391 | public void call(Object o) { 392 | String str = (String) o; 393 | Logger.d("观察者:onNextAction:call():s:" + str); 394 | } 395 | }; 396 | 397 | 398 | Action1 onErrorAction = new Action1() { 399 | @Override 400 | public void call(Throwable throwable) { 401 | Logger.d("观察者:onErrorAction:call(Throwable throwable):" + throwable.getMessage()); 402 | } 403 | }; 404 | 405 | 406 | Action0 onCompletedAction = new Action0() { 407 | @Override 408 | public void call() { 409 | Logger.d("观察者:onCompletedAction:call()"); 410 | } 411 | }; 412 | 413 | 414 | //3:订阅:被观察者被观察者订阅 415 | 416 | //subscribe(final Action1 onNext, final Action1 onError, final Action0 onComplete) 417 | // 自动创建 Subscriber ,并使用 onNextAction、 onErrorAction 和 onCompletedAction 来定义 onNext()、 onError() 和 onCompleted() 418 | observable.subscribe(onNextAction, onErrorAction, onCompletedAction); 419 | 420 | } 421 | 422 | //---------------------------------------4: Action0和Action1 讲解-------------------------------------------------------------- 423 | /** 424 | * 肯定有同学对Action0和Action1很困惑,就像当初我刚看到那样子; 425 | * 那就听听扔物线给大家讲一下: 426 | * 427 | * MaLin:扔物线大哥,你能够给我们讲解一下Action0和Action1是什么,以及他们之间的区别吗? 428 | * 429 | * 扔物线:大家好,我简单的解释一下: 430 | * Action0 是 RxJava 的一个接口,它只有一个方法 call(),这个方法是无参无返回值的; 431 | * 由于 onCompleted() 方法也是无参无返回值的,因此 Action0 可以被当成一个包装对象, 432 | * 将 onCompleted() 的内容打包起来将自己作为一个参数传入 subscribe() 以实现不完整定义的回调。 433 | * 这样其实也可以看做将 onCompleted() 方法作为参数传进了 subscribe(),相当于其他某些语言中的『闭包』。 434 | * 435 | * Action1 也是一个接口,它同样只有一个方法 call(T param),这个方法也无返回值,但有一个参数; 436 | * 与 Action0 同理,由于 onNext(T obj) 和 onError(Throwable error) 也是单参数无返回值的, 437 | * 因此 Action1 可以将 onNext(obj) 和 onError(error) 打包起来传入 subscribe() 以实现不完整定义的回调。 438 | * 事实上,虽然 Action0 和 Action1 在 API 中使用最广泛,但 RxJava 是提供了多个 ActionX 形式的接口 (例如 Action2, Action3) 的, 439 | * 它们可以被用以包装不同的无返回值的方法。 440 | */ 441 | 442 | 443 | //---------------------------------------5: 休息一下!推荐两个好用的日志查看工具------------------------------------------------------------- 444 | 445 | //1.[logger](https://github.com/orhanobut/logger) | 一个简洁,优雅,功能强大的Android日志输出工具 446 | //2.[pidcat](https://github.com/JakeWharton/pidcat)|JakeWharton项目一个简洁,优雅的,彩色日志终端查看库|在终端过滤日志信息 447 | 448 | /** 449 | * 使用com.github.orhanobut:logger 库可以查看当前的线程 450 | * ╔════════════════════════════════════════════════════════════════════════════════════════ 451 | D ║ Thread: main 452 | D ╟──────────────────────────────────────────────────────────────────────────────────────── 453 | D ║ MainActivity$11.onNext (MainActivity.java:338) 454 | D ║ MainActivity$11.onNext (MainActivity.java:354) 455 | D ╟──────────────────────────────────────────────────────────────────────────────────────── 456 | D ║ 观察者 onNext() 457 | D ╚════════════════════════════════════════════════════════════════════════════════════════ 458 | D ╔════════════════════════════════════════════════════════════════════════════════════════ 459 | D ║ Thread: main 460 | D ╟──────────────────────────────────────────────────────────────────────────────────────── 461 | D ║ SafeSubscriber.onCompleted (SafeSubscriber.java:83) 462 | D ║ MainActivity$11.onCompleted (MainActivity.java:341) 463 | D ╟──────────────────────────────────────────────────────────────────────────────────────── 464 | D ║ 观察者 onCompleted() 465 | D ╚════════════════════════════════════════════════════════════════════════════════════════ 466 | */ 467 | 468 | //---------------------------------------6 线程控制-Scheduler------------------------------------------------------------- 469 | 470 | /** 471 | * 显示图片 472 | * 后台线程取数据,主线程显示 473 | * 加载图片将会发生在 IO 线程,而设置图片则被设定在了主线程。这就意味着,即使加载图片耗费了几十甚至几百毫秒的时间,也不会造成丝毫界面的卡顿。 474 | */ 475 | private void method6() { 476 | 477 | final int drawableRes = R.mipmap.malin; 478 | Observable.create(new Observable.OnSubscribe() { //1:被观察者 479 | @Override 480 | public void call(Subscriber subscriber) { 481 | Logger.d("被观察者"); 482 | Drawable drawable = ContextCompat.getDrawable(RxJavaApplication.getApplication(), drawableRes); 483 | subscriber.onNext(drawable); 484 | subscriber.onCompleted(); 485 | } 486 | }) 487 | .subscribeOn(Schedulers.io())//事件产生的线程。指定 subscribe() 发生在 IO 线程 488 | // doOnSubscribe() 之后有 observeOn() 的话,它将执行在离它最近的 observeOn() 所指定的线程。这里将执行在主线程中 489 | .doOnSubscribe(new Action0() { 490 | @Override 491 | public void call() { 492 | if (mProgressBar != null) { 493 | mProgressBar.setVisibility(View.VISIBLE);//显示一个等待的ProgressBar--需要在主线程中执行 494 | } 495 | } 496 | }) 497 | .observeOn(AndroidSchedulers.mainThread())//指定 Subscriber 所运行在的线程。或者叫做事件消费的线程 498 | .subscribe(new Subscriber() { //3:订阅 //2:观察者 499 | @Override 500 | public void onCompleted() { 501 | if (mProgressBar != null) { 502 | mProgressBar.setVisibility(View.GONE); 503 | } 504 | Logger.d("观察者 onCompleted()"); 505 | Toast.makeText(MainActivity.this, "观察者 onCompleted()", Toast.LENGTH_SHORT).show(); 506 | } 507 | 508 | @Override 509 | public void onError(Throwable e) { 510 | if (mProgressBar != null) { 511 | mProgressBar.setVisibility(View.GONE); 512 | } 513 | Logger.d("观察者 onError()"); 514 | Toast.makeText(MainActivity.this, "观察者 onError() " + e.getMessage(), Toast.LENGTH_SHORT).show(); 515 | 516 | } 517 | 518 | @Override 519 | public void onNext(Drawable drawable) { 520 | Toast.makeText(MainActivity.this, "观察者 onNext()", Toast.LENGTH_SHORT).show(); 521 | Logger.d("观察者 onNext()"); 522 | if (mImageView == null || drawable == null) return; 523 | mImageView.setImageDrawable(drawable); 524 | } 525 | }); 526 | 527 | } 528 | 529 | //---------------------------------------7: 变换 map()------------------------------------------------------------- 530 | private void method7() { 531 | final int drawableRes = R.mipmap.malin; 532 | 533 | //1:被观察者 534 | Observable.just(drawableRes)//输入类型 int 535 | .map(new Func1() { 536 | 537 | @Override 538 | public Drawable call(Integer integer) {// 参数类型 String 539 | Logger.d("integer:" + integer); 540 | return ContextCompat.getDrawable(RxJavaApplication.getApplication(), integer); 541 | } 542 | }) 543 | .subscribeOn(Schedulers.io())//事件产生的线程。指定 subscribe() 发生在 IO 线程 544 | //doOnSubscribe() 之后有 observeOn() 的话,它将执行在离它最近的 observeOn() 所指定的线程。这里将执行在主线程中 545 | .doOnSubscribe(new Action0() { 546 | @Override 547 | public void call() { 548 | if (mProgressBar != null) { 549 | mProgressBar.setVisibility(View.VISIBLE);//显示一个等待的ProgressBar--需要在主线程中执行 550 | } 551 | } 552 | }) 553 | .observeOn(AndroidSchedulers.mainThread())//指定 Subscriber 所运行在的线程。或者叫做事件消费的线程 554 | .subscribe(new Subscriber() { //3:订阅 //2:观察者 555 | @Override 556 | public void onCompleted() { 557 | if (mProgressBar != null) { 558 | mProgressBar.setVisibility(View.GONE); 559 | } 560 | Logger.d("观察者:onCompleted()"); 561 | } 562 | 563 | @Override 564 | public void onError(Throwable e) { 565 | if (mProgressBar != null) { 566 | mProgressBar.setVisibility(View.GONE); 567 | } 568 | Toast.makeText(MainActivity.this, "" + e.getMessage(), Toast.LENGTH_SHORT).show(); 569 | Logger.d("观察者:onError(Throwable e):" + e.getMessage()); 570 | } 571 | 572 | @Override 573 | public void onNext(Drawable drawable) { 574 | if (mImageView == null || drawable == null) return; 575 | mImageView.setImageDrawable(drawable); 576 | Logger.d("观察者:onNext(Drawable drawable):" + drawable.toString()); 577 | } 578 | }); 579 | } 580 | 581 | //---------------------------------------8: 练习 中途休息一下------------------------------------------------------------- 582 | 583 | //演示嵌套循环 584 | private void method8() { 585 | ArrayList students = DataFactory.getData(); 586 | int size = students.size(); 587 | for (int i = 0; i < size; i++) { 588 | Logger.d("姓名:" + students.get(i).name); 589 | int sizeCourses = students.get(i).courses.size(); 590 | for (int j = 0; j < sizeCourses; j++) { 591 | Logger.d("课程:" + students.get(i).courses.get(j).name); 592 | } 593 | } 594 | } 595 | 596 | 597 | /** 598 | * 需要:依次输入学生的姓名:将每个学生(实体对象)依次发射出去 599 | * RxJava解决方案: 600 | * {@link #method8()} 601 | */ 602 | private void method9() { 603 | //just(T...): 将传入的参数依次发送出来,实现遍历的目的 604 | Observable.from(DataFactory.getData()) 605 | .subscribeOn(Schedulers.io()) 606 | .observeOn(AndroidSchedulers.mainThread()) 607 | .subscribe(new Action1() { 608 | @Override 609 | public void call(Student student) { 610 | Logger.d("观察者:" + student.name); 611 | } 612 | }); 613 | } 614 | 615 | 616 | /** 617 | * 需要:输出学生的姓名:将每个学生的(姓名)依次发射出去 618 | * RxJava解决方案 619 | * {@link #method9()} 620 | */ 621 | private void method10() { 622 | 623 | //1:被观察者 624 | 625 | //2:数据转换 626 | 627 | //3:事件产生的线程。 628 | 629 | //4:事件消费的线程。 630 | 631 | //5:被观察者被观察者订阅 632 | 633 | //6:观察者 634 | 635 | Observable.from(DataFactory.getData()) 636 | 637 | .map(new Func1() { 638 | @Override 639 | public String call(Student student) { 640 | return student.name; 641 | } 642 | }) 643 | .subscribeOn(Schedulers.io()) 644 | .observeOn(AndroidSchedulers.mainThread()) 645 | .subscribe(new Subscriber() { 646 | @Override 647 | public void onCompleted() { 648 | Logger.d("观察者:onCompleted()"); 649 | } 650 | 651 | @Override 652 | public void onError(Throwable e) { 653 | Logger.d("观察者:onError(Throwable e) " + e.getMessage()); 654 | } 655 | 656 | @Override 657 | public void onNext(String s) { 658 | Logger.d("观察者:onNext(String s) " + s); 659 | } 660 | }); 661 | 662 | } 663 | 664 | /** 665 | * 需要:输出学生的姓名:将每个学生的(姓名)依次发射出去,对method9()的简化 666 | * RxJava解决方案 667 | * 输出学生的姓名 668 | * {@link #method10()} 669 | */ 670 | private void method11() { 671 | Observable.from(DataFactory.getData()) 672 | .map(new Func1() { 673 | @Override 674 | public String call(Student student) { 675 | return student.name; 676 | } 677 | }) 678 | .subscribeOn(Schedulers.io()) 679 | .observeOn(AndroidSchedulers.mainThread()) 680 | .subscribe(new Action1() { 681 | @Override 682 | public void call(String s) { 683 | Logger.d("观察者:" + s); 684 | } 685 | }); 686 | 687 | } 688 | 689 | //---------------------------------------9: 引入flatmap()------------------------------------------------------------- 690 | 691 | /** 692 | * 需要:输出每一个学生所有选修的课程 693 | * 嵌套循环的RxJava解决方案 694 | * 输出每一个学生选修的课程 695 | * {@link #method11()} 696 | */ 697 | private void method12() { 698 | 699 | //1:被观察者 700 | 701 | //2:被观察者被观察者订阅 702 | 703 | //3:观察者 704 | 705 | Observable.from(DataFactory.getData()) 706 | .subscribe(new Subscriber() { 707 | @Override 708 | public void onCompleted() { 709 | Logger.d("观察者:onCompleted()"); 710 | } 711 | 712 | @Override 713 | public void onError(Throwable e) { 714 | Logger.d("观察者:onError(Throwable e)" + e.getMessage()); 715 | } 716 | 717 | @Override 718 | public void onNext(Student student) { 719 | ArrayList courses = student.courses; 720 | for (Course course : courses) { 721 | Logger.d("观察者:" + course.name); 722 | } 723 | } 724 | }); 725 | 726 | } 727 | 728 | /** 729 | * 需要:输出每一个学生选修的课程,对method12的简化 730 | * 嵌套循环的RxJava解决方案 731 | * {@link #method12()} 732 | * Student->ArrayList 733 | */ 734 | private void method13() { 735 | 736 | Observable.from(DataFactory.getData()) 737 | 738 | .map(new Func1>() { 739 | @Override 740 | public ArrayList call(Student student) { 741 | return student.courses; 742 | } 743 | }).subscribeOn(Schedulers.io()) 744 | .observeOn(AndroidSchedulers.mainThread()) 745 | .subscribe(new Action1>() { 746 | @Override 747 | public void call(ArrayList courses) { 748 | for (int i = 0; i < courses.size(); i++) { 749 | Logger.d("观察者:" + courses.get(i).name); 750 | } 751 | } 752 | }); 753 | } 754 | 755 | //---------------------------------------10: flatMap()的使用------------------------------------------------------------- 756 | 757 | /** 758 | * 需要:输出每一个学生选修的课程,对method13的简化 759 | * 嵌套循环的RxJava解决方案 760 | * {@link #method13()} 761 | * Student -> ArrayList -> Observable -> 762 | */ 763 | private void method14() { 764 | 765 | //1:被观察者 766 | 767 | //2:数据转换 768 | 769 | //3:事件产生的线程。 770 | 771 | //4:事件消费的线程。 772 | 773 | //5:被观察者被观察者订阅 774 | 775 | //6:观察者 776 | 777 | // Student->Course 778 | Observable.from(DataFactory.getData()) 779 | .flatMap(new Func1>() { 780 | @Override 781 | public Observable call(Student student) { 782 | return Observable.from(student.courses); 783 | } 784 | }).subscribeOn(Schedulers.io()) 785 | .observeOn(AndroidSchedulers.mainThread()) 786 | .subscribe(new Action1() { 787 | @Override 788 | public void call(Course course) { 789 | Logger.d("观察者:" + course.name); 790 | } 791 | }); 792 | } 793 | 794 | 795 | //---------------------------------------10: RxBinding的引入------------------------------------------------------------- 796 | 797 | 798 | /** 799 | * 需要防止快速连续点击,短时间内连续点击. 800 | */ 801 | private void method15() { 802 | 803 | 804 | mImageView.setOnClickListener(new View.OnClickListener() { 805 | @Override 806 | public void onClick(View v) { 807 | runOnUiThread(new Runnable() { 808 | @Override 809 | public void run() { 810 | if (ClickUtils.isFastDoubleClick()) { 811 | ToastUtil.getInstance().showToast(MainActivity.this, "点击过快啦"); 812 | return; 813 | } 814 | ToastUtil.getInstance().showToast(MainActivity.this, "匿名内部类实现click"); 815 | } 816 | }); 817 | } 818 | }); 819 | 820 | 821 | } 822 | 823 | /** 824 | * RxBinding 825 | * RxBinding 是 Jake Wharton 的一个开源库,它提供了一套在 Android 平台上的基于 RxJava 的 Binding API。 826 | * 所谓 Binding,就是类似设置 OnClickListener 、设置 TextWatcher 这样的注册绑定对象的 API。 827 | * 举个设置点击监听的例子。使用 RxBinding ,可以把事件监听用这样的方法来设置: 828 | * throttleFirst() ,用于去抖动,也就是消除手抖导致的快速连环点击: 829 | */ 830 | private void method16() { 831 | RxView.clicks(mImageView) 832 | .throttleFirst(500, TimeUnit.MILLISECONDS)//500ms,第一次点击后,500ms内点击无效,500ms后点击才会响应 833 | .subscribeOn(AndroidSchedulers.mainThread()) 834 | .observeOn(AndroidSchedulers.mainThread()) 835 | .subscribe(new Action1() { 836 | @Override 837 | public void call(Void aVoid) { 838 | Toast.makeText(MainActivity.this, "click", Toast.LENGTH_SHORT).show(); 839 | } 840 | }); 841 | } 842 | 843 | /** 844 | * RxBinding 845 | */ 846 | private void method17() { 847 | RxView.longClicks(mImageView) 848 | .throttleFirst(500, TimeUnit.MILLISECONDS) 849 | .subscribe(new Action1() { 850 | @Override 851 | public void call(Void aVoid) { 852 | Toast.makeText(MainActivity.this, "long click", Toast.LENGTH_SHORT).show(); 853 | } 854 | }); 855 | } 856 | 857 | /** 858 | * EditText,每隔500ms,去响应变化 859 | */ 860 | private void method18() { 861 | mSearchEditText.setVisibility(View.VISIBLE); 862 | RxTextView.textChangeEvents(mSearchEditText) 863 | .debounce(500, TimeUnit.MILLISECONDS) 864 | .observeOn(AndroidSchedulers.mainThread()) 865 | .subscribe(new Subscriber() { 866 | @Override 867 | public void onCompleted() { 868 | } 869 | 870 | @Override 871 | public void onError(Throwable e) { 872 | } 873 | 874 | @Override 875 | public void onNext(TextViewTextChangeEvent textViewTextChangeEvent) { 876 | String changedMessage = textViewTextChangeEvent.text().toString(); 877 | Logger.d(TAG, changedMessage); 878 | if (!TextUtils.isEmpty(changedMessage)) { 879 | ToastUtil.getInstance().showToast(MainActivity.this, changedMessage); 880 | } 881 | } 882 | }); 883 | } 884 | 885 | /** 886 | * 三、Defer、Just 887 | */ 888 | //操作符号 Range操作符根据出入的初始值n和数目m发射一系列大于等于n的m个值 889 | //例如:实现:输出1,2,3,4,5 890 | // 其使用也非常方便,仅仅制定初始值和数目就可以了,不用自己去实现对Subscriber的调用 891 | private void method19() { 892 | Observable.range(1, 5) 893 | .subscribeOn(Schedulers.io()) 894 | .observeOn(AndroidSchedulers.mainThread()) 895 | .subscribe(new Action1() { 896 | @Override 897 | public void call(Integer integer) { 898 | Logger.d(integer.toString() + ""); 899 | } 900 | }); 901 | } 902 | 903 | /** 904 | * 使用Retrofit网络库,获取androidmalin的GitHub个人信息 905 | */ 906 | private void method21() { 907 | 908 | mProgressBar.setVisibility(View.VISIBLE); 909 | mImageView.setVisibility(View.GONE); 910 | mResultTextView.setVisibility(View.VISIBLE); 911 | mResultTextView.setText(""); 912 | Call call = RetrofitService.getInstance().createService(GitHubApi.class).getUser("androidmalin"); 913 | 914 | //asynchronous 915 | call.enqueue(new Callback() { 916 | @Override 917 | public void onResponse(Call call, Response response) { 918 | User user = (User) response.body(); 919 | 920 | if (user == null) { 921 | //404 or the response cannot be converted to User. 922 | ResponseBody responseBody = response.errorBody(); 923 | if (responseBody != null) { 924 | try { 925 | Logger.d("responseBody = " + responseBody.string()); 926 | mResultTextView.setText("responseBody = " + responseBody.string()); 927 | } catch (IOException e) { 928 | e.printStackTrace(); 929 | } 930 | } else { 931 | Logger.d("responseBody = null"); 932 | mResultTextView.setText("responseBody = null"); 933 | } 934 | } else { 935 | //200 936 | String message = "Github Name :" + user.name + "\nWebsite :" + user.blog + "\nCompany Name :" + user.company; 937 | ToastUtil.getInstance().showToast(MainActivity.this, message); 938 | Logger.d(message); 939 | mResultTextView.setText(message); 940 | } 941 | mProgressBar.setVisibility(View.GONE); 942 | } 943 | 944 | @Override 945 | public void onFailure(Call call, Throwable t) { 946 | Logger.d("t = " + t.getMessage()); 947 | mProgressBar.setVisibility(View.GONE); 948 | } 949 | }); 950 | } 951 | 952 | /** 953 | * 使用Retrofit网络库,同时使用RxJava 获取androidmalin的GitHub个人信息 954 | */ 955 | private void method22() { 956 | //TODO:1:被观察者,数据源 957 | //TODO:2:观察者 958 | //TODO:3:订阅,被观察者 被 观察者订阅 959 | 960 | Observable observable = RetrofitService.getInstance().createService(GitHubApi.class).getUserObservable("androidmalin"); 961 | observable 962 | .subscribeOn(Schedulers.io()) 963 | .doOnSubscribe(new Action0() { 964 | @Override 965 | public void call() { 966 | mProgressBar.setVisibility(View.VISIBLE); 967 | mResultTextView.setText(""); 968 | mImageView.setVisibility(View.GONE); 969 | mResultTextView.setVisibility(View.VISIBLE); 970 | } 971 | }) 972 | .observeOn(AndroidSchedulers.mainThread()) 973 | .subscribe(new Subscriber() { 974 | @Override 975 | public void onCompleted() { 976 | Logger.d("onCompleted()"); 977 | mProgressBar.setVisibility(View.INVISIBLE); 978 | Toast.makeText(MainActivity.this, "onCompleted", Toast.LENGTH_SHORT).show(); 979 | } 980 | 981 | @Override 982 | public void onError(Throwable e) { 983 | Logger.d("onError()=>" + e.getMessage()); 984 | } 985 | 986 | @Override 987 | public void onNext(User user) { 988 | Logger.d("onNext()"); 989 | String message = "Github Name :" + user.name + "\nWebsite :" + user.blog + "\nCompany Name :" + user.company; 990 | Toast.makeText(MainActivity.this, "onNext", Toast.LENGTH_SHORT).show(); 991 | Logger.d(message); 992 | mResultTextView.setText(user.toString()); 993 | } 994 | }); 995 | } 996 | 997 | 998 | private ArrayAdapter mAdapter; 999 | private CompositeSubscription mSubscription = new CompositeSubscription(); 1000 | private ListView mResultListView; 1001 | 1002 | 1003 | /** 1004 | * 使用Retrofit网络库,同时使用RxJava 获取square的公司的retrofit项目的贡献者 1005 | */ 1006 | private void method23() { 1007 | 1008 | mImageView.setVisibility(View.GONE); 1009 | mResultTextView.setVisibility(View.GONE); 1010 | mImageView.setVisibility(View.GONE); 1011 | 1012 | mResultListView = (ListView) findViewById(R.id.lv_list); 1013 | mAdapter = new ArrayAdapter(MainActivity.this, R.layout.item_log, R.id.item_log, new ArrayList()); 1014 | mResultListView.setAdapter(mAdapter); 1015 | 1016 | mSubscription.add(RetrofitService.getInstance().createService(GitHubApi.class).getContributorsObservable("square", "retrofit") 1017 | .subscribeOn(Schedulers.io()) 1018 | .observeOn(AndroidSchedulers.mainThread()) 1019 | .doOnSubscribe(new Action0() { 1020 | @Override 1021 | public void call() { 1022 | mProgressBar.setVisibility(View.VISIBLE); 1023 | } 1024 | }) 1025 | .subscribe(new Observer>() { 1026 | @Override 1027 | public void onCompleted() { 1028 | Logger.d("Retrofit call 1 completed"); 1029 | mProgressBar.setVisibility(View.GONE); 1030 | mResultListView.setVisibility(View.VISIBLE); 1031 | ToastUtil.getInstance().showToast(MainActivity.this, "onCompleted"); 1032 | } 1033 | 1034 | @Override 1035 | public void onError(Throwable e) { 1036 | mProgressBar.setVisibility(View.GONE); 1037 | Logger.e(e.getMessage() + " woops we got an error while getting the list of contributors"); 1038 | ToastUtil.getInstance().showToast(MainActivity.this, "onError"); 1039 | } 1040 | 1041 | @Override 1042 | public void onNext(List contributors) { 1043 | ToastUtil.getInstance().showToast(MainActivity.this, "onNext"); 1044 | for (Contributor c : contributors) { 1045 | mAdapter.add(String.format("%s has made %d contributions to %s", 1046 | c.login, 1047 | c.contributions, 1048 | "retrofit")); 1049 | 1050 | Logger.d(String.format("%s has made %d contributions to %s", 1051 | c.login, 1052 | c.contributions, 1053 | "retrofit")); 1054 | } 1055 | } 1056 | })); 1057 | } 1058 | 1059 | 1060 | private static final int COUNT = 10; 1061 | private static final int TIME_ALL = 5000; 1062 | private ArrayList timeList = new ArrayList<>(); 1063 | 1064 | private void method20() { 1065 | 1066 | final int COUNT = 5; 1067 | final int TIME_ALL = 3000; 1068 | final ArrayList timeList = new ArrayList<>(); 1069 | final ArrayList allList = new ArrayList<>(); 1070 | 1071 | RxView.clicks(findViewById(R.id.iv_image)) 1072 | .map(new Func1() { 1073 | @Override 1074 | public Long call(Void aVoid) { 1075 | return System.currentTimeMillis(); 1076 | } 1077 | }) 1078 | .map(new Func1() { 1079 | @Override 1080 | public Boolean call(Long nowTime) { 1081 | allList.add(nowTime); 1082 | timeList.add(nowTime); 1083 | 1084 | boolean isOver = false; 1085 | Log.d(TAG, "timeList.size():" + timeList.size()); 1086 | if (timeList.size() >= COUNT) { 1087 | 1088 | if (nowTime - timeList.get(0) < TIME_ALL) { 1089 | isOver = true; 1090 | } else { 1091 | isOver = false; 1092 | } 1093 | timeList.clear(); 1094 | } 1095 | return isOver; 1096 | } 1097 | }).subscribe(new Action1() { 1098 | @Override 1099 | public void call(Boolean aBoolean) { 1100 | if (aBoolean) { 1101 | Toast.makeText(MainActivity.this, "3秒内点击超过了" + allList.size(), Toast.LENGTH_SHORT).show(); 1102 | allList.clear(); 1103 | } else { 1104 | // Toast.makeText(MainActivity.this, "ok "+timeList.size(), Toast.LENGTH_SHORT).show(); 1105 | } 1106 | } 1107 | }); 1108 | } 1109 | 1110 | public static String timeLongToString(long data) { 1111 | Date date = new Date(data); 1112 | SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()); 1113 | return formatter.format(date); 1114 | } 1115 | 1116 | 1117 | private void log(final String str) { 1118 | runOnUiThread(new Runnable() { 1119 | @Override 1120 | public void run() { 1121 | Log.d(TAG, str); 1122 | } 1123 | }); 1124 | } 1125 | 1126 | /** 1127 | * 测试这些每个知识点的功能 1128 | * 1129 | * @param number 1130 | */ 1131 | private void testFuncation(int number) { 1132 | switch (number) { 1133 | case 0: { 1134 | method0(); 1135 | break; 1136 | } 1137 | 1138 | case 1: { 1139 | method1(); 1140 | break; 1141 | } 1142 | 1143 | case 2: { 1144 | method2(); 1145 | break; 1146 | } 1147 | 1148 | case 3: { 1149 | method3(); 1150 | break; 1151 | } 1152 | 1153 | case 4: { 1154 | method4(); 1155 | break; 1156 | } 1157 | 1158 | case 5: { 1159 | method5(); 1160 | break; 1161 | } 1162 | 1163 | case 6: { 1164 | method6(); 1165 | break; 1166 | } 1167 | 1168 | case 7: { 1169 | method7(); 1170 | break; 1171 | } 1172 | 1173 | case 8: { 1174 | method8(); 1175 | break; 1176 | } 1177 | 1178 | case 9: { 1179 | method9(); 1180 | break; 1181 | } 1182 | 1183 | case 10: { 1184 | method10(); 1185 | break; 1186 | } 1187 | 1188 | case 11: { 1189 | method11(); 1190 | break; 1191 | } 1192 | 1193 | case 12: { 1194 | method12(); 1195 | break; 1196 | } 1197 | 1198 | case 13: { 1199 | method13(); 1200 | break; 1201 | } 1202 | 1203 | case 14: { 1204 | method14(); 1205 | break; 1206 | } 1207 | 1208 | case 15: { 1209 | method15(); 1210 | break; 1211 | } 1212 | case 16: { 1213 | method16(); 1214 | break; 1215 | } 1216 | 1217 | case 17: { 1218 | method17(); 1219 | break; 1220 | } 1221 | 1222 | case 18: { 1223 | method18(); 1224 | break; 1225 | } 1226 | 1227 | 1228 | case 19: { 1229 | method19(); 1230 | break; 1231 | } 1232 | 1233 | case 20: { 1234 | method20(); 1235 | break; 1236 | } 1237 | 1238 | case 21: { 1239 | method21(); 1240 | break; 1241 | } 1242 | 1243 | 1244 | case 22: { 1245 | method22(); 1246 | break; 1247 | } 1248 | 1249 | case 23: { 1250 | method23(); 1251 | break; 1252 | } 1253 | default: { 1254 | 1255 | break; 1256 | } 1257 | } 1258 | } 1259 | 1260 | 1261 | @Override 1262 | public void onResume() { 1263 | super.onResume(); 1264 | mSubscription = RxUtils.getNewCompositeSubIfUnsubscribed(mSubscription); 1265 | } 1266 | 1267 | @Override 1268 | public void onPause() { 1269 | super.onPause(); 1270 | 1271 | RxUtils.unsubscribeIfNotNull(mSubscription); 1272 | } 1273 | 1274 | private boolean mGoToRecycleImageView = false; 1275 | 1276 | @Override 1277 | protected void onDestroy() { 1278 | super.onDestroy(); 1279 | //rl_root_layout 这个是根布局的id 1280 | unBingListener(findViewById(R.id.rl_root_layout)); 1281 | unBindDrawables(findViewById(R.id.rl_root_layout)); 1282 | recycleImageView(); 1283 | } 1284 | 1285 | 1286 | private void recycleImageView() { 1287 | //回收ImageView占用的图像内存 1288 | if (mGoToRecycleImageView) { 1289 | Logger.d("onDestroy()> RecycleBitmap.recycleImageView(mImageView)"); 1290 | RecycleBitmap.recycleImageView(mImageView); 1291 | mImageView.setImageBitmap(null); 1292 | } 1293 | 1294 | if (mManyBitmapSuperposition != null && !mManyBitmapSuperposition.isRecycled()) { 1295 | mManyBitmapSuperposition.recycle(); 1296 | mManyBitmapSuperposition = null; 1297 | } 1298 | 1299 | //@link http://blog.csdn.net/yanzi1225627/article/details/8236309 1300 | if (mCanvas != null) { 1301 | //清屏 1302 | Paint paint = new Paint(); 1303 | paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); 1304 | mCanvas.drawPaint(paint); 1305 | paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC)); 1306 | mCanvas = null; 1307 | } 1308 | 1309 | } 1310 | 1311 | /** 1312 | * 做法也非常简单,在Activity onDestory时候从view的rootview开始, 1313 | * 递归释放所有子view涉及的图片,背景,DrawingCache,监听器等等资源, 1314 | * 让Activity成为一个不占资源的空壳,泄露了也不会导致图片资源被持有。 1315 | * 1316 | * @param view:the root view of the layout 1317 | * @description Unbind the rootView 1318 | * @author malin.myemail@gmail.com 1319 | * @link http://stackoverflow.com/questions/9461364/exception-in-unbinddrawables 1320 | * http://mp.weixin.qq.com/s?__biz=MzAwNDY1ODY2OQ==&mid=400656149&idx=1&sn=122b4f4965fafebf78ec0b4fce2ef62a&3rd=MzA3MDU4NTYzMw==&scene=6#rd 1321 | * @since 2015.12.16 1322 | */ 1323 | private void unBindDrawables(View view) { 1324 | if (view != null) { 1325 | try { 1326 | Drawable drawable = view.getBackground(); 1327 | if (drawable != null) { 1328 | drawable.setCallback(null); 1329 | } else { 1330 | } 1331 | if (view instanceof ViewGroup && !(view instanceof AdapterView)) { 1332 | ViewGroup viewGroup = (ViewGroup) view; 1333 | int viewGroupChildCount = viewGroup.getChildCount(); 1334 | for (int j = 0; j < viewGroupChildCount; j++) { 1335 | unBindDrawables(viewGroup.getChildAt(j)); 1336 | } 1337 | viewGroup.removeAllViews(); 1338 | } 1339 | } catch (Exception e) { 1340 | e.printStackTrace(); 1341 | } 1342 | 1343 | } 1344 | } 1345 | 1346 | /** 1347 | * Remove an onclick listener 1348 | * 1349 | * @param view 1350 | * @author malin.myemail@gmail.com 1351 | * @website https://github.com/androidmalin 1352 | * @data 2016/01/22 1353 | */ 1354 | private void unBingListener(View view) { 1355 | if (view != null) { 1356 | try { 1357 | if (view.hasOnClickListeners()) { 1358 | view.setOnClickListener(null); 1359 | } 1360 | if (view instanceof ViewGroup && !(view instanceof AdapterView)) { 1361 | ViewGroup viewGroup = (ViewGroup) view; 1362 | int viewGroupChildCount = viewGroup.getChildCount(); 1363 | for (int i = 0; i < viewGroupChildCount; i++) { 1364 | unBingListener(viewGroup.getChildAt(i)); 1365 | } 1366 | } 1367 | } catch (Exception e) { 1368 | e.printStackTrace(); 1369 | } 1370 | 1371 | } 1372 | } 1373 | 1374 | //-----------------------------------谜之缩进--嵌套循环--回调地狱 ----------------------------------------------------------- 1375 | 1376 | /** 1377 | * 实现的功能:获取assets文件夹下所有文件夹中的jpg图片,并且将所有的图片画到一个ImageView上,没有实际的用处,只是为了说明问题--- 谜之缩进--嵌套循环--回调地狱 1378 | * 不使用RxJava的写法-- 谜之缩进--回调地狱 1379 | */ 1380 | //思路:需要以下6个步骤完成 1381 | //1:遍历获取assets文件夹下所有的文件夹的名称 1382 | //2:遍历获取获取assets文件夹下某个文件夹中所有图片路径的集合 1383 | //3:过滤掉非JPG格式的图片 1384 | //4:获取某个路径下图片的bitmap 1385 | //5:将Bitmap绘制到画布上 1386 | //6:循环结束后更新UI,给ImageView设置最后绘制完成后的Bitmap,隐藏ProgressBar 1387 | private void miZhiSuoJinAndNestedLoopAndCallbackHell() { 1388 | new Thread(new Runnable() { 1389 | @Override 1390 | public void run() { 1391 | 1392 | runOnUiThread(new Runnable() { 1393 | @Override 1394 | public void run() { 1395 | mProgressBar.setVisibility(View.VISIBLE); 1396 | } 1397 | }); 1398 | //1:遍历获取assets文件夹下所有的文件夹的名称 1399 | ArrayList assetsFolderNameList = ImageNameFactory.getAssetImageFolderName(); 1400 | 1401 | for (String folderName : assetsFolderNameList) { 1402 | 1403 | //2:遍历获取获取assets文件夹下某个文件夹中所有图片路径的集合 1404 | ArrayList imagePathList = ImageUtils.getAssetsImageNamePathList(getApplicationContext(), folderName); 1405 | 1406 | for (final String imagePathName : imagePathList) { 1407 | //3:过滤掉非JPG格式的图片 1408 | if (imagePathName.endsWith(JPG)) { 1409 | 1410 | //4:获取某个路径下图片的bitmap 1411 | final Bitmap bitmap = ImageUtils.getImageBitmapFromAssetsFolderThroughImagePathName(getApplicationContext(), imagePathName, Constant.IMAGE_WITH, Constant.IMAGE_HEIGHT); 1412 | runOnUiThread(new Runnable() { 1413 | @Override 1414 | public void run() { 1415 | //Logger.d(mCounter + ":" + imagePathName); 1416 | 1417 | //5:将Bitmap绘制到画布上 1418 | createSingleImageFromMultipleImages(bitmap, mCounter); 1419 | mCounter++; 1420 | 1421 | } 1422 | }); 1423 | } 1424 | } 1425 | } 1426 | 1427 | 1428 | //6:循环结束后更新UI,给ImageView设置最后绘制完成后的Bitmap,隐藏ProgressBar 1429 | runOnUiThread(new Runnable() { 1430 | @Override 1431 | public void run() { 1432 | mImageView.setImageBitmap(mManyBitmapSuperposition); 1433 | mProgressBar.setVisibility(View.GONE); 1434 | } 1435 | }); 1436 | 1437 | } 1438 | }).start(); 1439 | } 1440 | 1441 | 1442 | /** 1443 | * 就是循环在画布上画图,呈现一种整齐的线性分布:像方格 1444 | * 所有绘制都绘制到了创建Canvas时传入的Bitmap上面 1445 | * 1446 | * @param bitmap:每张图片对应的Bitamp 1447 | * @param mCounter:一个自增的整数从0开始 1448 | */ 1449 | //实现思路: 1450 | //1:产生和手机屏幕尺寸同样大小的Bitmap 1451 | //2:以Bitmap对象创建一个画布,将内容都绘制在Bitmap上,这个Bitmap用来存储所有绘制在Canvas上的像素信息. 1452 | //3:这里将所有图片压缩成了相同的尺寸均为正方形图(64px*64px) 1453 | //4:计算获取绘制每个Bitmap的坐标,距离屏幕左边和上边的距离,距离左边的距离不断自增,距离顶部的距离循环自增 1454 | //5:将Bitmap画到指定坐标 1455 | private void createSingleImageFromMultipleImages(Bitmap bitmap, int mCounter) { 1456 | if (mCounter == 0) { 1457 | //1:产生和手机屏幕尺寸同样大小的Bitmap 1458 | mManyBitmapSuperposition = Bitmap.createBitmap(DeviceInfo.screenWidthForPortrait, DeviceInfo.screenHeightForPortrait, bitmap.getConfig()); 1459 | 1460 | //2:以Bitmap对象创建一个画布,则将内容都绘制在Bitmap上 1461 | mCanvas = new Canvas(mManyBitmapSuperposition); 1462 | } 1463 | if (mCanvas != null) { 1464 | int left;//距离左边的距离 1465 | int top;//距离顶部的距离 1466 | 1467 | //3:这里将所有图片压缩成了相同的尺寸均为正方形图(64px*64px) 1468 | int imageWidth = Constant.IMAGE_WITH; 1469 | int imageHeight = Constant.IMAGE_HEIGHT; 1470 | int number = DeviceInfo.screenHeightForPortrait / imageHeight;//手机竖屏模式下,垂直方向上绘制图片的个数 1471 | 1472 | //4:计算获取绘制每个Bitmap的坐标,距离屏幕左边和上边的距离,距离左边的距离不断自增,距离顶部的距离循环自增 1473 | if (mCounter >= (mCounter / number) * number && mCounter < (((mCounter / number) + 1) * number)) {//[0,number) 1474 | left = (mCounter / number) * imageWidth; 1475 | top = (mCounter % number) * imageHeight; 1476 | // Log.d(TAG,""+mCounter+" left="+left+" top="+top); 1477 | 1478 | //5:将Bitmap画到指定坐标 1479 | mCanvas.drawBitmap(bitmap, left, top, null); 1480 | } 1481 | } 1482 | } 1483 | 1484 | 1485 | /** 1486 | * 用于测试除法和取余 1487 | */ 1488 | private void showMath() { 1489 | String TAG = "Math"; 1490 | for (int i = 0; i < 100; i++) { 1491 | int ss = i / 10; 1492 | int ww = i % 10; 1493 | Log.d(TAG, i + "/10 ==" + ss); 1494 | Log.d(TAG, i + "%10 ==" + ww); 1495 | } 1496 | } 1497 | 1498 | 1499 | //-----------------------------------RxJava的实现--链式调用--十分简洁 ----------------------------------------------------------- 1500 | 1501 | 1502 | private void rxJavaSolveMiZhiSuoJinAndNestedLoopAndCallbackHell() { 1503 | //1:被观察者: 1504 | 1505 | //2:数据转换 1506 | 1507 | //3:设置事件的产生发生在IO线程 1508 | 1509 | //4:设置事件的消费发生在主线程 1510 | 1511 | //5:观察者 1512 | 1513 | //6:订阅:被观察者被观察者订阅 1514 | mGoToRecycleImageView = false; 1515 | Observable.from(ImageNameFactory.getAssetImageFolderName()) 1516 | //assets下一个文件夹的名称,assets下一个文件夹中一张图片的路径 1517 | .flatMap(new Func1>() { 1518 | @Override 1519 | public Observable call(String folderName) { 1520 | return Observable.from(ImageUtils.getAssetsImageNamePathList(getApplicationContext(), folderName)); 1521 | } 1522 | }) 1523 | //过滤,筛选出jpg图片 1524 | .filter(new Func1() { 1525 | @Override 1526 | public Boolean call(String imagePathNameAll) { 1527 | return imagePathNameAll.endsWith(JPG); 1528 | } 1529 | }) 1530 | //将图片路径转换为对应图片的Bitmap 1531 | .map(new Func1() { 1532 | @Override 1533 | public Bitmap call(String imagePathName) { 1534 | return ImageUtils.getImageBitmapFromAssetsFolderThroughImagePathName(getApplicationContext(), imagePathName, Constant.IMAGE_WITH, Constant.IMAGE_HEIGHT); 1535 | } 1536 | }) 1537 | .map(new Func1() { 1538 | @Override 1539 | public Void call(Bitmap bitmap) { 1540 | createSingleImageFromMultipleImages(bitmap, mCounter); 1541 | mCounter++; 1542 | return null; 1543 | } 1544 | }) 1545 | .subscribeOn(Schedulers.io())//设置事件的产生发生在IO线程 1546 | .doOnSubscribe(new Action0() { 1547 | @Override 1548 | public void call() { 1549 | mProgressBar.setVisibility(View.VISIBLE); 1550 | } 1551 | }) 1552 | .observeOn(AndroidSchedulers.mainThread())//设置事件的消费发生在主线程 1553 | .subscribe(new Subscriber() { 1554 | @Override 1555 | public void onCompleted() { 1556 | mImageView.setImageBitmap(mManyBitmapSuperposition); 1557 | mProgressBar.setVisibility(View.GONE); 1558 | } 1559 | 1560 | @Override 1561 | public void onError(Throwable e) { 1562 | //Toast.makeText(MainActivity.this, ""+e.getMessage(), Toast.LENGTH_SHORT).show(); 1563 | } 1564 | 1565 | @Override 1566 | public void onNext(Void aVoid) { 1567 | 1568 | } 1569 | }); 1570 | } 1571 | } 1572 | -------------------------------------------------------------------------------- /app/src/main/java/com/malin/rxjava/application/RxJavaApplication.java: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * The MIT License (MIT) 4 | * 5 | * Copyright (c) 2015 malin 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | 26 | package com.malin.rxjava.application; 27 | 28 | import android.app.Application; 29 | 30 | 31 | /** 32 | * 类描述:Application 33 | * 创建人:malin.myemail@gmail.com 34 | * 创建时间:15-12-16 上午11:00 35 | * 修改人: 36 | * 修改时间: 37 | * 修改备注: 38 | */ 39 | public class RxJavaApplication extends Application { 40 | 41 | private static RxJavaApplication application; 42 | @Override 43 | public void onCreate() { 44 | super.onCreate(); 45 | application = this; 46 | } 47 | 48 | public static RxJavaApplication getApplication(){ 49 | return application; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/java/com/malin/rxjava/constant/Constant.java: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * The MIT License (MIT) 4 | * 5 | * Copyright (c) 2015 malin 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | 26 | package com.malin.rxjava.constant; 27 | 28 | /** 29 | * 类描述:全局常量 30 | * 创建人:malin.myemail@gmail.com 31 | * 创建时间:15-11-13. 32 | * 版本:1.0.0 33 | * 备注: 34 | */ 35 | public class Constant { 36 | public static final int IMAGE_WITH = 64;//px 37 | public static final int IMAGE_HEIGHT = 64;//px 38 | 39 | public static final String BLANK_LOG = "\t"; 40 | public static final boolean isDebug = true; 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/java/com/malin/rxjava/factory/DataFactory.java: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * The MIT License (MIT) 4 | * 5 | * Copyright (c) 2015 malin 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | 26 | package com.malin.rxjava.factory; 27 | 28 | import com.malin.rxjava.model.Course; 29 | import com.malin.rxjava.model.Student; 30 | 31 | import java.util.ArrayList; 32 | 33 | /** 34 | * 类描述:获取学生集合 35 | * 创建人:malin.myemail@gmail.com 36 | * 创建时间:15-11-10. 37 | * 备注: 38 | */ 39 | public class DataFactory { 40 | 41 | private DataFactory() { 42 | } 43 | 44 | /** 45 | * 获取学生集合 46 | * 47 | * [ 48 | * 1:{ 49 | * id:1 50 | * name:学生1 51 | * course:[学生1的课程1,学生1的课程2,学生1的课程3] 52 | * } 53 | * 54 | * 2:{ 55 | * id:2 56 | * name:学生2 57 | * course:[学生2的课程1,学生2的课程2,学生2的课程3] 58 | * } 59 | * 60 | * 3:{ 61 | * id:3 62 | * name:学生3 63 | * course:[学生3的课程1,学生3的课程2,学生3的课程3] 64 | * } 65 | * ] 66 | * @return 67 | */ 68 | public static ArrayList getData() { 69 | 70 | ArrayList students = new ArrayList<>(); 71 | 72 | ArrayList courses; 73 | Student student; 74 | Course course; 75 | for (int i = 0; i < 3; i++) { 76 | 77 | courses = new ArrayList<>(); 78 | 79 | student = new Student(); 80 | student.id = i; 81 | student.name = new StringBuffer("学生").append((i+1)).toString(); 82 | 83 | for (int j = 0; j < 2; j++) { 84 | course = new Course(); 85 | course.id = j; 86 | course.name = new StringBuffer(student.name).append("的课程").append((j+1)).toString(); 87 | courses.add(course); 88 | } 89 | 90 | student.courses = courses; 91 | students.add(student); 92 | 93 | 94 | } 95 | return students; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /app/src/main/java/com/malin/rxjava/factory/ImageNameFactory.java: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * The MIT License (MIT) 4 | * 5 | * Copyright (c) 2015 malin 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | 26 | package com.malin.rxjava.factory; 27 | 28 | import java.util.ArrayList; 29 | 30 | /** 31 | * 类描述:获取图片文件夹类 32 | * 创建人:malin.myemail@gmail.com 33 | * 创建时间:15-11-10. 34 | * 备注: 35 | */ 36 | public class ImageNameFactory { 37 | 38 | private static final String FOLDER_NAME_ONE = "one"; 39 | private static final String FOLDER_NAME_TWO = "two"; 40 | private static final String FOLDER_NAME_THREE = "three"; 41 | private static final String FOLDER_NAME_FOUR = "four"; 42 | 43 | private ImageNameFactory() { 44 | } 45 | 46 | /** 47 | * 获取asset目录下的文件夹的名称集合 48 | * 49 | * @return 50 | */ 51 | public static ArrayList getAssetImageFolderName() { 52 | ArrayList assetsFolderNameList = new ArrayList<>(); 53 | assetsFolderNameList.add(FOLDER_NAME_ONE); 54 | assetsFolderNameList.add(FOLDER_NAME_TWO); 55 | assetsFolderNameList.add(FOLDER_NAME_THREE); 56 | assetsFolderNameList.add(FOLDER_NAME_FOUR); 57 | return assetsFolderNameList; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /app/src/main/java/com/malin/rxjava/githubapi/GitHubApi.java: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * The MIT License (MIT) 4 | * 5 | * Copyright (c) 2015 malin 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | 26 | package com.malin.rxjava.githubapi; 27 | 28 | 29 | import com.malin.rxjava.model.Contributor; 30 | import com.malin.rxjava.model.User; 31 | 32 | import java.util.List; 33 | 34 | import retrofit2.Call; 35 | import retrofit2.http.GET; 36 | import retrofit2.http.Path; 37 | import rx.Observable; 38 | 39 | /** 40 | * 类描述:GitHubApi 41 | * 创建人:malin.myemail@gmail.com 42 | * 创建时间:16-1-24 43 | * 备注:https://github.com/basil2style 44 | */ 45 | public interface GitHubApi { 46 | 47 | /** 48 | * See https://developer.github.com/v3/users/ 49 | */ 50 | 51 | @GET("/users/{username}") 52 | Call getUser(@Path("username") String user); 53 | 54 | @GET("/users/{username}") 55 | Observable getUserObservable(@Path("username") String username); 56 | 57 | 58 | /** 59 | * See https://developer.github.com/v3/repos/#list-contributors 60 | */ 61 | @GET("/repos/{owner}/{repo}/contributors") 62 | Observable> getContributorsObservable(@Path("owner") String owner, @Path("repo") String repo); 63 | 64 | @GET("/repos/{owner}/{repo}/contributors") 65 | List getContributors(@Path("owner") String owner, @Path("repo") String repo); 66 | } 67 | -------------------------------------------------------------------------------- /app/src/main/java/com/malin/rxjava/model/Contributor.java: -------------------------------------------------------------------------------- 1 | package com.malin.rxjava.model; 2 | 3 | /** 4 | * 类描述::GitHub API 中的Contributor 5 | * 创建人:malin.myemail@gmail.com 6 | * 创建时间:16-1-24 7 | * 备注:https://github.com/kaushikgopal/RxJava-Android-Samples 8 | * 使用:http://www.jsonschema2pojo.org/这个网站就Json自动转换为POJO 9 | */ 10 | 11 | public class Contributor { 12 | public String login; 13 | public Integer id; 14 | public String avatarUrl; 15 | public String gravatarId; 16 | public String url; 17 | public String htmlUrl; 18 | public String followersUrl; 19 | public String followingUrl; 20 | public String gistsUrl; 21 | public String starredUrl; 22 | public String subscriptionsUrl; 23 | public String organizationsUrl; 24 | public String reposUrl; 25 | public String eventsUrl; 26 | public String receivedEventsUrl; 27 | public String type; 28 | public Boolean siteAdmin; 29 | public Integer contributions; 30 | 31 | @Override 32 | public String toString() { 33 | return "Contributor{" + 34 | "login='" + login + '\'' + 35 | ", id=" + id + 36 | ", avatarUrl='" + avatarUrl + '\'' + 37 | ", gravatarId='" + gravatarId + '\'' + 38 | ", url='" + url + '\'' + 39 | ", htmlUrl='" + htmlUrl + '\'' + 40 | ", followersUrl='" + followersUrl + '\'' + 41 | ", followingUrl='" + followingUrl + '\'' + 42 | ", gistsUrl='" + gistsUrl + '\'' + 43 | ", starredUrl='" + starredUrl + '\'' + 44 | ", subscriptionsUrl='" + subscriptionsUrl + '\'' + 45 | ", organizationsUrl='" + organizationsUrl + '\'' + 46 | ", reposUrl='" + reposUrl + '\'' + 47 | ", eventsUrl='" + eventsUrl + '\'' + 48 | ", receivedEventsUrl='" + receivedEventsUrl + '\'' + 49 | ", type='" + type + '\'' + 50 | ", siteAdmin=" + siteAdmin + 51 | ", contributions=" + contributions + 52 | '}'; 53 | } 54 | } 55 | 56 | -------------------------------------------------------------------------------- /app/src/main/java/com/malin/rxjava/model/Course.java: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * The MIT License (MIT) 4 | * 5 | * Copyright (c) 2015 malin 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | 26 | package com.malin.rxjava.model; 27 | 28 | /** 29 | * 类描述:课程类 30 | * 创建人:malin.myemail@gmail.com 31 | * 创建时间:15-11-13. 32 | * 备注: 33 | */ 34 | 35 | public class Course { 36 | 37 | public int id;//课程编号 38 | public String name;//课程名称 39 | 40 | @Override 41 | public String toString() { 42 | return "Course{" + 43 | "id=" + id + 44 | ", name='" + name + '\'' + 45 | '}'; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/java/com/malin/rxjava/model/Student.java: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * The MIT License (MIT) 4 | * 5 | * Copyright (c) 2015 malin 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | 26 | package com.malin.rxjava.model; 27 | 28 | import java.util.ArrayList; 29 | 30 | /** 31 | * 类描述:学生类 32 | * 创建人:malin.myemail@gmail.com 33 | * 创建时间:15-11-10. 34 | * 备注: 35 | */ 36 | public class Student { 37 | 38 | public int id;//学号 39 | public String name;//姓名 40 | 41 | public ArrayList courses;//学生选修的课程 42 | 43 | @Override 44 | public String toString() { 45 | return "Student{" + 46 | "id=" + id + 47 | ", name='" + name + '\'' + 48 | ", courses=" + courses + 49 | '}'; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/java/com/malin/rxjava/model/User.java: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * The MIT License (MIT) 4 | * 5 | * Copyright (c) 2015 malin 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | 26 | package com.malin.rxjava.model; 27 | 28 | /** 29 | * 类描述:GitHub API 中的User 30 | * 创建人:malin.myemail@gmail.com 31 | * 创建时间:16-1-24 32 | * 备注:使用:http://www.jsonschema2pojo.org/这个网站就Json自动转换为POJO 33 | */ 34 | public class User { 35 | 36 | public String login; 37 | public Integer id; 38 | public String avatarUrl; 39 | public String gravatarId; 40 | public String url; 41 | public String htmlUrl; 42 | public String followersUrl; 43 | public String followingUrl; 44 | public String gistsUrl; 45 | public String starredUrl; 46 | public String subscriptionsUrl; 47 | public String organizationsUrl; 48 | public String reposUrl; 49 | public String eventsUrl; 50 | public String receivedEventsUrl; 51 | public String type; 52 | public Boolean siteAdmin; 53 | public String name; 54 | public String company; 55 | public String blog; 56 | public String location; 57 | public String email; 58 | public Boolean hireable; 59 | public Object bio; 60 | public Integer publicRepos; 61 | public Integer publicGists; 62 | public Integer followers; 63 | public Integer following; 64 | public String createdAt; 65 | public String updatedAt; 66 | 67 | 68 | @Override 69 | public String toString() { 70 | return "User{" + 71 | "login='" + login + '\'' + 72 | ", id=" + id + 73 | ", avatarUrl='" + avatarUrl + '\'' + 74 | ", gravatarId='" + gravatarId + '\'' + 75 | ", url='" + url + '\'' + 76 | ", htmlUrl='" + htmlUrl + '\'' + 77 | ", followersUrl='" + followersUrl + '\'' + 78 | ", followingUrl='" + followingUrl + '\'' + 79 | ", gistsUrl='" + gistsUrl + '\'' + 80 | ", starredUrl='" + starredUrl + '\'' + 81 | ", subscriptionsUrl='" + subscriptionsUrl + '\'' + 82 | ", organizationsUrl='" + organizationsUrl + '\'' + 83 | ", reposUrl='" + reposUrl + '\'' + 84 | ", eventsUrl='" + eventsUrl + '\'' + 85 | ", receivedEventsUrl='" + receivedEventsUrl + '\'' + 86 | ", type='" + type + '\'' + 87 | ", siteAdmin=" + siteAdmin + 88 | ", name='" + name + '\'' + 89 | ", company='" + company + '\'' + 90 | ", blog='" + blog + '\'' + 91 | ", location='" + location + '\'' + 92 | ", email='" + email + '\'' + 93 | ", hireable=" + hireable + 94 | ", bio=" + bio + 95 | ", publicRepos=" + publicRepos + 96 | ", publicGists=" + publicGists + 97 | ", followers=" + followers + 98 | ", following=" + following + 99 | ", createdAt='" + createdAt + '\'' + 100 | ", updatedAt='" + updatedAt + '\'' + 101 | '}'; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /app/src/main/java/com/malin/rxjava/service/RetrofitService.java: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * The MIT License (MIT) 4 | * 5 | * Copyright (c) 2015 malin 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | 26 | package com.malin.rxjava.service; 27 | 28 | 29 | import retrofit2.Retrofit; 30 | import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory; 31 | import retrofit2.converter.gson.GsonConverterFactory; 32 | 33 | /** 34 | * 类描述:RetrofitService 35 | * 创建人:malin.myemail@gmail.com 36 | * 创建时间:16-1-24 37 | * 备注:{@link https://github.com/basil2style/Retrofit-Android-Basic} Thanks for ,Her code is very good ! I made reference to his code,It saves me a lot of time! 38 | * 修改人: 39 | * 修改时间: 40 | * 修改备注: 41 | */ 42 | public class RetrofitService { 43 | private static final String API = "https://api.github.com"; 44 | 45 | protected RetrofitService() { 46 | retrofit = new Retrofit.Builder() 47 | .baseUrl(API) 48 | .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 49 | .addConverterFactory(GsonConverterFactory.create()) 50 | .build(); 51 | } 52 | 53 | private volatile static RetrofitService instance = null; 54 | 55 | private Retrofit retrofit; 56 | 57 | public static RetrofitService getInstance() { 58 | if (instance == null) { 59 | synchronized (RetrofitService.class) { 60 | if (instance == null) { 61 | instance = new RetrofitService(); 62 | } 63 | } 64 | } 65 | return instance; 66 | } 67 | 68 | public T createService(Class clz){ 69 | return retrofit.create(clz); 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /app/src/main/java/com/malin/rxjava/utils/ClickUtils.java: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * The MIT License (MIT) 4 | * 5 | * Copyright (c) 2015 malin 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | 26 | package com.malin.rxjava.utils; 27 | 28 | import android.os.SystemClock; 29 | import android.util.Log; 30 | 31 | /** 32 | * 类描述:手机设备的信息 33 | * 创建人:malin.myemail@gmail.com 34 | * 创建时间:16-01-20.下午17:50 35 | * 备注: 36 | */ 37 | public class ClickUtils { 38 | 39 | private static final String TAG = ClickUtils.class.getSimpleName(); 40 | private static long lastClickTime = 0L; 41 | private static final boolean isDebug = true; 42 | private static final String BLANK_LOG = "\t"; 43 | 44 | private ClickUtils() { 45 | } 46 | 47 | /** 48 | * 用于处理频繁点击问题, 如果两次点击小于500毫秒则不予以响应 49 | * 50 | * @return true:是连续的快速点击 51 | */ 52 | public static boolean isFastDoubleClick() { 53 | long nowTime = SystemClock.elapsedRealtime();//从开机到现在的毫秒数(手机睡眠(sleep)的时间也包括在内) 54 | 55 | if (isDebug){ 56 | Log.d(TAG,"nowTime:" + nowTime); 57 | Log.d(TAG,"lastClickTime:" + lastClickTime); 58 | Log.d(TAG,"时间间隔:"+(nowTime - lastClickTime)); 59 | } 60 | if ((nowTime - lastClickTime) < 100000) { 61 | 62 | if (isDebug){ 63 | Log.d(TAG,"快速点击"); 64 | Log.d(TAG, BLANK_LOG); 65 | } 66 | return true; 67 | } else { 68 | lastClickTime = nowTime; 69 | 70 | if (isDebug){ 71 | Log.d(TAG,"lastClickTime:" + lastClickTime); 72 | Log.d(TAG,"不是快速点击"); 73 | Log.d(TAG,BLANK_LOG); 74 | } 75 | return false; 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /app/src/main/java/com/malin/rxjava/utils/DeviceInfo.java: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * The MIT License (MIT) 4 | * 5 | * Copyright (c) 2015 malin 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | 26 | package com.malin.rxjava.utils; 27 | 28 | import android.app.Activity; 29 | import android.util.DisplayMetrics; 30 | 31 | /** 32 | * 类描述:手机设备的信息 33 | * 创建人:malin.myemail@gmail.com 34 | * 创建时间:15-11-10.下午3:26 35 | * 备注: 36 | * 参考项目:Android-Universal-Image-Loader 37 | */ 38 | public class DeviceInfo { 39 | 40 | public static int screenWidthForPortrait; // 屏幕宽度 41 | public static int screenHeightForPortrait; // 屏幕高度 42 | public static float mDensity; 43 | public static int mDensityDpi; 44 | 45 | 46 | private volatile static DeviceInfo instance; 47 | 48 | /** 49 | * Returns singleton class instance 50 | */ 51 | public static DeviceInfo getInstance() { 52 | if (instance == null) { 53 | synchronized (DeviceInfo.class) { 54 | if (instance == null) { 55 | instance = new DeviceInfo(); 56 | } 57 | } 58 | } 59 | return instance; 60 | } 61 | 62 | private DeviceInfo() { 63 | 64 | } 65 | 66 | 67 | /** 68 | * init get device information 69 | * 70 | * @param activity 71 | */ 72 | public void initializeScreenInfo(Activity activity) { 73 | DisplayMetrics metric = new DisplayMetrics(); 74 | activity.getWindowManager().getDefaultDisplay().getMetrics(metric); 75 | mDensity = metric.density; 76 | mDensityDpi = metric.densityDpi; 77 | if (metric.heightPixels >= metric.widthPixels) { 78 | screenWidthForPortrait = metric.widthPixels; 79 | screenHeightForPortrait = metric.heightPixels; 80 | } else { 81 | screenWidthForPortrait = metric.heightPixels; 82 | screenHeightForPortrait = metric.widthPixels; 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /app/src/main/java/com/malin/rxjava/utils/ImageUtils.java: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * The MIT License (MIT) 4 | * 5 | * Copyright (c) 2015 malin 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | 26 | package com.malin.rxjava.utils; 27 | 28 | import android.annotation.SuppressLint; 29 | import android.annotation.TargetApi; 30 | import android.content.Context; 31 | import android.content.res.AssetManager; 32 | import android.graphics.Bitmap; 33 | import android.graphics.BitmapFactory; 34 | import android.os.Build; 35 | 36 | import java.io.File; 37 | import java.io.IOException; 38 | import java.io.InputStream; 39 | import java.util.ArrayList; 40 | 41 | 42 | /** 43 | * 类描述:图片处理类 44 | * 创建人:malin.myemail@gmail.com 45 | * 创建时间:15-11-11. 46 | * 参考项目: 47 | */ 48 | public class ImageUtils { 49 | 50 | private static final String TAG = "PaoWuXian_RxJava"; 51 | 52 | private ImageUtils() { 53 | } 54 | 55 | /** 56 | * 从assets文件夹中获取制定路径的图片的Bitmap 57 | * 58 | * @param context:上下文 59 | * @param imagePathName:图片路径的名称:例如: paowuxian/04.jpg 60 | * @param reqWidth:图片需要显示的宽 61 | * @param reqHeight:图片需要显示的高 62 | * @return 63 | */ 64 | public static Bitmap getImageBitmapFromAssetsFolderThroughImagePathName(Context context, String imagePathName, int reqWidth, int reqHeight) { 65 | BitmapFactory.Options opts = new BitmapFactory.Options(); 66 | opts.inJustDecodeBounds = true; 67 | Bitmap bitmap = null; 68 | AssetManager assetManager = context.getResources().getAssets(); 69 | InputStream inputStream; 70 | 71 | try { 72 | inputStream = assetManager.open(imagePathName); 73 | inputStream.mark(Integer.MAX_VALUE); 74 | } catch (IOException e) { 75 | e.printStackTrace(); 76 | return null; 77 | }catch (OutOfMemoryError e) { 78 | e.printStackTrace(); 79 | System.gc(); 80 | return null; 81 | } 82 | 83 | try { 84 | if (inputStream != null) { 85 | BitmapFactory.decodeStream(inputStream, null, opts); 86 | inputStream.reset(); 87 | } else { 88 | return null; 89 | } 90 | } catch (OutOfMemoryError e) { 91 | e.printStackTrace(); 92 | System.gc(); 93 | return null; 94 | } catch (Exception e) { 95 | e.printStackTrace(); 96 | return null; 97 | } 98 | opts.inSampleSize = calculateInSampleSiez(opts, reqWidth, reqHeight); 99 | // Log.d(TAG,""+opts.inSampleSize); 100 | opts.inJustDecodeBounds = false; 101 | opts.inPreferredConfig = Bitmap.Config.RGB_565; 102 | opts.inPurgeable = true; 103 | opts.inInputShareable = true; 104 | opts.inDither = false; 105 | opts.inTempStorage = new byte[512 * 1024]; 106 | try { 107 | if (inputStream != null) { 108 | bitmap = BitmapFactory.decodeStream(inputStream, null, opts); 109 | } else { 110 | return null; 111 | } 112 | } catch (OutOfMemoryError e) { 113 | e.printStackTrace(); 114 | System.gc(); 115 | return null; 116 | } catch (Exception e) { 117 | e.printStackTrace(); 118 | return null; 119 | } finally { 120 | if (inputStream != null) { 121 | try { 122 | inputStream.close(); 123 | } catch (Exception e) { 124 | e.printStackTrace(); 125 | return null; 126 | } 127 | } 128 | } 129 | // Log.d(TAG,"w:"+bitmap.getWidth()+" h:"+bitmap.getHeight()); 130 | if (bitmap != null) { 131 | try { 132 | bitmap = Bitmap.createScaledBitmap(bitmap, reqWidth, reqHeight, true); 133 | }catch (OutOfMemoryError outOfMemoryError){ 134 | outOfMemoryError.printStackTrace(); 135 | System.gc(); 136 | return null; 137 | } 138 | 139 | } 140 | return bitmap; 141 | } 142 | 143 | 144 | /** 145 | * 获取一个合适的缩放系数(2^n) 146 | * 147 | * @param options:Options 148 | * @param reqWidth:图片需要显示的宽 149 | * @param reqHeight:图片需要显示的高 150 | * @return 缩放系数, 2的次方 151 | * @Link http://hukai.me/android-training-course-in-chinese/graphics/displaying-bitmaps/load-bitmap.html 152 | */ 153 | public static int calculateInSampleSiez(BitmapFactory.Options options, int reqWidth, int reqHeight) { 154 | // Raw height and width of image 155 | final int height = options.outHeight; 156 | final int width = options.outWidth; 157 | int inSampleSize = 1; 158 | 159 | if (height > reqHeight || width > reqWidth) { 160 | 161 | final int halfHeight = height / 2; 162 | final int halfWidth = width / 2; 163 | 164 | // Calculate the largest inSampleSize value that is a power of 2 and keeps both 165 | // height and width larger than the requested height and width. 166 | while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) { 167 | inSampleSize *= 2; 168 | } 169 | } 170 | return inSampleSize; 171 | } 172 | 173 | 174 | /** 175 | * 获取assets文件夹下某个文件夹中所有图片路径的集合 176 | *

177 | * 例如:assets/paowuxian 这个目录下的图片路径的集合 178 | * { 179 | * paowuxian/04.jpg, 180 | * paowuxian/05.jpg, 181 | * paowuxian/06.jpg, 182 | * paowuxian/07.jpg, 183 | *

184 | * } 185 | * 186 | * @param context:上下文 187 | * @param folderName:文件夹名称 188 | * @return 189 | */ 190 | public static ArrayList getAssetsImageNamePathList(Context context, String folderName) { 191 | 192 | ArrayList imagePathList = new ArrayList<>(); 193 | 194 | String[] imageNameArray = getAssetsImageNameArray(context, folderName); 195 | 196 | if (imageNameArray != null && imageNameArray.length > 0 && folderName != null && !folderName.replaceAll(" ", "").trim().equals("")) { 197 | for (String imageName : imageNameArray) { 198 | imagePathList.add(new StringBuffer(folderName).append(File.separator).append(imageName).toString()); 199 | } 200 | } 201 | 202 | return imagePathList; 203 | } 204 | 205 | 206 | /** 207 | * 得到assets文件夹下--某个文件夹下--所有文件的文件名 208 | * 例如:assets/paowuxian 这个目录下的图片名称(包含后缀)集合 209 | * { 210 | * 04.jpg, 211 | * 05.jpg, 212 | * 06.jpg, 213 | * 07.jpg, 214 | * } 215 | * 216 | * @param context:上下文 217 | * @param folderName:文件夹名称 218 | * @return 219 | */ 220 | private static String[] getAssetsImageNameArray(Context context, String folderName) { 221 | String[] imageNameArray = null; 222 | try { 223 | imageNameArray = context.getAssets().list(folderName); 224 | } catch (IOException e) { 225 | e.printStackTrace(); 226 | } 227 | return imageNameArray; 228 | } 229 | 230 | 231 | /** 232 | * 将本地ResFolder图片转换为Bitmap 233 | */ 234 | 235 | /** 236 | * inDensity 就是原始资源的 density 237 | * 238 | * inTargetDensity 就是屏幕的 density。 239 | */ 240 | 241 | public static Bitmap getLocalBitmapFromResFolder(Context context, int resId) { 242 | return BitmapFactory.decodeResource(context.getResources(), resId); 243 | } 244 | 245 | /** 246 | * 获取Bitmap大小 247 | * @param bitmap 248 | * @return 249 | */ 250 | @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1) 251 | public static int getBitmapSize2(Bitmap bitmap) { 252 | if (bitmap==null) return 0; 253 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB_MR1) { 254 | return bitmap.getRowBytes() * bitmap.getHeight(); 255 | } else { 256 | return bitmap.getByteCount(); 257 | } 258 | } 259 | 260 | /** 261 | * 获取Bitmap大小 262 | * @param bitmap 263 | * @return 264 | */ 265 | @SuppressLint("NewApi") 266 | public static int getBitmapSize(Bitmap bitmap) { 267 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { // API 19 268 | return bitmap.getAllocationByteCount(); 269 | } 270 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {// API 12 271 | return bitmap.getByteCount(); 272 | } 273 | return bitmap.getRowBytes() * bitmap.getHeight(); // earlier version 274 | } 275 | } 276 | -------------------------------------------------------------------------------- /app/src/main/java/com/malin/rxjava/utils/RecycleBitmap.java: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * The MIT License (MIT) 4 | * 5 | * Copyright (c) 2015 malin 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | 26 | package com.malin.rxjava.utils; 27 | 28 | 29 | import android.graphics.Bitmap; 30 | import android.graphics.drawable.BitmapDrawable; 31 | import android.graphics.drawable.Drawable; 32 | import android.widget.ImageView; 33 | 34 | /** 35 | * 类描述:回收ImageView占用的图像内存 36 | * 创建人:malin.myemail@gmail.com 37 | * 创建时间:15-11-21. 38 | * 参考内容:http://blog.csdn.net/intbird/article/details/19905549 39 | */ 40 | 41 | public class RecycleBitmap { 42 | private RecycleBitmap() { 43 | } 44 | 45 | /** 46 | * 回收ImageView占用的图像内存; 47 | * 48 | * @param imageView 49 | */ 50 | public static void recycleImageView(ImageView imageView) { 51 | if (imageView == null) { 52 | return; 53 | } 54 | 55 | Drawable drawable = imageView.getDrawable(); 56 | if (drawable != null && drawable instanceof BitmapDrawable) { 57 | BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable; 58 | Bitmap bitmap = bitmapDrawable.getBitmap(); 59 | if (bitmap != null && !bitmap.isRecycled()) { 60 | bitmap.recycle(); 61 | bitmap = null; 62 | imageView.setImageBitmap(null); 63 | } 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /app/src/main/java/com/malin/rxjava/utils/RxUtils.java: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * The MIT License (MIT) 4 | * 5 | * Copyright (c) 2015 malin 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | 26 | package com.malin.rxjava.utils; 27 | 28 | import rx.Subscription; 29 | import rx.subscriptions.CompositeSubscription; 30 | 31 | public class RxUtils { 32 | 33 | private RxUtils() { 34 | } 35 | 36 | public static void unsubscribeIfNotNull(Subscription subscription) { 37 | if (subscription != null) { 38 | subscription.unsubscribe(); 39 | } 40 | } 41 | 42 | public static CompositeSubscription getNewCompositeSubIfUnsubscribed(CompositeSubscription subscription) { 43 | if (subscription == null || subscription.isUnsubscribed()) { 44 | return new CompositeSubscription(); 45 | } 46 | 47 | return subscription; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/java/com/malin/rxjava/utils/ToastUtil.java: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * The MIT License (MIT) 4 | * 5 | * Copyright (c) 2015 malin 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | 26 | package com.malin.rxjava.utils; 27 | 28 | import android.content.Context; 29 | import android.widget.Toast; 30 | 31 | /** 32 | * 类描述:防止Toast显示多次 33 | * 创建人:malin.myemail@gmail.com 34 | * 创建时间:16-01-20.下午17:50 35 | * 备注: 36 | */ 37 | public class ToastUtil { 38 | 39 | 40 | private static String mOldMessage = ""; 41 | protected static Toast mToast = null; 42 | private static long mFirstTime = 0L; 43 | private static long mSecondTime = 0L; 44 | 45 | 46 | private volatile static ToastUtil instance; 47 | 48 | /** 49 | * Returns singleton class instance 50 | */ 51 | public static ToastUtil getInstance() { 52 | if (instance == null) { 53 | synchronized (ToastUtil.class) { 54 | if (instance == null) { 55 | instance = new ToastUtil(); 56 | } 57 | } 58 | } 59 | return instance; 60 | } 61 | 62 | private ToastUtil() { 63 | 64 | } 65 | 66 | 67 | public void showToast(Context context, String message) { 68 | if (mToast == null) { 69 | synchronized (ToastUtil.class) { 70 | if (mToast == null) { 71 | mToast = Toast.makeText(context, message, Toast.LENGTH_SHORT); 72 | mToast.show(); 73 | mFirstTime = System.currentTimeMillis(); 74 | } 75 | } 76 | 77 | } else { 78 | mSecondTime = System.currentTimeMillis(); 79 | if (message.equals(mOldMessage)) { 80 | if (mSecondTime - mFirstTime > Toast.LENGTH_SHORT) { 81 | mToast.show(); 82 | } 83 | } else { 84 | mOldMessage = message; 85 | mToast.setText(message); 86 | mToast.show(); 87 | } 88 | } 89 | mFirstTime = mSecondTime; 90 | } 91 | 92 | 93 | public void showToast(Context context, int resId) { 94 | showToast(context, context.getString(resId)); 95 | } 96 | 97 | 98 | } -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 43 | 44 | 45 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_log.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/malin.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidmalin/RxjavaSample/3a13759b2db1105024b94be75ad81906a00b59c8/app/src/main/res/mipmap-xhdpi/malin.jpg -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values-zh/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | RxJavaSample 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | RxJavaSample 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | buildscript { 3 | repositories { 4 | jcenter() 5 | mavenCentral() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.2.3' 9 | // NOTE: Do not place your application dependencies here; they belong 10 | // in the individual module build.gradle files 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | jcenter() 17 | } 18 | } 19 | 20 | task clean(type: Delete) { 21 | delete rootProject.buildDir 22 | } 23 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | ## Project-wide Gradle settings. 2 | # 3 | # For more details on how to configure your build environment visit 4 | # http://www.gradle.org/docs/current/userguide/build_environment.html 5 | # 6 | # Specifies the JVM arguments used for the daemon process. 7 | # The setting is particularly useful for tweaking memory settings. 8 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 9 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 10 | # 11 | # When configured, Gradle will run in incubating parallel mode. 12 | # This option should only be used with decoupled projects. More details, visit 13 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 14 | # org.gradle.parallel=true 15 | #Wed Jan 27 10:24:18 CST 2016 16 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidmalin/RxjavaSample/3a13759b2db1105024b94be75ad81906a00b59c8/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Dec 16 15:33:33 CST 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /qrcode/dowload_qrcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androidmalin/RxjavaSample/3a13759b2db1105024b94be75ad81906a00b59c8/qrcode/dowload_qrcode.png -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | --------------------------------------------------------------------------------