├── .gitignore ├── .idea └── encodings.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── che58 │ │ └── ljb │ │ └── rxjava │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── che58 │ │ │ └── ljb │ │ │ └── rxjava │ │ │ ├── DemoApplication.java │ │ │ ├── act │ │ │ └── MainActivity.java │ │ │ ├── fragment │ │ │ ├── BufferFragment.java │ │ │ ├── CheckBoxUpdateFragment.java │ │ │ ├── ConcatFragment.java │ │ │ ├── DebounceFragment.java │ │ │ ├── LoopFragment.java │ │ │ ├── Net2Fragment.java │ │ │ ├── NetFragment.java │ │ │ ├── NotMoreClickFragment.java │ │ │ ├── PublishSubjectBottomFragment.java │ │ │ ├── PublishSubjectFragment.java │ │ │ ├── PublishSubjectTopFragment.java │ │ │ ├── ReuseSubscriberFragment.java │ │ │ ├── TimerFragment.java │ │ │ ├── ZipFragment.java │ │ │ └── main │ │ │ │ └── MainFragment.java │ │ │ ├── model │ │ │ ├── Contacter.java │ │ │ ├── DeleteModel.java │ │ │ ├── GetModel.java │ │ │ ├── PostModel.java │ │ │ └── PutModel.java │ │ │ ├── net │ │ │ ├── XgoHttpClient.java │ │ │ └── interceptor │ │ │ │ └── XgoLogInterceptor.java │ │ │ ├── protocol │ │ │ ├── BaseProtocol.java │ │ │ └── TestProtocol.java │ │ │ ├── protocol2 │ │ │ ├── BaseProtocol.java │ │ │ └── TestProtocol.java │ │ │ ├── rxbus │ │ │ ├── RxBus.java │ │ │ ├── RxBusDemoFragment.java │ │ │ ├── RxBusDemo_Bottom3Fragment.java │ │ │ └── RxBusDemo_TopFragment.java │ │ │ ├── utils │ │ │ └── XgoLog.java │ │ │ └── view │ │ │ └── ProgressWheel.java │ └── res │ │ ├── drawable-xxhdpi │ │ ├── default_image.png │ │ ├── icon_back.png │ │ ├── icon_search.png │ │ ├── pic_1.jpg │ │ ├── pic_2.jpg │ │ ├── pic_3.jpg │ │ ├── pic_4.jpg │ │ └── x.png │ │ ├── drawable │ │ ├── btn_round.xml │ │ └── shape_bg.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── fragment_buffer.xml │ │ ├── fragment_checkbox_update.xml │ │ ├── fragment_concat.xml │ │ ├── fragment_loop.xml │ │ ├── fragment_main.xml │ │ ├── fragment_net.xml │ │ ├── fragment_not_more_click.xml │ │ ├── fragment_publish.xml │ │ ├── fragment_publish_bottom.xml │ │ ├── fragment_publish_top.xml │ │ ├── fragment_reuse_subscriber.xml │ │ ├── fragment_rxbus_bottom.xml │ │ ├── fragment_rxbus_demo.xml │ │ ├── fragment_rxbus_top.xml │ │ ├── fragment_search_text_change.xml │ │ ├── fragment_timer.xml │ │ ├── fragment_zip.xml │ │ ├── item_list.xml │ │ └── item_menu.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── attrs.xml │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── che58 │ └── ljb │ └── rxjava │ └── ExampleUnitTest.java ├── build.gradle ├── gif ├── PublishSubject.gif ├── Timer.gif ├── Zip操作符.gif ├── buffer.gif ├── checkbox.gif ├── interval.gif ├── merge.gif ├── rxbus.gif ├── rxjava+okhttp+gson.gif ├── rxjava+okhttp.gif └── searchword.gif ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | # built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # files for the dex VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # generated files 12 | bin/ 13 | gen/ 14 | build/ 15 | 16 | # Gradle files 17 | .gradle/ 18 | subProjects/facebook/build 19 | 20 | # Intellij project files 21 | .idea/libraries 22 | .idea/.name 23 | .idea/compiler.xml 24 | .idea/gradle.xml 25 | .idea/modules.xml 26 | .idea/runConfigurations.xml 27 | .idea/vcs.xml 28 | .idea/workspace.xml 29 | .idea/misc.xml 30 | gen-external-apklibs/ 31 | *.iml 32 | *.iws 33 | 34 | # Local configuration file (sdk path, etc) 35 | local.properties 36 | 37 | # Mac-specific stuff 38 | .DS_Store 39 | 40 | #Maven 41 | target 42 | release.properties 43 | pom.xml.* 44 | 45 | #Ant 46 | build.xml 47 | ant.properties 48 | profiles_settings.xml 49 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rxjava_for_android 2 | 3 | **Kotlin版本:**[https://github.com/cn-ljb/rxjava_for_kotlin](https://github.com/cn-ljb/rxjava_for_kotlin) 4 | 5 | 6 | Android平台上使用RxJava的Demo 7 | 8 | 感谢DevFactory的Mohamed Ezzat对代码的优化和建议 9 | 10 | 11 |
12 | 13 | ![](http://i.imgur.com/iWI5WxY.gif) 14 | ![](http://i.imgur.com/vjXS2pI.gif) 15 | 16 |
...
17 | ----------------------------------------------------------- 18 | 19 | 1、Rxjava是什么(异步库、响应式编程) 20 | 一个使用Java语言基于观察者模式拓展而来的高效异步库。 21 | 22 | 2、Rxjava能做什么(异步、灵活、高效) 23 | 首先我们需要明确,使用RxJava写出的功能,并不会说比普通的Java代码I在功能表现上有多么强大,那有什么卵用? ——异步、灵活、高效。 24 | 25 | 3、如何学习RxJava(耐心) 26 | 首先请调节好学习心态,RxJava并不是一个"拿来就能用"的项目,他需要我们像学习门新语言一样从语法-->词汇-->用法的学习过程,我们需要做的只是摆好心态,耐心的学习。 27 | 28 |


29 | ### 一、入门 30 | 如果你还没有接触过RxJava,下面这些文章可能会帮到你: 31 | 32 | [给 Android 开发者的 RxJava 详解 ](http://gank.io/post/560e15be2dca930e00da1083) ——扔物线 对RxJava的概念以及基本特性做了详细介绍 33 | 34 | 下面这些文章适合你跟着去敲,了解RxJava的基本语法: 35 | 36 | [深入浅出RxJava(一:基础篇)](http://blog.csdn.net/lzyzsd/article/details/41833541) 37 | 38 | [深入浅出RxJava ( 二:操作符 )](http://blog.csdn.net/lzyzsd/article/details/44094895) 39 | 40 | [深入浅出RxJava ( 三--响应式的好处 )](http://blog.csdn.net/lzyzsd/article/details/44891933) 41 | 42 | [深入浅出RxJava ( 四-在Android中使用响应式编程 )](http://blog.csdn.net/lzyzsd/article/details/45033611) 43 | 44 | ——hi大头鬼hi 45 | 46 | 47 | 如果你对RxJava的链式编程和代码结构感到好奇,下面这篇文章会从代码的角度给你带来惊喜: 48 | 49 | [NotRxJava懒人专用指南 ](http://www.devtf.cn/?p=323) 从代码的角度教你实现一个简易的RxJava库 50 | ——作者:Yaroslav Heriatovych 译者:Rocko 51 | 52 |


53 | ### 二、进阶 54 | 如果你已了解RxJava基本语法,并尝试着去练习,那么现在你需要熟悉更多的操作符,并理解它们的意思,在特定的场合使用它们去编写代码。 55 | 56 | 操作符介绍:[ReactiveX中文翻译文档](https://mcxiaoke.gitbooks.io/rxdocs/content/index.html) 57 | 58 | 以下是网上收集到的RxJava操作符在某些场景下的使用: 59 | 60 | [RxJava使用场景小结](http://blog.csdn.net/theone10211024/article/details/50435325) ——THEONE10211024 61 | 62 | [RxJava使用场景小结 ](http://blog.csdn.net/lzyzsd/article/details/50120801) ——hi大头鬼hi 63 | 64 | [RxJava-Android-Samples ](https://github.com/kaushikgopal/RxJava-Android-Samples) ——kaushikgopal 65 | 66 | 67 |
以下是本人在工作之余写的Demo 68 | 69 | [rxjava-for-android](https://github.com/cn-ljb/rxjava_for_android) 70 | 71 | [(一)RxJava在Android网络框架中的使用](http://blog.csdn.net/qq1026291832/article/details/51006059) 72 | 73 | [(二)RxJava+RxBinding在View上的一些使用技巧](http://blog.csdn.net/qq1026291832/article/details/51006145) 74 | 75 | [(三)RxJava操作符:Buffer](http://blog.csdn.net/qq1026291832/article/details/51006385) 76 | 77 | [(四)RxJava操作符:zip数据合并操作](http://blog.csdn.net/qq1026291832/article/details/51006451) 78 | 79 | [(五)RxJava操作符:merge合并操作符](http://blog.csdn.net/qq1026291832/article/details/51006538) 80 | 81 | [(六)RxJava轮询器:interval](http://blog.csdn.net/qq1026291832/article/details/51006613) 82 | 83 | [(七)RxJava定时器:timer](http://blog.csdn.net/qq1026291832/article/details/51006705) 84 | 85 | [(八)RxJava:PublishSubject](http://blog.csdn.net/qq1026291832/article/details/51006746) 86 | 87 | [(九)RxJava:RxBus](http://blog.csdn.net/qq1026291832/article/details/51006825) 88 | 89 | [(十)【续】网络层(RxJava+OkHttp+Gson)](http://blog.csdn.net/qq1026291832/article/details/51084960) 90 | 91 |


92 | ### 三、 其他可能对你有所帮助的资料 93 | 94 | [那些年我们错过的响应式编程](http://www.devtf.cn/?p=174) ——很详细的介绍什么是响应式编程 95 | 96 | [使用RxJava.Observable取代AsyncTask和AsyncTaskLoader](http://www.devtf.cn/?p=114) ——通过比较介绍RxJava在异步处理上的优势 97 | 98 | [RxJava部分操作符介绍 ](http://mushuichuan.com/tags/RxJava/) ——水木川博客 99 | 100 | [Awesome-RxJava](https://github.com/lzyzsd/Awesome-RxJava) ——hi大头鬼hi RxJava资源的总结分享 101 | 102 | ##### 值得一读的文章: 103 | 104 | [给创业码农的话--如何提升开发效率](http://mp.weixin.qq.com/s?__biz=MzAwNDY1ODY2OQ==&mid=400785752&idx=1&sn=e1c166e7fad0892811c9ca9bca6d1540&scene=23&srcid=0329Nz6yhFIZKbW9emQgjUlM#rd) 105 | 106 | [关于APK瘦身值得分享的一些经验](http://zmywly8866.github.io/2015/04/06/decrease-apk-size.html) 107 | 108 | [Android客户端性能优化](http://blog.csdn.net/yueqian_scut/article/details/50762649#comments) 109 | 110 | [zjutkz's blog](http://zjutkz.net/archives/ "http://zjutkz.net/archives/") 111 | 112 |


113 | ### 四、学习中可能会涉及到的库 114 | https://github.com/ReactiveX/RxJava ——RxJava核心库 115 | 116 | https://github.com/ReactiveX/RxAndroid ——RxJava在Android中使用的扩展库 117 | 118 | https://github.com/JakeWharton/RxBinding ——Android控件对RxJava的支持库 119 | 120 | https://github.com/f2prateek/rx-preferences ——使SharedPreferences支持 121 | RxJava 122 | 123 | https://github.com/trello/RxLifecycle ——帮助RxJava在Android中生命周期的控制,避免内存溢出等问题 124 | 125 | https://github.com/square/retrofit ——Retrofit 126 | 127 | https://github.com/pushtorefresh/storio ——数据库对RxJava的支持 128 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion '25.0.0' 6 | 7 | defaultConfig { 8 | applicationId "com.che58.ljb.rxjava" 9 | minSdkVersion 15 10 | targetSdkVersion 23 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(include: ['*.jar'], dir: 'libs') 24 | testCompile 'junit:junit:4.12' 25 | compile 'com.jakewharton:butterknife:7.0.1' 26 | compile 'com.android.support:appcompat-v7:23.2.0' 27 | compile 'io.reactivex:rxjava:1.0.14' 28 | compile 'io.reactivex:rxandroid:1.1.0' 29 | compile 'com.f2prateek.rx.preferences:rx-preferences:1.0.1' 30 | compile 'com.squareup.okhttp:okhttp:2.7.2' 31 | compile 'com.squareup.okio:okio:1.6.0' 32 | compile 'com.google.code.gson:gson:2.5' 33 | compile 'com.jakewharton.rxbinding:rxbinding:0.4.0' 34 | compile 'com.trello:rxlifecycle:0.4.0' 35 | compile 'com.trello:rxlifecycle-components:0.4.0' 36 | compile 'com.github.bumptech.glide:glide:3.6.1' 37 | } 38 | -------------------------------------------------------------------------------- /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 D:\Android\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/che58/ljb/rxjava/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.che58.ljb.rxjava; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 14 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/che58/ljb/rxjava/DemoApplication.java: -------------------------------------------------------------------------------- 1 | package com.che58.ljb.rxjava; 2 | 3 | import android.app.Application; 4 | 5 | /** 6 | * Demo Application 7 | * Created by ljb on 2016/3/23. 8 | */ 9 | public class DemoApplication extends Application { 10 | 11 | private static Application mApp; 12 | 13 | @Override 14 | public void onCreate() { 15 | super.onCreate(); 16 | mApp = this; 17 | } 18 | 19 | public static Application getApplaction(){ 20 | return mApp; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/che58/ljb/rxjava/act/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.che58.ljb.rxjava.act; 2 | 3 | import android.os.Bundle; 4 | 5 | import com.che58.ljb.rxjava.R; 6 | import com.che58.ljb.rxjava.fragment.main.MainFragment; 7 | import com.che58.ljb.rxjava.rxbus.RxBus; 8 | import com.trello.rxlifecycle.components.support.RxFragmentActivity; 9 | 10 | public class MainActivity extends RxFragmentActivity { 11 | 12 | private RxBus _rxBus; 13 | 14 | /**获取RxBus对象*/ 15 | public RxBus getRxBusSingleton() { 16 | if (_rxBus == null) { 17 | _rxBus = new RxBus(); 18 | } 19 | return _rxBus; 20 | } 21 | 22 | @Override 23 | protected void onCreate(Bundle savedInstanceState) { 24 | super.onCreate(savedInstanceState); 25 | setContentView(R.layout.activity_main); 26 | initFragment(); 27 | } 28 | 29 | private void initFragment() { 30 | getSupportFragmentManager().beginTransaction() 31 | .replace(R.id.main_content, new MainFragment(), MainFragment.class.getName()) 32 | .commit(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/java/com/che58/ljb/rxjava/fragment/BufferFragment.java: -------------------------------------------------------------------------------- 1 | package com.che58.ljb.rxjava.fragment; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.Button; 9 | import android.widget.EditText; 10 | import android.widget.TextView; 11 | import android.widget.Toast; 12 | 13 | import com.che58.ljb.rxjava.R; 14 | import com.jakewharton.rxbinding.view.RxView; 15 | import com.trello.rxlifecycle.components.support.RxFragment; 16 | 17 | import java.util.List; 18 | 19 | import butterknife.Bind; 20 | import butterknife.ButterKnife; 21 | import butterknife.OnClick; 22 | import rx.Observable; 23 | import rx.android.schedulers.AndroidSchedulers; 24 | import rx.functions.Action1; 25 | 26 | /** 27 | * Buffer操作符 28 | * Created by ljb on 2016/3/25. 29 | */ 30 | public class BufferFragment extends RxFragment { 31 | 32 | @Bind(R.id.btn_buffer_count) 33 | Button btn_buffer_count; 34 | 35 | @Bind(R.id.btn_buffer_count_skip) 36 | Button btn_buffer_count_skip; 37 | 38 | @Bind(R.id.et_input) 39 | EditText et_input; 40 | 41 | @Bind(R.id.tv_output) 42 | TextView tv_output; 43 | 44 | @Nullable 45 | @Override 46 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 47 | View view = inflater.inflate(R.layout.fragment_buffer, null); 48 | ButterKnife.bind(this, view); 49 | return view; 50 | } 51 | 52 | 53 | @Override 54 | public void onActivityCreated(@Nullable Bundle savedInstanceState) { 55 | super.onActivityCreated(savedInstanceState); 56 | demo_buffer_count(); 57 | } 58 | 59 | private void demo_buffer_count() { 60 | RxView.clicks(btn_buffer_count) 61 | .buffer(3) 62 | .compose(this.>bindToLifecycle()) 63 | .observeOn(AndroidSchedulers.mainThread()) 64 | .subscribe(new Action1>() { 65 | @Override 66 | public void call(List voids) { 67 | Toast.makeText(BufferFragment.this.getActivity(), R.string.des_demo_buffer_count, Toast.LENGTH_SHORT).show(); 68 | } 69 | }); 70 | } 71 | 72 | @OnClick(R.id.btn_buffer_count_skip) 73 | void demo_buffer_count_skip() { 74 | tv_output.setText(""); 75 | char[] cs = et_input.getText().toString().trim().toCharArray(); 76 | Character[] chs = new Character[cs.length]; 77 | for (int i = 0; i < chs.length; i++) { 78 | chs[i] = cs[i]; 79 | } 80 | 81 | Observable.from(chs) 82 | .buffer(2, 3) 83 | .compose(this.>bindToLifecycle()) 84 | .observeOn(AndroidSchedulers.mainThread()) 85 | .subscribe(new Action1>() { 86 | 87 | @Override 88 | public void call(List characters) { 89 | tv_output.setText(tv_output.getText() + characters.toString()); 90 | } 91 | }); 92 | 93 | 94 | } 95 | 96 | 97 | } 98 | -------------------------------------------------------------------------------- /app/src/main/java/com/che58/ljb/rxjava/fragment/CheckBoxUpdateFragment.java: -------------------------------------------------------------------------------- 1 | package com.che58.ljb.rxjava.fragment; 2 | 3 | import android.content.SharedPreferences; 4 | import android.os.Bundle; 5 | import android.preference.PreferenceManager; 6 | import android.support.annotation.Nullable; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.Button; 11 | import android.widget.CheckBox; 12 | import android.widget.Toast; 13 | 14 | import com.che58.ljb.rxjava.R; 15 | import com.f2prateek.rx.preferences.Preference; 16 | import com.f2prateek.rx.preferences.RxSharedPreferences; 17 | import com.jakewharton.rxbinding.widget.RxCompoundButton; 18 | import com.trello.rxlifecycle.components.support.RxFragment; 19 | 20 | import butterknife.Bind; 21 | import butterknife.ButterKnife; 22 | import butterknife.OnClick; 23 | import rx.functions.Action1; 24 | 25 | /** 26 | * 随着CheckBox状态发生改变UI而改变 27 | * Created by ljb on 2016/3/24. 28 | */ 29 | public class CheckBoxUpdateFragment extends RxFragment { 30 | 31 | @Bind(R.id.cb_1) 32 | CheckBox checkBox1; 33 | 34 | @Bind(R.id.cb_2) 35 | CheckBox checkBox2; 36 | 37 | @Bind(R.id.btn_login) 38 | Button btn_login; 39 | 40 | @Nullable 41 | @Override 42 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 43 | View view = inflater.inflate(R.layout.fragment_checkbox_update, null); 44 | ButterKnife.bind(this, view); 45 | return view; 46 | } 47 | 48 | @Override 49 | public void onActivityCreated(@Nullable Bundle savedInstanceState) { 50 | super.onActivityCreated(savedInstanceState); 51 | check_update1(); 52 | check_update2(); 53 | } 54 | 55 | /** 56 | * 同步SharedPreferences 57 | */ 58 | private void check_update1() { 59 | SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity()); 60 | RxSharedPreferences rxPreferences = RxSharedPreferences.create(preferences); 61 | Preference xxFunction = rxPreferences.getBoolean("xxFunction", false); 62 | 63 | checkBox1.setChecked(xxFunction.get()); 64 | 65 | RxCompoundButton.checkedChanges(checkBox1) 66 | .subscribe(xxFunction.asAction()); 67 | } 68 | 69 | /** 70 | * 同步UI 71 | */ 72 | private void check_update2() { 73 | RxCompoundButton.checkedChanges(checkBox2) 74 | .subscribe(new Action1() { 75 | @Override 76 | public void call(Boolean aBoolean) { 77 | btn_login.setClickable(aBoolean); 78 | btn_login.setBackgroundResource(aBoolean ? R.color.can_login : R.color.not_login); 79 | } 80 | }); 81 | } 82 | 83 | @OnClick(R.id.btn_login) 84 | void login(){ 85 | Toast.makeText(getActivity(), R.string.login, Toast.LENGTH_SHORT).show(); 86 | } 87 | 88 | 89 | } 90 | -------------------------------------------------------------------------------- /app/src/main/java/com/che58/ljb/rxjava/fragment/ConcatFragment.java: -------------------------------------------------------------------------------- 1 | package com.che58.ljb.rxjava.fragment; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.ArrayAdapter; 9 | import android.widget.ListView; 10 | 11 | import com.che58.ljb.rxjava.R; 12 | import com.che58.ljb.rxjava.model.Contacter; 13 | import com.che58.ljb.rxjava.utils.XgoLog; 14 | import com.che58.ljb.rxjava.view.ProgressWheel; 15 | import com.trello.rxlifecycle.components.support.RxFragment; 16 | 17 | import java.util.ArrayList; 18 | import java.util.List; 19 | 20 | import butterknife.Bind; 21 | import butterknife.ButterKnife; 22 | import rx.Observable; 23 | import rx.Subscriber; 24 | import rx.android.schedulers.AndroidSchedulers; 25 | import rx.functions.Action0; 26 | import rx.functions.Action1; 27 | import rx.schedulers.Schedulers; 28 | 29 | /** 30 | * contact操作符 31 | * 可以将多个Observables的输出合并,就好像它们是一个单个的Observable一样 32 | *

33 | * Demo:模拟先读取(1s)本地缓存数据,再读取(3s)网络数据 34 | * Created by zjh on 2016/3/26. 35 | */ 36 | public class ConcatFragment extends RxFragment { 37 | private static final String LOCATION = "location:"; 38 | private static final String NET = "net:"; 39 | 40 | @Bind(R.id.view_load) 41 | ProgressWheel loadView; 42 | 43 | @Bind(R.id.lv_list) 44 | ListView lv_list; 45 | 46 | @Nullable 47 | @Override 48 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 49 | View view = inflater.inflate(R.layout.fragment_concat, null); 50 | ButterKnife.bind(this, view); 51 | return view; 52 | } 53 | 54 | @Override 55 | public void onActivityCreated(@Nullable Bundle savedInstanceState) { 56 | super.onActivityCreated(savedInstanceState); 57 | concatDemo(); 58 | } 59 | 60 | 61 | private void concatDemo() { 62 | Observable.concat( 63 | getDataFromLocation(), 64 | getDataFromNet() 65 | ).compose(this.>bindToLifecycle()) 66 | .subscribeOn(Schedulers.io()) 67 | .observeOn(AndroidSchedulers.mainThread()) 68 | .subscribe(new Action1>() { 69 | @Override 70 | public void call(List contacters) { 71 | initPage(contacters); 72 | } 73 | }, new Action1() { 74 | @Override 75 | public void call(Throwable throwable) { 76 | XgoLog.e(throwable.getMessage()); 77 | } 78 | }, new Action0() { 79 | @Override 80 | public void call() { 81 | XgoLog.d("onCompleted()"); 82 | } 83 | }); 84 | 85 | } 86 | 87 | private void initPage(List contacters) { 88 | loadView.setVisibility(View.GONE); 89 | XgoLog.d(contacters.toString()); 90 | lv_list.setAdapter(new ArrayAdapter<>(getActivity(), R.layout.item_list, R.id.tv_text, contacters)); 91 | } 92 | 93 | private Observable> getDataFromNet() { 94 | return Observable.create(new Observable.OnSubscribe>() { 95 | @Override 96 | public void call(Subscriber> subscriber) { 97 | try { 98 | Thread.sleep(3000); 99 | } catch (InterruptedException e) { 100 | e.printStackTrace(); 101 | } 102 | 103 | ArrayList contacters = new ArrayList<>(); 104 | contacters.add(new Contacter(NET + "Zeus")); 105 | contacters.add(new Contacter(NET + "Athena")); 106 | contacters.add(new Contacter(NET + "Prometheus")); 107 | // subscriber.onError(new Throwable("模拟出错")); 108 | subscriber.onNext(contacters); 109 | subscriber.onCompleted(); 110 | } 111 | }); 112 | } 113 | 114 | 115 | private Observable> getDataFromLocation() { 116 | return Observable.create(new Observable.OnSubscribe>() { 117 | @Override 118 | public void call(Subscriber> subscriber) { 119 | try { 120 | Thread.sleep(1000); 121 | } catch (InterruptedException e) { 122 | e.printStackTrace(); 123 | } 124 | 125 | List datas = new ArrayList<>(); 126 | datas.add(new Contacter(LOCATION + "张三")); 127 | datas.add(new Contacter(LOCATION + "李四")); 128 | datas.add(new Contacter(LOCATION + "王五")); 129 | 130 | subscriber.onNext(datas); 131 | subscriber.onCompleted(); 132 | } 133 | }); 134 | } 135 | 136 | } 137 | -------------------------------------------------------------------------------- /app/src/main/java/com/che58/ljb/rxjava/fragment/DebounceFragment.java: -------------------------------------------------------------------------------- 1 | package com.che58.ljb.rxjava.fragment; 2 | 3 | import android.os.Bundle; 4 | import android.os.Looper; 5 | import android.os.SystemClock; 6 | import android.support.annotation.Nullable; 7 | import android.text.TextUtils; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.widget.AdapterView; 12 | import android.widget.ArrayAdapter; 13 | import android.widget.EditText; 14 | import android.widget.ImageView; 15 | import android.widget.ListView; 16 | import android.widget.Toast; 17 | 18 | import com.che58.ljb.rxjava.R; 19 | import com.che58.ljb.rxjava.utils.XgoLog; 20 | import com.jakewharton.rxbinding.widget.RxTextView; 21 | import com.jakewharton.rxbinding.widget.TextViewTextChangeEvent; 22 | import com.trello.rxlifecycle.components.support.RxFragment; 23 | 24 | import java.util.ArrayList; 25 | import java.util.List; 26 | import java.util.concurrent.TimeUnit; 27 | 28 | import butterknife.Bind; 29 | import butterknife.ButterKnife; 30 | import butterknife.OnClick; 31 | import rx.Observable; 32 | import rx.Subscriber; 33 | import rx.android.schedulers.AndroidSchedulers; 34 | import rx.functions.Action1; 35 | import rx.functions.Func1; 36 | import rx.schedulers.Schedulers; 37 | 38 | /** 39 | * RxJava实现搜索关键字推荐Demo 40 | * Created by ljb on 2016/3/24. 41 | */ 42 | public class DebounceFragment extends RxFragment { 43 | 44 | @Bind(R.id.et_search) 45 | EditText et_search; 46 | 47 | @Bind(R.id.iv_x) 48 | ImageView iv_x; 49 | 50 | @Bind(R.id.lv_list) 51 | ListView lv_list; 52 | private ArrayAdapter mAdapter; 53 | 54 | @Nullable 55 | @Override 56 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 57 | View view = inflater.inflate(R.layout.fragment_search_text_change, null); 58 | ButterKnife.bind(this, view); 59 | return view; 60 | } 61 | 62 | @Override 63 | public void onActivityCreated(@Nullable Bundle savedInstanceState) { 64 | super.onActivityCreated(savedInstanceState); 65 | searchKeyWordDemo(); 66 | } 67 | 68 | /** 69 | * 搜索关键字提醒Demo 70 | */ 71 | 72 | private void searchKeyWordDemo() { 73 | 74 | RxTextView.textChangeEvents(et_search) 75 | .debounce(150, TimeUnit.MILLISECONDS) //debounce:每次文本更改后有150毫秒的缓冲时间,默认在computation调度器 76 | .observeOn(AndroidSchedulers.mainThread()) 77 | .doOnNext(new Action1() { 78 | @Override 79 | public void call(TextViewTextChangeEvent textViewTextChangeEvent) { 80 | clearPage(textViewTextChangeEvent); 81 | } 82 | }) 83 | .filter(new Func1() { 84 | @Override 85 | public Boolean call(TextViewTextChangeEvent textViewTextChangeEvent) { 86 | return !TextUtils.isEmpty(textViewTextChangeEvent.text()); 87 | } 88 | }) 89 | .switchMap(new Func1>>() { 90 | @Override 91 | public Observable> call(TextViewTextChangeEvent textViewTextChangeEvent) { 92 | return getKeyWordFormNet(textViewTextChangeEvent.text().toString().trim()).subscribeOn(Schedulers.io()); 93 | } 94 | }) 95 | .observeOn(AndroidSchedulers.mainThread()) //触发后回到Android主线程调度器 96 | .subscribe(new Action1>() { 97 | @Override 98 | public void call(List strings) { 99 | initPage(strings); 100 | } 101 | }, new Action1() { 102 | @Override 103 | public void call(Throwable throwable) { 104 | throwable.printStackTrace(); 105 | } 106 | }); 107 | } 108 | 109 | private void clearPage(TextViewTextChangeEvent event) { 110 | String text = event.text().toString().trim(); 111 | if (mAdapter != null && TextUtils.isEmpty(text)) { 112 | mAdapter.clear(); 113 | mAdapter.notifyDataSetChanged(); 114 | } 115 | } 116 | 117 | 118 | private void initPage(List keyWords) { 119 | XgoLog.d("data::" + keyWords.toString()); 120 | if (mAdapter == null) { 121 | mAdapter = new ArrayAdapter<>(getActivity(), R.layout.item_list, R.id.tv_text, keyWords); 122 | lv_list.setAdapter(mAdapter); 123 | lv_list.setOnItemClickListener(itemClick()); 124 | } else { 125 | mAdapter.clear(); 126 | mAdapter.addAll(keyWords); 127 | mAdapter.notifyDataSetChanged(); 128 | } 129 | } 130 | 131 | private AdapterView.OnItemClickListener itemClick() { 132 | return new AdapterView.OnItemClickListener() { 133 | @Override 134 | public void onItemClick(AdapterView parent, View view, int position, long id) { 135 | Toast.makeText(DebounceFragment.this.getActivity(), "搜索:" + mAdapter.getItem(position), Toast.LENGTH_SHORT).show(); 136 | } 137 | }; 138 | } 139 | 140 | 141 | /** 142 | * 模拟网路接口获取匹配到的关键字列表 143 | */ 144 | private Observable> getKeyWordFormNet(final String key) { 145 | return Observable.create(new Observable.OnSubscribe>() { 146 | @Override 147 | public void call(Subscriber> subscriber) { 148 | 149 | boolean b = Thread.currentThread() == Looper.getMainLooper().getThread(); 150 | XgoLog.d("IO线程::" + !b); 151 | 152 | SystemClock.sleep(500); 153 | //这里是网络请求操作... 154 | List datas = new ArrayList<>(); 155 | for (int i = 0; i < 10; i++) { 156 | datas.add("KeyWord:" + key + i); 157 | } 158 | subscriber.onNext(datas); 159 | subscriber.onCompleted(); 160 | } 161 | }); 162 | } 163 | 164 | @OnClick(R.id.iv_x) 165 | void clear() { 166 | et_search.setText(""); 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /app/src/main/java/com/che58/ljb/rxjava/fragment/LoopFragment.java: -------------------------------------------------------------------------------- 1 | package com.che58.ljb.rxjava.fragment; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.v4.view.PagerAdapter; 7 | import android.support.v4.view.ViewPager; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.view.animation.Interpolator; 12 | import android.widget.ImageView; 13 | import android.widget.Scroller; 14 | 15 | import com.che58.ljb.rxjava.R; 16 | import com.trello.rxlifecycle.components.support.RxFragment; 17 | 18 | import java.lang.reflect.Field; 19 | import java.util.ArrayList; 20 | import java.util.List; 21 | import java.util.concurrent.TimeUnit; 22 | 23 | import butterknife.Bind; 24 | import butterknife.ButterKnife; 25 | import butterknife.OnClick; 26 | import rx.Observable; 27 | import rx.Subscription; 28 | import rx.android.schedulers.AndroidSchedulers; 29 | import rx.functions.Action1; 30 | 31 | /** 32 | * 轮询器Demo 33 | * Created by ljb on 2016/3/28. 34 | */ 35 | public class LoopFragment extends RxFragment { 36 | @Bind(R.id.viewpager) 37 | ViewPager mViewPager; 38 | 39 | private static final int[] DATAS = new int[]{R.drawable.pic_1, R.drawable.pic_2, R.drawable.pic_3}; 40 | private PicLoopAdapter loopAdapter; 41 | private Subscription subscribe_auto; 42 | 43 | @Nullable 44 | @Override 45 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 46 | View view = inflater.inflate(R.layout.fragment_loop, null); 47 | ButterKnife.bind(this, view); 48 | return view; 49 | } 50 | 51 | @Override 52 | public void onActivityCreated(@Nullable Bundle savedInstanceState) { 53 | super.onActivityCreated(savedInstanceState); 54 | initViewPager(); 55 | startLoop(); 56 | } 57 | 58 | 59 | @Override 60 | public void onDestroy() { 61 | super.onDestroy(); 62 | stopLoop(); 63 | } 64 | 65 | @OnClick(R.id.btn_start_loop) 66 | void startLoop() { 67 | autoLoop(); 68 | } 69 | 70 | @OnClick(R.id.btn_stop_loop) 71 | void stopLoop() { 72 | if (subscribe_auto != null && !subscribe_auto.isUnsubscribed()) { 73 | subscribe_auto.unsubscribe(); 74 | } 75 | } 76 | 77 | private void autoLoop() { 78 | if (subscribe_auto == null || subscribe_auto.isUnsubscribed()) { 79 | subscribe_auto = Observable.interval(3000, 3000, TimeUnit.MILLISECONDS) 80 | //延时3000 ,每间隔3000,时间单位 81 | .compose(this.bindToLifecycle()) 82 | .observeOn(AndroidSchedulers.mainThread()) 83 | .subscribe(new Action1() { 84 | @Override 85 | public void call(Long aLong) { 86 | int currentIndex = mViewPager.getCurrentItem(); 87 | if (++currentIndex == loopAdapter.getCount()) { 88 | mViewPager.setCurrentItem(0); 89 | } else { 90 | mViewPager.setCurrentItem(currentIndex, true); 91 | } 92 | } 93 | }); 94 | } 95 | } 96 | 97 | private void initViewPager() { 98 | loopAdapter = new PicLoopAdapter(DATAS); 99 | mViewPager.setAdapter(loopAdapter); 100 | 101 | try { 102 | //自定义滑动速度 103 | Field mScrollerField = ViewPager.class.getDeclaredField("mScroller"); 104 | mScrollerField.setAccessible(true); 105 | mScrollerField.set(mViewPager, new ViewPagerScroller(mViewPager.getContext())); 106 | } catch (NoSuchFieldException e) { 107 | e.printStackTrace(); 108 | } catch (IllegalAccessException e) { 109 | e.printStackTrace(); 110 | } 111 | } 112 | 113 | private class PicLoopAdapter extends PagerAdapter { 114 | 115 | private final int[] mDatas; 116 | private List mCacheViews = new ArrayList<>(); 117 | 118 | public PicLoopAdapter(int[] datas) { 119 | this.mDatas = datas; 120 | } 121 | 122 | @Override 123 | public int getCount() { 124 | return Integer.MAX_VALUE; 125 | } 126 | 127 | @Override 128 | public boolean isViewFromObject(View view, Object object) { 129 | return view == object; 130 | } 131 | 132 | @Override 133 | public View instantiateItem(ViewGroup container, int position) { 134 | int index = position % mDatas.length; 135 | ImageView iv; 136 | if (mCacheViews.size() > 0) { 137 | iv = mCacheViews.remove(0); 138 | } else { 139 | iv = new ImageView(getActivity()); 140 | iv.setLayoutParams(new ViewPager.LayoutParams()); 141 | iv.setScaleType(ImageView.ScaleType.CENTER_CROP); 142 | } 143 | 144 | iv.setImageResource(mDatas[index]); 145 | container.addView(iv); 146 | return iv; 147 | } 148 | 149 | @Override 150 | public void destroyItem(ViewGroup container, int position, Object object) { 151 | container.removeView((View) object); 152 | mCacheViews.add((ImageView) object); 153 | } 154 | } 155 | 156 | /** 157 | * 自定义Scroller,用于调节ViewPager滑动速度 158 | */ 159 | public class ViewPagerScroller extends Scroller { 160 | private static final int M_SCROLL_DURATION = 1200;// 滑动速度 161 | 162 | public ViewPagerScroller(Context context) { 163 | super(context); 164 | } 165 | 166 | public ViewPagerScroller(Context context, Interpolator interpolator) { 167 | super(context, interpolator); 168 | } 169 | 170 | public ViewPagerScroller(Context context, Interpolator interpolator, boolean flywheel) { 171 | super(context, interpolator, flywheel); 172 | } 173 | 174 | @Override 175 | public void startScroll(int startX, int startY, int dx, int dy, int duration) { 176 | super.startScroll(startX, startY, dx, dy, M_SCROLL_DURATION); 177 | } 178 | 179 | @Override 180 | public void startScroll(int startX, int startY, int dx, int dy) { 181 | super.startScroll(startX, startY, dx, dy, M_SCROLL_DURATION); 182 | } 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /app/src/main/java/com/che58/ljb/rxjava/fragment/Net2Fragment.java: -------------------------------------------------------------------------------- 1 | package com.che58.ljb.rxjava.fragment; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.TextView; 9 | 10 | import com.che58.ljb.rxjava.R; 11 | import com.che58.ljb.rxjava.model.DeleteModel; 12 | import com.che58.ljb.rxjava.model.GetModel; 13 | import com.che58.ljb.rxjava.model.PostModel; 14 | import com.che58.ljb.rxjava.model.PutModel; 15 | import com.che58.ljb.rxjava.protocol2.TestProtocol; 16 | import com.trello.rxlifecycle.components.support.RxFragment; 17 | 18 | import java.util.TreeMap; 19 | 20 | import butterknife.Bind; 21 | import butterknife.ButterKnife; 22 | import butterknife.OnClick; 23 | import rx.android.schedulers.AndroidSchedulers; 24 | import rx.functions.Action1; 25 | 26 | /** 27 | * RxJava+OkHttp+Gson 28 | * Created by ljb on 2016/4/7. 29 | */ 30 | public class Net2Fragment extends RxFragment { 31 | @Bind(R.id.tv_result) 32 | TextView tv_reuslt; 33 | 34 | @Bind(R.id.tv_msg) 35 | TextView tv_msg; 36 | 37 | private TestProtocol mTestProtocol; 38 | 39 | @Nullable 40 | @Override 41 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 42 | View view = inflater.inflate(R.layout.fragment_net, null); 43 | ButterKnife.bind(this, view); 44 | tv_msg.setText(R.string.des_demo_net2); 45 | return view; 46 | } 47 | 48 | @Override 49 | public void onActivityCreated(@Nullable Bundle savedInstanceState) { 50 | super.onActivityCreated(savedInstanceState); 51 | mTestProtocol = new TestProtocol(); 52 | } 53 | 54 | @OnClick(R.id.btn_get) 55 | void click_get() { 56 | mTestProtocol.testGet() 57 | .compose(this.bindToLifecycle()) 58 | .observeOn(AndroidSchedulers.mainThread()) 59 | .subscribe(new Action1() { 60 | @Override 61 | public void call(GetModel data) { 62 | tv_reuslt.setText("Get Result:\r\n" + data); 63 | } 64 | }, new Action1() { 65 | @Override 66 | public void call(Throwable throwable) { 67 | tv_reuslt.setText("Get Error:\r\n" + throwable.getMessage()); 68 | } 69 | }); 70 | } 71 | 72 | @OnClick(R.id.btn_post) 73 | void click_post() { 74 | TreeMap params = new TreeMap<>(); 75 | params.put("name", "Zeus"); 76 | mTestProtocol.testPost(params) 77 | .compose(this.bindToLifecycle()) 78 | .observeOn(AndroidSchedulers.mainThread()) 79 | .subscribe(new Action1() { 80 | @Override 81 | public void call(PostModel s) { 82 | tv_reuslt.setText("Post Result:\r\n" + s); 83 | } 84 | }, new Action1() { 85 | @Override 86 | public void call(Throwable throwable) { 87 | tv_reuslt.setText("Post Error:\r\n" + throwable.getMessage()); 88 | } 89 | }); 90 | } 91 | 92 | @OnClick(R.id.btn_put) 93 | void click_put() { 94 | TreeMap params = new TreeMap<>(); 95 | params.put("name", "Zeus"); 96 | mTestProtocol.testPut(params) 97 | .compose(this.bindToLifecycle()) 98 | .observeOn(AndroidSchedulers.mainThread()) 99 | .subscribe(new Action1() { 100 | @Override 101 | public void call(PutModel data) { 102 | tv_reuslt.setText("Put Result:\r\n" + data); 103 | } 104 | }, new Action1() { 105 | @Override 106 | public void call(Throwable throwable) { 107 | tv_reuslt.setText("Put Error:\r\n" + throwable.getMessage()); 108 | } 109 | }); 110 | } 111 | 112 | @OnClick(R.id.btn_delete) 113 | void click_delete() { 114 | mTestProtocol.testDelete() 115 | .compose(this.bindToLifecycle()) 116 | .observeOn(AndroidSchedulers.mainThread()) 117 | .subscribe(new Action1() { 118 | @Override 119 | public void call(DeleteModel data) { 120 | tv_reuslt.setText("Delete Result:\r\n" + data); 121 | } 122 | }, new Action1() { 123 | @Override 124 | public void call(Throwable throwable) { 125 | tv_reuslt.setText("Delete Error:\r\n" + throwable.getMessage()); 126 | } 127 | }); 128 | } 129 | 130 | } 131 | -------------------------------------------------------------------------------- /app/src/main/java/com/che58/ljb/rxjava/fragment/NetFragment.java: -------------------------------------------------------------------------------- 1 | package com.che58.ljb.rxjava.fragment; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.TextView; 9 | 10 | import com.che58.ljb.rxjava.R; 11 | import com.che58.ljb.rxjava.protocol.TestProtocol; 12 | import com.trello.rxlifecycle.components.support.RxFragment; 13 | 14 | import java.util.TreeMap; 15 | 16 | import butterknife.Bind; 17 | import butterknife.ButterKnife; 18 | import butterknife.OnClick; 19 | import rx.android.schedulers.AndroidSchedulers; 20 | import rx.functions.Action1; 21 | 22 | /** 23 | * RxJava网络请求Demo 24 | * Created by ljb on 2016/3/23. 25 | */ 26 | public class NetFragment extends RxFragment { 27 | 28 | @Bind(R.id.tv_result) 29 | TextView tv_reuslt; 30 | 31 | private TestProtocol mTestProtocol; 32 | 33 | @Nullable 34 | @Override 35 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 36 | View view = inflater.inflate(R.layout.fragment_net, null); 37 | ButterKnife.bind(this, view); 38 | return view; 39 | } 40 | 41 | @Override 42 | public void onActivityCreated(@Nullable Bundle savedInstanceState) { 43 | super.onActivityCreated(savedInstanceState); 44 | mTestProtocol = new TestProtocol(); 45 | } 46 | 47 | @OnClick(R.id.btn_get) 48 | void click_get() { 49 | mTestProtocol.testGet() // (1) 50 | .compose(this.bindToLifecycle()) // (2) 51 | .observeOn(AndroidSchedulers.mainThread()) // (3) 52 | .subscribe(new Action1() { // (4) 53 | @Override 54 | public void call(String data) { // (5) 55 | tv_reuslt.setText("Get Result:\r\n" + data); 56 | } 57 | }, new Action1() { 58 | @Override 59 | public void call(Throwable throwable) { // (6) 60 | tv_reuslt.setText("Get Error:\r\n" + throwable.getMessage()); 61 | } 62 | }); 63 | 64 | 65 | } 66 | 67 | @OnClick(R.id.btn_post) 68 | void click_post() { 69 | TreeMap params = new TreeMap<>(); 70 | params.put("name", "Zeus"); 71 | mTestProtocol.testPost(params) 72 | .compose(this.bindToLifecycle()) 73 | .observeOn(AndroidSchedulers.mainThread()) 74 | .subscribe(new Action1() { 75 | @Override 76 | public void call(String s) { 77 | tv_reuslt.setText("Post Result:\r\n" + s); 78 | } 79 | }, new Action1() { 80 | @Override 81 | public void call(Throwable throwable) { 82 | tv_reuslt.setText("Post Error:\r\n" + throwable.getMessage()); 83 | } 84 | }); 85 | } 86 | 87 | @OnClick(R.id.btn_put) 88 | void click_put() { 89 | TreeMap params = new TreeMap<>(); 90 | params.put("name", "Zeus"); 91 | mTestProtocol.testPut(params) 92 | .compose(this.bindToLifecycle()) 93 | .observeOn(AndroidSchedulers.mainThread()) 94 | .subscribe(new Action1() { 95 | @Override 96 | public void call(String data) { 97 | tv_reuslt.setText("Put Result:\r\n" + data); 98 | } 99 | }, new Action1() { 100 | @Override 101 | public void call(Throwable throwable) { 102 | tv_reuslt.setText("Put Error:\r\n" + throwable.getMessage()); 103 | } 104 | }); 105 | } 106 | 107 | @OnClick(R.id.btn_delete) 108 | void click_delete() { 109 | mTestProtocol.testDelete() 110 | .compose(this.bindToLifecycle()) 111 | .observeOn(AndroidSchedulers.mainThread()) 112 | .subscribe(new Action1() { 113 | @Override 114 | public void call(String data) { 115 | tv_reuslt.setText("Delete Result:\r\n" + data); 116 | } 117 | }, new Action1() { 118 | @Override 119 | public void call(Throwable throwable) { 120 | tv_reuslt.setText("Delete Error:\r\n" + throwable.getMessage()); 121 | } 122 | }); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /app/src/main/java/com/che58/ljb/rxjava/fragment/NotMoreClickFragment.java: -------------------------------------------------------------------------------- 1 | package com.che58.ljb.rxjava.fragment; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.Button; 9 | import android.widget.Toast; 10 | 11 | import com.che58.ljb.rxjava.R; 12 | import com.jakewharton.rxbinding.view.RxView; 13 | import com.trello.rxlifecycle.components.support.RxFragment; 14 | 15 | import java.util.concurrent.TimeUnit; 16 | 17 | import butterknife.Bind; 18 | import butterknife.ButterKnife; 19 | import rx.functions.Action1; 20 | 21 | /** 22 | * View防止连续点击Demo 23 | * Created by ljb on 2016/3/24. 24 | */ 25 | public class NotMoreClickFragment extends RxFragment { 26 | 27 | @Bind(R.id.btn_click) 28 | Button btn_click; 29 | 30 | @Nullable 31 | @Override 32 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 33 | View view = inflater.inflate(R.layout.fragment_not_more_click, null); 34 | ButterKnife.bind(this, view); 35 | return view; 36 | } 37 | 38 | @Override 39 | public void onActivityCreated(@Nullable Bundle savedInstanceState) { 40 | super.onActivityCreated(savedInstanceState); 41 | notMoreClick(); 42 | } 43 | 44 | /** 45 | * 3秒内不允许按钮多次点击 46 | * */ 47 | private void notMoreClick() { 48 | RxView.clicks(btn_click) 49 | .throttleFirst(3, TimeUnit.SECONDS) 50 | .subscribe(new Action1() { 51 | @Override 52 | public void call(Void aVoid) { 53 | Toast.makeText(getActivity(), R.string.des_demo_not_more_click, Toast.LENGTH_SHORT).show(); 54 | } 55 | }); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /app/src/main/java/com/che58/ljb/rxjava/fragment/PublishSubjectBottomFragment.java: -------------------------------------------------------------------------------- 1 | package com.che58.ljb.rxjava.fragment; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.TextView; 9 | 10 | import com.che58.ljb.rxjava.R; 11 | import com.trello.rxlifecycle.components.support.RxFragment; 12 | 13 | import butterknife.Bind; 14 | import butterknife.ButterKnife; 15 | import rx.Subscription; 16 | import rx.functions.Action1; 17 | import rx.subjects.PublishSubject; 18 | 19 | /** 20 | * PublishSubject Demo 底部Fragment 21 | * Created by ljb on 2016/3/28. 22 | */ 23 | public class PublishSubjectBottomFragment extends RxFragment { 24 | 25 | @Bind(R.id.tv_result) 26 | TextView tv_result; 27 | 28 | private final PublishSubject publishSubject; 29 | private Subscription mSubscribe; 30 | 31 | public PublishSubjectBottomFragment(PublishSubject publishSubject) { 32 | this.publishSubject = publishSubject; 33 | } 34 | 35 | @Nullable 36 | @Override 37 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 38 | View view = inflater.inflate(R.layout.fragment_publish_bottom, null); 39 | ButterKnife.bind(this, view); 40 | return view; 41 | } 42 | 43 | @Override 44 | public void onActivityCreated(@Nullable Bundle savedInstanceState) { 45 | super.onActivityCreated(savedInstanceState); 46 | initData(); 47 | } 48 | 49 | private void initData() { 50 | mSubscribe = publishSubject.subscribe(new Action1() { 51 | @Override 52 | public void call(String s) { 53 | tv_result.setText(s); 54 | } 55 | }); 56 | } 57 | 58 | @Override 59 | public void onDestroy() { 60 | super.onDestroy(); 61 | if (mSubscribe != null && !mSubscribe.isUnsubscribed()) { 62 | mSubscribe.unsubscribe(); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /app/src/main/java/com/che58/ljb/rxjava/fragment/PublishSubjectFragment.java: -------------------------------------------------------------------------------- 1 | package com.che58.ljb.rxjava.fragment; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | 9 | import com.che58.ljb.rxjava.R; 10 | import com.trello.rxlifecycle.components.support.RxFragment; 11 | 12 | import butterknife.ButterKnife; 13 | import rx.subjects.PublishSubject; 14 | 15 | /** 16 | * 可连接的Subject 17 | * 与普通的Subject不同,在订阅时并不立即触发订阅事件,而是允许我们在任意时刻手动调用onNext(),onError(),onCompleted来触发事件 18 | * Created by ljb on 2016/3/28. 19 | */ 20 | public class PublishSubjectFragment extends RxFragment { 21 | 22 | 23 | @Nullable 24 | @Override 25 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 26 | View view = inflater.inflate(R.layout.fragment_publish, null); 27 | ButterKnife.bind(this, view); 28 | return view; 29 | } 30 | 31 | @Override 32 | public void onActivityCreated(@Nullable Bundle savedInstanceState) { 33 | super.onActivityCreated(savedInstanceState); 34 | PublishSubject publishSubject = PublishSubject.create(); 35 | //不建议直接在构造方法里传递参数,我这里只是为了方便演示 36 | PublishSubjectTopFragment topFragment = new PublishSubjectTopFragment(publishSubject); 37 | PublishSubjectBottomFragment bottom_Fragment = new PublishSubjectBottomFragment(publishSubject); 38 | getActivity().getSupportFragmentManager() 39 | .beginTransaction() 40 | .replace(R.id.fl_top,topFragment, "top") 41 | .replace(R.id.fl_bottom, bottom_Fragment, "bottom") 42 | .commit(); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/java/com/che58/ljb/rxjava/fragment/PublishSubjectTopFragment.java: -------------------------------------------------------------------------------- 1 | package com.che58.ljb.rxjava.fragment; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.EditText; 9 | 10 | import com.che58.ljb.rxjava.R; 11 | import com.trello.rxlifecycle.components.support.RxFragment; 12 | 13 | import butterknife.Bind; 14 | import butterknife.ButterKnife; 15 | import butterknife.OnClick; 16 | import rx.subjects.PublishSubject; 17 | 18 | /** 19 | * PublishSubject Demo 顶部Fragment 20 | * Created by ljb on 2016/3/28. 21 | */ 22 | public class PublishSubjectTopFragment extends RxFragment { 23 | 24 | @Bind(R.id.et_input) 25 | EditText et_input; 26 | 27 | private final PublishSubject publishSubject; 28 | 29 | public PublishSubjectTopFragment(PublishSubject publishSubject) { 30 | this.publishSubject = publishSubject; 31 | } 32 | 33 | @Nullable 34 | @Override 35 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 36 | View view = inflater.inflate(R.layout.fragment_publish_top , null); 37 | ButterKnife.bind(this, view); 38 | return view; 39 | } 40 | 41 | @Override 42 | public void onActivityCreated(@Nullable Bundle savedInstanceState) { 43 | super.onActivityCreated(savedInstanceState); 44 | } 45 | 46 | @OnClick(R.id.btn_send) 47 | void sendToBottom(){ 48 | String result = et_input.getText().toString().trim(); 49 | publishSubject.onNext(result); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/java/com/che58/ljb/rxjava/fragment/ReuseSubscriberFragment.java: -------------------------------------------------------------------------------- 1 | package com.che58.ljb.rxjava.fragment; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.Toast; 9 | 10 | import com.che58.ljb.rxjava.R; 11 | import com.trello.rxlifecycle.components.support.RxFragment; 12 | 13 | import butterknife.ButterKnife; 14 | import butterknife.OnClick; 15 | import rx.Observable; 16 | import rx.Observer; 17 | import rx.android.schedulers.AndroidSchedulers; 18 | 19 | /** 20 | * 复用订阅者Demo 21 | * Created by ljb on 2016/4/29. 22 | */ 23 | public class ReuseSubscriberFragment extends RxFragment { 24 | 25 | 26 | private Observer mReuseSubscriber; 27 | 28 | @Nullable 29 | @Override 30 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 31 | View view = inflater.inflate(R.layout.fragment_reuse_subscriber, null); 32 | ButterKnife.bind(this, view); 33 | return view; 34 | } 35 | 36 | @Override 37 | public void onActivityCreated(@Nullable Bundle savedInstanceState) { 38 | super.onActivityCreated(savedInstanceState); 39 | initData(); 40 | } 41 | 42 | private void initData() { 43 | //订阅者 44 | mReuseSubscriber = new Observer() { 45 | @Override 46 | public void onCompleted() { 47 | 48 | } 49 | 50 | @Override 51 | public void onError(Throwable e) { 52 | 53 | } 54 | 55 | @Override 56 | public void onNext(Object data) { 57 | if (data.getClass() == Integer.class) { 58 | Toast.makeText(getActivity(), "The data from Btn1!", Toast.LENGTH_SHORT).show(); 59 | } else if (data.getClass() == String.class) { 60 | Toast.makeText(getActivity(), "The data from Btn2!", Toast.LENGTH_SHORT).show(); 61 | } 62 | } 63 | }; 64 | } 65 | 66 | //被观察者1 67 | @OnClick(R.id.btn1) 68 | void btn1() { 69 | Observable.just(1) 70 | .compose(this.bindToLifecycle()) 71 | .observeOn(AndroidSchedulers.mainThread()) 72 | .subscribe(mReuseSubscriber); 73 | } 74 | 75 | //被观察者2 76 | @OnClick(R.id.btn2) 77 | void btn2() { 78 | Observable.just("string") 79 | .compose(this.bindToLifecycle()) 80 | .observeOn(AndroidSchedulers.mainThread()) 81 | .subscribe(mReuseSubscriber); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /app/src/main/java/com/che58/ljb/rxjava/fragment/TimerFragment.java: -------------------------------------------------------------------------------- 1 | package com.che58.ljb.rxjava.fragment; 2 | 3 | import android.animation.ObjectAnimator; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.ImageView; 10 | 11 | import com.che58.ljb.rxjava.R; 12 | import com.trello.rxlifecycle.components.support.RxFragment; 13 | 14 | import java.util.concurrent.TimeUnit; 15 | 16 | import butterknife.Bind; 17 | import butterknife.ButterKnife; 18 | import rx.Observable; 19 | import rx.android.schedulers.AndroidSchedulers; 20 | import rx.functions.Action1; 21 | 22 | /** 23 | * RxJava定时器 24 | * Created by ljb on 2016/3/28. 25 | */ 26 | public class TimerFragment extends RxFragment { 27 | 28 | @Bind(R.id.iv_welcome) 29 | ImageView iv_welcome; 30 | 31 | @Nullable 32 | @Override 33 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 34 | View view = inflater.inflate(R.layout.fragment_timer, null); 35 | ButterKnife.bind(this, view); 36 | return view; 37 | } 38 | 39 | @Override 40 | public void onActivityCreated(@Nullable Bundle savedInstanceState) { 41 | super.onActivityCreated(savedInstanceState); 42 | starTimer(); 43 | } 44 | 45 | 46 | 47 | private void starTimer() { 48 | Observable.timer(3000 , TimeUnit.MILLISECONDS) 49 | .observeOn(AndroidSchedulers.mainThread()) 50 | .compose(this.bindToLifecycle()) 51 | .subscribe(new Action1() { 52 | @Override 53 | public void call(Long aLong) { 54 | iv_welcome.setVisibility(View.VISIBLE); 55 | ObjectAnimator 56 | .ofFloat(iv_welcome, "alpha", 0.0F, 1.0F) 57 | .setDuration(500) 58 | .start(); 59 | } 60 | }); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /app/src/main/java/com/che58/ljb/rxjava/fragment/ZipFragment.java: -------------------------------------------------------------------------------- 1 | package com.che58.ljb.rxjava.fragment; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.ArrayAdapter; 9 | import android.widget.ListView; 10 | 11 | import com.che58.ljb.rxjava.R; 12 | import com.che58.ljb.rxjava.model.Contacter; 13 | import com.che58.ljb.rxjava.utils.XgoLog; 14 | import com.che58.ljb.rxjava.view.ProgressWheel; 15 | import com.trello.rxlifecycle.components.support.RxFragment; 16 | 17 | import java.util.ArrayList; 18 | import java.util.List; 19 | 20 | import butterknife.Bind; 21 | import butterknife.ButterKnife; 22 | import rx.Observable; 23 | import rx.Subscriber; 24 | import rx.android.schedulers.AndroidSchedulers; 25 | import rx.functions.Action1; 26 | import rx.functions.Func2; 27 | import rx.schedulers.Schedulers; 28 | 29 | /** 30 | * Zip数据合并操作 31 | * Created by ljb on 2016/3/25. 32 | */ 33 | public class ZipFragment extends RxFragment { 34 | 35 | @Bind(R.id.view_load) 36 | ProgressWheel loadView; 37 | 38 | @Bind(R.id.lv_list) 39 | ListView lv_list; 40 | 41 | @Nullable 42 | @Override 43 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 44 | View view = inflater.inflate(R.layout.fragment_zip, null); 45 | ButterKnife.bind(this, view); 46 | return view; 47 | } 48 | 49 | @Override 50 | public void onActivityCreated(@Nullable Bundle savedInstanceState) { 51 | super.onActivityCreated(savedInstanceState); 52 | getContactData(); 53 | } 54 | 55 | private void getContactData() { 56 | Observable.zip( 57 | queryContactsFromLocation(), 58 | queryContactsForNet(), 59 | new Func2, List, List>() { 60 | @Override 61 | public List call(List contacters, List contacters2) { 62 | contacters.addAll(contacters2); 63 | return contacters; 64 | } 65 | } 66 | ).compose(this.>bindToLifecycle()) 67 | .subscribeOn(Schedulers.io()) 68 | .observeOn(AndroidSchedulers.mainThread()) 69 | .subscribe(new Action1>() { 70 | @Override 71 | public void call(List contacters) { 72 | initPage(contacters); 73 | } 74 | }); 75 | } 76 | 77 | private void initPage(List contacters) { 78 | loadView.setVisibility(View.GONE); 79 | XgoLog.d(contacters.toString()); 80 | lv_list.setAdapter(new ArrayAdapter(getActivity(), R.layout.item_list, R.id.tv_text, contacters)); 81 | } 82 | 83 | 84 | /** 85 | * 模拟网络联系人列表 86 | */ 87 | private Observable> queryContactsForNet() { 88 | return Observable.create(new Observable.OnSubscribe>() { 89 | @Override 90 | public void call(Subscriber> subscriber) { 91 | 92 | try { 93 | Thread.sleep(3000); 94 | } catch (InterruptedException e) { 95 | e.printStackTrace(); 96 | } 97 | 98 | ArrayList contacters = new ArrayList<>(); 99 | contacters.add(new Contacter("net:Zeus")); 100 | contacters.add(new Contacter("net:Athena")); 101 | contacters.add(new Contacter("net:Prometheus")); 102 | subscriber.onNext(contacters); 103 | subscriber.onCompleted(); 104 | } 105 | }); 106 | } 107 | 108 | /** 109 | * 模拟手机本地联系人查询 110 | */ 111 | private Observable> queryContactsFromLocation() { 112 | return Observable.create(new Observable.OnSubscribe>() { 113 | @Override 114 | public void call(Subscriber> subscriber) { 115 | 116 | ArrayList contacters = new ArrayList<>(); 117 | contacters.add(new Contacter("location:张三")); 118 | contacters.add(new Contacter("location:李四")); 119 | contacters.add(new Contacter("location:王五")); 120 | subscriber.onNext(contacters); 121 | subscriber.onCompleted(); 122 | } 123 | }); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /app/src/main/java/com/che58/ljb/rxjava/fragment/main/MainFragment.java: -------------------------------------------------------------------------------- 1 | package com.che58.ljb.rxjava.fragment.main; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v4.app.Fragment; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | 10 | import com.che58.ljb.rxjava.R; 11 | import com.che58.ljb.rxjava.fragment.BufferFragment; 12 | import com.che58.ljb.rxjava.fragment.CheckBoxUpdateFragment; 13 | import com.che58.ljb.rxjava.fragment.LoopFragment; 14 | import com.che58.ljb.rxjava.fragment.ConcatFragment; 15 | import com.che58.ljb.rxjava.fragment.Net2Fragment; 16 | import com.che58.ljb.rxjava.fragment.PublishSubjectFragment; 17 | import com.che58.ljb.rxjava.fragment.ReuseSubscriberFragment; 18 | import com.che58.ljb.rxjava.fragment.TimerFragment; 19 | import com.che58.ljb.rxjava.fragment.ZipFragment; 20 | import com.che58.ljb.rxjava.fragment.NetFragment; 21 | import com.che58.ljb.rxjava.fragment.NotMoreClickFragment; 22 | import com.che58.ljb.rxjava.fragment.DebounceFragment; 23 | import com.che58.ljb.rxjava.rxbus.RxBusDemoFragment; 24 | 25 | import butterknife.ButterKnife; 26 | import butterknife.OnClick; 27 | 28 | /** 29 | * 主菜单Fragment 30 | * Created by ljb on 2016/3/23. 31 | */ 32 | public class MainFragment extends Fragment { 33 | 34 | @Nullable 35 | @Override 36 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 37 | View view = inflater.inflate(R.layout.fragment_main, null); 38 | ButterKnife.bind(this, view); 39 | return view; 40 | } 41 | 42 | @OnClick(R.id.btn_net) 43 | void btn_net() { 44 | open(new NetFragment()); 45 | } 46 | 47 | @OnClick(R.id.btn_net2) 48 | void btn_net2() { 49 | open(new Net2Fragment()); 50 | } 51 | 52 | @OnClick(R.id.btn_not_more_click) 53 | void btn_not_more_click() { 54 | open(new NotMoreClickFragment()); 55 | } 56 | 57 | @OnClick(R.id.btn_checkbox_state_update) 58 | void btn_checkbox_update() { 59 | open(new CheckBoxUpdateFragment()); 60 | } 61 | 62 | @OnClick(R.id.btn_text_change) 63 | void btn_text_change() { 64 | open(new DebounceFragment()); 65 | } 66 | 67 | @OnClick(R.id.btn_buffer) 68 | void btn_buffer() { 69 | open(new BufferFragment()); 70 | } 71 | 72 | @OnClick(R.id.btn_zip) 73 | void btn_zip() { 74 | open(new ZipFragment()); 75 | } 76 | 77 | @OnClick(R.id.btn_concat) 78 | void btn_concat() { 79 | open(new ConcatFragment()); 80 | } 81 | 82 | @OnClick(R.id.btn_loop) 83 | void btn_loop() { 84 | open(new LoopFragment()); 85 | } 86 | 87 | @OnClick(R.id.btn_timer) 88 | void btn_timer() { 89 | open(new TimerFragment()); 90 | } 91 | 92 | @OnClick(R.id.btn_publish) 93 | void btn_publish() { 94 | open(new PublishSubjectFragment()); 95 | } 96 | 97 | @OnClick(R.id.btn_rxbus) 98 | void btn_rxbus() { 99 | open(new RxBusDemoFragment()); 100 | } 101 | 102 | @OnClick(R.id.btn_reuse_subscriber) 103 | void btn_reuseSubscriber(){ 104 | open(new ReuseSubscriberFragment()); 105 | } 106 | /** 107 | * 开启新的Fragment 108 | */ 109 | private void open(Fragment fragment) { 110 | final String tag = fragment.getClass().getName(); 111 | getActivity().getSupportFragmentManager() 112 | .beginTransaction() 113 | .addToBackStack(tag) 114 | .replace(R.id.main_content, fragment, tag) 115 | .commit(); 116 | } 117 | 118 | } 119 | -------------------------------------------------------------------------------- /app/src/main/java/com/che58/ljb/rxjava/model/Contacter.java: -------------------------------------------------------------------------------- 1 | package com.che58.ljb.rxjava.model; 2 | 3 | /** 4 | * Created by ljb on 2016/3/17. 5 | */ 6 | public class Contacter { 7 | 8 | private String name; 9 | 10 | public Contacter(String name) { 11 | this.name = name; 12 | } 13 | 14 | public String getName() { 15 | return name; 16 | } 17 | 18 | public void setName(String name) { 19 | this.name = name; 20 | } 21 | 22 | @Override 23 | public String toString() { 24 | return "Contacter{" + 25 | "name='" + name + '\'' + 26 | '}'; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/java/com/che58/ljb/rxjava/model/DeleteModel.java: -------------------------------------------------------------------------------- 1 | package com.che58.ljb.rxjava.model; 2 | 3 | /** 4 | * Created by ljb on 2016/4/7. 5 | */ 6 | public class DeleteModel { 7 | private int code; 8 | private String message; 9 | private XgoEntity entity; 10 | 11 | private class XgoEntity { 12 | private Data data; 13 | 14 | private class Data { 15 | private int id; 16 | private String name; 17 | private String value; 18 | private Links links; 19 | 20 | @Override 21 | public String toString() { 22 | return "Data{" + 23 | "id=" + id + 24 | ", name='" + name + '\'' + 25 | ", value='" + value + '\'' + 26 | ", links=" + links + 27 | '}'; 28 | } 29 | 30 | private class Links { 31 | private String rel; 32 | private String href; 33 | 34 | @Override 35 | public String toString() { 36 | return "Links{" + 37 | "rel='" + rel + '\'' + 38 | ", href='" + href + '\'' + 39 | '}'; 40 | } 41 | } 42 | } 43 | 44 | @Override 45 | public String toString() { 46 | return "XgoEntity{" + 47 | "data=" + data + 48 | '}'; 49 | } 50 | } 51 | 52 | @Override 53 | public String toString() { 54 | return "DeleteModel{" + 55 | "code=" + code + 56 | ", message='" + message + '\'' + 57 | ", entity=" + entity + 58 | '}'; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /app/src/main/java/com/che58/ljb/rxjava/model/GetModel.java: -------------------------------------------------------------------------------- 1 | package com.che58.ljb.rxjava.model; 2 | 3 | /** 4 | * Get数据 JavaBean 5 | * Created by ljb on 2016/4/7. 6 | */ 7 | public class GetModel { 8 | private int code; 9 | private String message; 10 | private XgoEntity entity; 11 | 12 | private class XgoEntity { 13 | private Data data; 14 | 15 | private class Data { 16 | private int id; 17 | private String name; 18 | private String value; 19 | private Links links; 20 | 21 | @Override 22 | public String toString() { 23 | return "Data{" + 24 | "id=" + id + 25 | ", name='" + name + '\'' + 26 | ", value='" + value + '\'' + 27 | ", links=" + links + 28 | '}'; 29 | } 30 | 31 | private class Links { 32 | private String rel; 33 | private String href; 34 | 35 | @Override 36 | public String toString() { 37 | return "Links{" + 38 | "rel='" + rel + '\'' + 39 | ", href='" + href + '\'' + 40 | '}'; 41 | } 42 | } 43 | } 44 | 45 | @Override 46 | public String toString() { 47 | return "XgoEntity{" + 48 | "data=" + data + 49 | '}'; 50 | } 51 | } 52 | 53 | @Override 54 | public String toString() { 55 | return "PostModel{" + 56 | "code=" + code + 57 | ", message='" + message + '\'' + 58 | ", entity=" + entity + 59 | '}'; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /app/src/main/java/com/che58/ljb/rxjava/model/PostModel.java: -------------------------------------------------------------------------------- 1 | package com.che58.ljb.rxjava.model; 2 | 3 | /** 4 | * Created by ljb on 2016/4/7. 5 | */ 6 | public class PostModel { 7 | private int code; 8 | private String message; 9 | private XgoEntity entity; 10 | 11 | private class XgoEntity { 12 | private Data data; 13 | 14 | private class Data { 15 | private String xxx; 16 | 17 | @Override 18 | public String toString() { 19 | return "Data{" + 20 | "xxx='" + xxx + '\'' + 21 | '}'; 22 | } 23 | } 24 | 25 | @Override 26 | public String toString() { 27 | return "XgoEntity{" + 28 | "data=" + data + 29 | '}'; 30 | } 31 | } 32 | 33 | @Override 34 | public String toString() { 35 | return "GetModel{" + 36 | "code=" + code + 37 | ", message='" + message + '\'' + 38 | ", entity=" + entity + 39 | '}'; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/java/com/che58/ljb/rxjava/model/PutModel.java: -------------------------------------------------------------------------------- 1 | package com.che58.ljb.rxjava.model; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Created by ljb on 2016/4/7. 7 | */ 8 | public class PutModel { 9 | private int code; 10 | private String message; 11 | private XgoEntity entity; 12 | 13 | private class XgoEntity { 14 | private List data; 15 | 16 | private class Data { 17 | @Override 18 | public String toString() { 19 | return "Data{}"; 20 | } 21 | } 22 | 23 | @Override 24 | public String toString() { 25 | return "XgoEntity{" + 26 | "data=" + data + 27 | '}'; 28 | } 29 | } 30 | 31 | @Override 32 | public String toString() { 33 | return "PutModel{" + 34 | "code=" + code + 35 | ", message='" + message + '\'' + 36 | ", entity=" + entity + 37 | '}'; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/src/main/java/com/che58/ljb/rxjava/net/XgoHttpClient.java: -------------------------------------------------------------------------------- 1 | package com.che58.ljb.rxjava.net; 2 | 3 | import android.net.Uri; 4 | 5 | import com.che58.ljb.rxjava.net.interceptor.XgoLogInterceptor; 6 | import com.che58.ljb.rxjava.utils.XgoLog; 7 | import com.squareup.okhttp.Callback; 8 | import com.squareup.okhttp.MediaType; 9 | import com.squareup.okhttp.MultipartBuilder; 10 | import com.squareup.okhttp.OkHttpClient; 11 | import com.squareup.okhttp.Request; 12 | import com.squareup.okhttp.RequestBody; 13 | import com.squareup.okhttp.Response; 14 | 15 | import java.io.File; 16 | import java.io.IOException; 17 | import java.net.FileNameMap; 18 | import java.net.URLConnection; 19 | import java.util.Map; 20 | import java.util.Set; 21 | import java.util.TreeMap; 22 | import java.util.concurrent.TimeUnit; 23 | 24 | 25 | /** 26 | * XgoHttpClient 27 | * for okHttp simple encapsulation 28 | * Created by Ljb on 2015/12/11. 29 | */ 30 | public class XgoHttpClient { 31 | 32 | public static final String METHOD_GET = "GET"; 33 | public static final String METHOD_POST = "POST"; 34 | public static final String METHOD_PUT = "PUT"; 35 | public static final String METHOD_DELETE = "DELETE"; 36 | 37 | private static final XgoHttpClient mClient = new XgoHttpClient(); 38 | private static final OkHttpClient mOkHttpClient = new OkHttpClient(); 39 | 40 | static { 41 | mOkHttpClient.setConnectTimeout(5000, TimeUnit.MILLISECONDS); 42 | //添加日志过滤器 43 | XgoLogInterceptor logInterceptor = new XgoLogInterceptor(new XgoLogInterceptor.Logger() { 44 | @Override 45 | public void log(String message) { 46 | XgoLog.d(message); 47 | } 48 | }); 49 | logInterceptor.setLevel(XgoLogInterceptor.Level.BODY); 50 | mOkHttpClient.interceptors().add(logInterceptor); 51 | } 52 | 53 | public static XgoHttpClient getClient() { 54 | return mClient; 55 | } 56 | 57 | /** 58 | * 同步模式 59 | * 60 | * @param request 61 | * @return String(json) 62 | */ 63 | public String execute2String(Request request) { 64 | 65 | String result = null; 66 | try { 67 | Response response = mOkHttpClient.newCall(request).execute(); 68 | if (response != null && response.isSuccessful()) { 69 | result = response.body().string(); 70 | } 71 | } catch (IOException e) { 72 | e.printStackTrace(); 73 | } 74 | return result; 75 | } 76 | 77 | /** 78 | * 异步CallBack模式 79 | * 80 | * @param request 81 | * @param responseCallback 82 | */ 83 | public void enqueue(Request request, Callback responseCallback) { 84 | mOkHttpClient.newCall(request).enqueue(responseCallback); 85 | } 86 | 87 | /** 88 | * 通过http请求的基本信息,创建一个Request对象 89 | */ 90 | public Request getRequest(String url, String method, Map params) { 91 | if (params == null) { 92 | params = new TreeMap<>(); 93 | } 94 | 95 | Request.Builder builder = new Request.Builder(); 96 | 97 | if (XgoHttpClient.METHOD_GET.equalsIgnoreCase(method)) { 98 | //GET 99 | builder.url(initGetRequest(url, params)).get(); 100 | } else if (XgoHttpClient.METHOD_POST.equalsIgnoreCase(method)) { 101 | //POST 102 | builder.url(url).post(initRequestBody(params)); 103 | } else if (XgoHttpClient.METHOD_PUT.equalsIgnoreCase(method)) { 104 | //PUT 105 | builder.url(url).put(initRequestBody(params)); 106 | } else if (XgoHttpClient.METHOD_DELETE.equalsIgnoreCase(method)) { 107 | //DELETE 108 | if (params.size() == 0) { 109 | builder.url(url).delete(); 110 | } else { 111 | builder.url(url).delete(initRequestBody(params)); 112 | } 113 | } 114 | return builder.build(); 115 | } 116 | 117 | /** 118 | * 初始化Body类型请求参数 119 | * init Body type params 120 | */ 121 | private RequestBody initRequestBody(Map params) { 122 | MultipartBuilder bodyBuilder = new MultipartBuilder().type(MultipartBuilder.FORM); 123 | Set> entries = params.entrySet(); 124 | for (Map.Entry entry : entries) { 125 | String key = entry.getKey(); 126 | Object value = entry.getValue(); 127 | 128 | if (value instanceof File) { 129 | File file = (File) value; 130 | try { 131 | FileNameMap fileNameMap = URLConnection.getFileNameMap(); 132 | String mimeType = fileNameMap.getContentTypeFor(file.getAbsolutePath()); 133 | XgoLog.w("mimeType::" + mimeType); 134 | bodyBuilder.addFormDataPart(key, file.getName(), RequestBody.create(MediaType.parse(mimeType), file)); 135 | } catch (Exception e) { 136 | e.printStackTrace(); 137 | XgoLog.e("mimeType is Error !"); 138 | } 139 | } else { 140 | XgoLog.w(key + "::" + value); 141 | bodyBuilder.addFormDataPart(key, value.toString()); 142 | } 143 | } 144 | return bodyBuilder.build(); 145 | } 146 | 147 | /** 148 | * 初始化Get请求参数 149 | * init Get type params 150 | */ 151 | private String initGetRequest(String url, Map params) { 152 | StringBuilder sb = new StringBuilder(url); 153 | //has params ? 154 | if (params.size() > 0) { 155 | sb.append('?'); 156 | Set> entries = params.entrySet(); 157 | int count = 0; 158 | for (Map.Entry entry : entries) { 159 | count++; 160 | sb.append(entry.getKey()).append('=').append(Uri.encode(entry.getValue().toString())); 161 | if (count == params.size()) { 162 | break; 163 | } 164 | sb.append('&'); 165 | } 166 | url = new String(sb); 167 | } 168 | return url; 169 | } 170 | 171 | /** 172 | * set timeout 173 | */ 174 | public void setConnectTimeout(long time) { 175 | if (mOkHttpClient != null) { 176 | mOkHttpClient.setConnectTimeout(time, TimeUnit.MILLISECONDS); 177 | } 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /app/src/main/java/com/che58/ljb/rxjava/net/interceptor/XgoLogInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.che58.ljb.rxjava.net.interceptor; 2 | 3 | import com.squareup.okhttp.Connection; 4 | import com.squareup.okhttp.Headers; 5 | import com.squareup.okhttp.Interceptor; 6 | import com.squareup.okhttp.MediaType; 7 | import com.squareup.okhttp.Protocol; 8 | import com.squareup.okhttp.Request; 9 | import com.squareup.okhttp.RequestBody; 10 | import com.squareup.okhttp.Response; 11 | import com.squareup.okhttp.ResponseBody; 12 | import com.squareup.okhttp.internal.Platform; 13 | import com.squareup.okhttp.internal.http.HttpEngine; 14 | 15 | import java.io.IOException; 16 | import java.nio.charset.Charset; 17 | import java.util.concurrent.TimeUnit; 18 | 19 | import okio.Buffer; 20 | import okio.BufferedSource; 21 | 22 | /** 23 | * The Http XgoLog filter 24 | * Created by Ljb on 2015/12/11. 25 | */ 26 | public class XgoLogInterceptor implements Interceptor { 27 | 28 | private static final String BYTE_BODY = "-byte body)"; 29 | 30 | private static final String END = "--> END "; 31 | 32 | private static final Charset UTF8 = Charset.forName("UTF-8"); 33 | 34 | private final Logger logger; 35 | 36 | private volatile Level level = Level.NONE; 37 | 38 | public enum Level { 39 | /** No logs. */ 40 | NONE, 41 | /** 42 | * Logs request and response lines. 43 | *

44 | * Example: 45 | *

{@code
 46 |          * --> POST /greeting HTTP/1.1 (3-byte body)
 47 |          *
 48 |          * <-- HTTP/1.1 200 OK (22ms, 6-byte body)
 49 |          * }
50 | */ 51 | BASIC, 52 | /** 53 | * Logs request and response lines and their respective headers. 54 | *

55 | * Example: 56 | *

{@code
 57 |          * --> POST /greeting HTTP/1.1
 58 |          * Host: example.com
 59 |          * Content-Type: plain/text
 60 |          * Content-Length: 3
 61 |          * --> END POST
 62 |          *
 63 |          * <-- HTTP/1.1 200 OK (22ms)
 64 |          * Content-Type: plain/text
 65 |          * Content-Length: 6
 66 |          * <-- END HTTP
 67 |          * }
68 | */ 69 | HEADERS, 70 | /** 71 | * Logs request and response lines and their respective headers and bodies (if present). 72 | *

73 | * Example: 74 | *

{@code
 75 |          * --> POST /greeting HTTP/1.1
 76 |          * Host: example.com
 77 |          * Content-Type: plain/text
 78 |          * Content-Length: 3
 79 |          *
 80 |          * Hi?
 81 |          * --> END GET
 82 |          *
 83 |          * <-- HTTP/1.1 200 OK (22ms)
 84 |          * Content-Type: plain/text
 85 |          * Content-Length: 6
 86 |          *
 87 |          * Hello!
 88 |          * <-- END HTTP
 89 |          * }
90 | */ 91 | BODY 92 | } 93 | 94 | public interface Logger { 95 | /** A {@link Logger} defaults output appropriate for the current platform. */ 96 | Logger DEFAULT = new Logger() { 97 | @Override 98 | public void log(String message) { 99 | Platform.get().log(message); 100 | } 101 | }; 102 | 103 | void log(String message); 104 | 105 | } 106 | 107 | public XgoLogInterceptor() { 108 | this(Logger.DEFAULT); 109 | } 110 | 111 | public XgoLogInterceptor(Logger logger) { 112 | this.logger = logger; 113 | } 114 | 115 | /** Change the level at which this interceptor logs. */ 116 | public XgoLogInterceptor setLevel(Level level) { 117 | if (level == null) throw new NullPointerException("level == null. Use Level.NONE instead."); 118 | this.level = level; 119 | return this; 120 | } 121 | 122 | public Level getLevel() { 123 | return level; 124 | } 125 | 126 | @Override 127 | public Response intercept(Chain chain) throws IOException { 128 | Level level = this.level; 129 | 130 | Request request = chain.request(); 131 | if (level == Level.NONE) { 132 | return chain.proceed(request); 133 | } 134 | 135 | boolean logBody = level == Level.BODY; 136 | boolean logHeaders = logBody || level == Level.HEADERS; 137 | 138 | RequestBody requestBody = request.body(); 139 | boolean hasRequestBody = requestBody != null; 140 | 141 | Connection connection = chain.connection(); 142 | Protocol protocol = connection != null ? connection.getProtocol() : Protocol.HTTP_1_1; 143 | StringBuilder requestStartMessage = new StringBuilder(); 144 | requestStartMessage.append("--> " + request.method() + ' ' + request.url() + ' ' + protocol(protocol)); 145 | if (!logHeaders && hasRequestBody) { 146 | requestStartMessage.append(" (" + requestBody.contentLength() + BYTE_BODY); 147 | } 148 | logger.log(requestStartMessage.toString()); 149 | 150 | if (logHeaders) { 151 | if (hasRequestBody) { 152 | // Request body headers are only present when installed as a network interceptor. Force 153 | // them to be included (when available) so there values are known. 154 | if (requestBody.contentType() != null) { 155 | logger.log("Content-Type: " + requestBody.contentType()); 156 | } 157 | if (requestBody.contentLength() != -1) { 158 | logger.log("Content-Length: " + requestBody.contentLength()); 159 | } 160 | } 161 | 162 | Headers headers = request.headers(); 163 | for (int i = 0, count = headers.size(); i < count; i++) { 164 | String name = headers.name(i); 165 | // Skip headers from the request body as they are explicitly logged above. 166 | if (!"Content-Type".equalsIgnoreCase(name) && !"Content-Length".equalsIgnoreCase(name)) { 167 | logger.log(name + ": " + headers.value(i)); 168 | } 169 | } 170 | 171 | if (!logBody || !hasRequestBody) { 172 | logger.log(END + request.method()); 173 | } else if (bodyEncoded(request.headers())) { 174 | logger.log(END + request.method() + " (encoded body omitted)"); 175 | } else { 176 | Buffer buffer = new Buffer(); 177 | requestBody.writeTo(buffer); 178 | 179 | Charset charset = UTF8; 180 | MediaType contentType = requestBody.contentType(); 181 | if (contentType != null) { 182 | contentType.charset(UTF8); 183 | } 184 | 185 | logger.log(""); 186 | logger.log(buffer.readString(charset)); 187 | 188 | logger.log(END + request.method() 189 | + " (" + requestBody.contentLength() + BYTE_BODY); 190 | } 191 | } 192 | 193 | long startNs = System.nanoTime(); 194 | Response response = chain.proceed(request); 195 | long tookMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs); 196 | 197 | ResponseBody responseBody = response.body(); 198 | logger.log("<-- " + response.code() + ' ' + response.message() + ' ' 199 | + response.request().url() + " (" + tookMs + "ms" + (!logHeaders ? ", " 200 | + responseBody.contentLength() + "-byte body" : "") + ')'); 201 | 202 | if (logHeaders) { 203 | Headers headers = response.headers(); 204 | for (int i = 0, count = headers.size(); i < count; i++) { 205 | logger.log(headers.name(i) + ": " + headers.value(i)); 206 | } 207 | 208 | if (!logBody || !HttpEngine.hasBody(response)) { 209 | logger.log("<-- END HTTP"); 210 | } else if (bodyEncoded(response.headers())) { 211 | logger.log("<-- END HTTP (encoded body omitted)"); 212 | } else { 213 | BufferedSource source = responseBody.source(); 214 | source.request(Long.MAX_VALUE); // Buffer the entire body. 215 | Buffer buffer = source.buffer(); 216 | 217 | Charset charset = UTF8; 218 | MediaType contentType = responseBody.contentType(); 219 | if (contentType != null) { 220 | charset = contentType.charset(UTF8); 221 | } 222 | 223 | if (responseBody.contentLength() != 0) { 224 | logger.log(""); 225 | logger.log(buffer.clone().readString(charset)); 226 | } 227 | 228 | logger.log("<-- END HTTP (" + buffer.size() + BYTE_BODY); 229 | } 230 | } 231 | 232 | return response; 233 | } 234 | 235 | private boolean bodyEncoded(Headers headers) { 236 | String contentEncoding = headers.get("Content-Encoding"); 237 | return contentEncoding != null && !contentEncoding.equalsIgnoreCase("identity"); 238 | } 239 | 240 | private static String protocol(Protocol protocol) { 241 | return protocol == Protocol.HTTP_1_0 ? "HTTP/1.0" : "HTTP/1.1"; 242 | } 243 | 244 | } 245 | -------------------------------------------------------------------------------- /app/src/main/java/com/che58/ljb/rxjava/protocol/BaseProtocol.java: -------------------------------------------------------------------------------- 1 | package com.che58.ljb.rxjava.protocol; 2 | 3 | import android.text.TextUtils; 4 | 5 | import com.che58.ljb.rxjava.net.XgoHttpClient; 6 | import com.squareup.okhttp.Request; 7 | 8 | import java.util.Map; 9 | 10 | import rx.Observable; 11 | import rx.Subscriber; 12 | import rx.schedulers.Schedulers; 13 | 14 | /** 15 | * BaseProtocol 16 | * Created by Ljb on 2015/12/22. 17 | */ 18 | public abstract class BaseProtocol { 19 | 20 | 21 | /** 22 | * 创建一个工作在IO线程的被观察者(被订阅者)对象 23 | * @param url 24 | * @param method 25 | * @param params 26 | */ 27 | protected Observable createObservable(final String url, final String method, final Map params) { 28 | return Observable.create(new Observable.OnSubscribe() { // (2) 29 | @Override 30 | public void call(Subscriber subscriber) { 31 | Request request = XgoHttpClient.getClient().getRequest(url, method, params); // (3) 32 | String json = XgoHttpClient.getClient().execute2String(request); // (4) 33 | setData(subscriber, json); // (5) 34 | } 35 | }).subscribeOn(Schedulers.io()); 36 | } 37 | 38 | 39 | /** 40 | * 为观察者(订阅者)设置返回数据 41 | * */ 42 | protected void setData(Subscriber subscriber, String json) { 43 | if (TextUtils.isEmpty(json)) { // (6) 44 | subscriber.onError(new Throwable("not data")); 45 | return; 46 | } 47 | subscriber.onNext(json); // (7) 48 | subscriber.onCompleted(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/src/main/java/com/che58/ljb/rxjava/protocol/TestProtocol.java: -------------------------------------------------------------------------------- 1 | package com.che58.ljb.rxjava.protocol; 2 | 3 | import com.che58.ljb.rxjava.net.XgoHttpClient; 4 | 5 | import java.util.Map; 6 | 7 | import rx.Observable; 8 | 9 | /** 10 | * 测试接口 11 | * Created by ljb on 2016/3/23. 12 | */ 13 | public class TestProtocol extends BaseProtocol { 14 | 15 | private static final String URL = "http://integer.wang/init/json.shtml"; 16 | 17 | /** 18 | * Get请求 19 | */ 20 | public Observable testGet() { 21 | return createObservable(URL, XgoHttpClient.METHOD_GET, null); // (1) 22 | } 23 | 24 | 25 | /** 26 | * Post请求 27 | */ 28 | public Observable testPost(Map params) { 29 | return createObservable(URL, XgoHttpClient.METHOD_POST, params); 30 | } 31 | 32 | /** 33 | * Put请求 34 | */ 35 | public Observable testPut(Map params) { 36 | return createObservable(URL, XgoHttpClient.METHOD_PUT, params); 37 | } 38 | 39 | /** 40 | * Delete请求 41 | */ 42 | public Observable testDelete() { 43 | return createObservable(URL, XgoHttpClient.METHOD_DELETE, null); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/java/com/che58/ljb/rxjava/protocol2/BaseProtocol.java: -------------------------------------------------------------------------------- 1 | package com.che58.ljb.rxjava.protocol2; 2 | 3 | import android.text.TextUtils; 4 | 5 | import com.che58.ljb.rxjava.net.XgoHttpClient; 6 | import com.google.gson.Gson; 7 | import com.squareup.okhttp.Request; 8 | 9 | import java.util.Map; 10 | 11 | import rx.Observable; 12 | import rx.Subscriber; 13 | import rx.schedulers.Schedulers; 14 | 15 | /** 16 | * BaseProtocol 加入Gson解析 17 | * Created by Ljb on 2015/12/22. 18 | */ 19 | public abstract class BaseProtocol { 20 | 21 | private static final Gson mGson; 22 | 23 | static { 24 | mGson = new Gson(); 25 | } 26 | 27 | 28 | /** 29 | * 创建一个工作在IO线程的被观察者(被订阅者)对象 30 | * 31 | * @param url 32 | * @param method 33 | * @param params 34 | */ 35 | protected Observable createObservable(final String url, final String method, final Map params, final Class clazz) { 36 | return Observable.create(new Observable.OnSubscribe() { 37 | @Override 38 | public void call(Subscriber subscriber) { 39 | Request request = XgoHttpClient.getClient().getRequest(url, method, params); 40 | String json = XgoHttpClient.getClient().execute2String(request); 41 | setData(subscriber, json, clazz); 42 | } 43 | }).subscribeOn(Schedulers.io()); 44 | } 45 | 46 | 47 | /** 48 | * 为观察者(订阅者)设置返回数据 49 | */ 50 | protected void setData(Subscriber subscriber, String json, Class clazz) { 51 | if (TextUtils.isEmpty(json)) { 52 | subscriber.onError(new Throwable("not data")); 53 | return; 54 | } 55 | 56 | T data = mGson.fromJson(json, clazz); 57 | 58 | subscriber.onNext(data); 59 | subscriber.onCompleted(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /app/src/main/java/com/che58/ljb/rxjava/protocol2/TestProtocol.java: -------------------------------------------------------------------------------- 1 | package com.che58.ljb.rxjava.protocol2; 2 | 3 | import com.che58.ljb.rxjava.model.DeleteModel; 4 | import com.che58.ljb.rxjava.model.GetModel; 5 | import com.che58.ljb.rxjava.model.PostModel; 6 | import com.che58.ljb.rxjava.model.PutModel; 7 | import com.che58.ljb.rxjava.net.XgoHttpClient; 8 | 9 | import java.util.Map; 10 | 11 | import rx.Observable; 12 | 13 | /** 14 | * 测试接口 15 | * Created by ljb on 2016/3/23. 16 | */ 17 | public class TestProtocol extends BaseProtocol { 18 | 19 | private static final String URL = "http://integer.wang/init/json.shtml"; 20 | 21 | /** 22 | * Get请求 23 | */ 24 | public Observable testGet() { 25 | return createObservable(URL, XgoHttpClient.METHOD_GET, null, GetModel.class); 26 | } 27 | 28 | 29 | /** 30 | * Post请求 31 | */ 32 | public Observable testPost(Map params) { 33 | return createObservable(URL, XgoHttpClient.METHOD_POST, params, PostModel.class); 34 | } 35 | 36 | /** 37 | * Put请求 38 | */ 39 | public Observable testPut(Map params) { 40 | return createObservable(URL, XgoHttpClient.METHOD_PUT, params, PutModel.class); 41 | } 42 | 43 | /** 44 | * Delete请求 45 | */ 46 | public Observable testDelete() { 47 | return createObservable(URL, XgoHttpClient.METHOD_DELETE, null, DeleteModel.class); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /app/src/main/java/com/che58/ljb/rxjava/rxbus/RxBus.java: -------------------------------------------------------------------------------- 1 | package com.che58.ljb.rxjava.rxbus; 2 | 3 | import rx.Observable; 4 | import rx.subjects.PublishSubject; 5 | import rx.subjects.SerializedSubject; 6 | import rx.subjects.Subject; 7 | 8 | /** 9 | * RxBus 10 | */ 11 | public class RxBus { 12 | 13 | //private final PublishSubject _bus = PublishSubject.create(); //线程不安全 14 | 15 | private final Subject _bus = new SerializedSubject<>(PublishSubject.create()); //线程安全 16 | 17 | public void send(Object o) { 18 | _bus.onNext(o); 19 | } 20 | 21 | /**获取实际的Bus对象*/ 22 | public Observable toObserverable() { 23 | return _bus; 24 | } 25 | 26 | /**是否含有观察者*/ 27 | public boolean hasObservers() { 28 | return _bus.hasObservers(); 29 | } 30 | } -------------------------------------------------------------------------------- /app/src/main/java/com/che58/ljb/rxjava/rxbus/RxBusDemoFragment.java: -------------------------------------------------------------------------------- 1 | package com.che58.ljb.rxjava.rxbus; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | 9 | import com.che58.ljb.rxjava.R; 10 | import com.trello.rxlifecycle.components.support.RxFragment; 11 | 12 | import butterknife.ButterKnife; 13 | 14 | /** 15 | * RxBus Demo 16 | */ 17 | public class RxBusDemoFragment extends RxFragment { 18 | 19 | @Override 20 | public View onCreateView(LayoutInflater inflater,@Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 21 | View layout = inflater.inflate(R.layout.fragment_rxbus_demo, container, false); 22 | ButterKnife.bind(this, layout); 23 | return layout; 24 | } 25 | 26 | @Override 27 | public void onActivityCreated(@Nullable Bundle savedInstanceState) { 28 | super.onActivityCreated(savedInstanceState); 29 | 30 | getActivity().getSupportFragmentManager() 31 | .beginTransaction() 32 | .replace(R.id.demo_rxbus_frag_1, new RxBusDemo_TopFragment()) 33 | .replace(R.id.demo_rxbus_frag_2, new RxBusDemo_Bottom3Fragment()) 34 | .commit(); 35 | } 36 | 37 | public static class TapEvent { 38 | } 39 | } -------------------------------------------------------------------------------- /app/src/main/java/com/che58/ljb/rxjava/rxbus/RxBusDemo_Bottom3Fragment.java: -------------------------------------------------------------------------------- 1 | package com.che58.ljb.rxjava.rxbus; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v4.view.ViewCompat; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.TextView; 10 | 11 | import com.che58.ljb.rxjava.R; 12 | import com.che58.ljb.rxjava.act.MainActivity; 13 | import com.trello.rxlifecycle.FragmentEvent; 14 | import com.trello.rxlifecycle.components.support.RxFragment; 15 | 16 | import java.util.List; 17 | import java.util.concurrent.TimeUnit; 18 | 19 | import butterknife.Bind; 20 | import butterknife.ButterKnife; 21 | import rx.Observable; 22 | import rx.android.schedulers.AndroidSchedulers; 23 | import rx.functions.Action1; 24 | import rx.functions.Func1; 25 | import rx.observables.ConnectableObservable; 26 | 27 | public class RxBusDemo_Bottom3Fragment extends RxFragment { 28 | 29 | @Bind(R.id.demo_rxbus_tap_txt) 30 | TextView _tapEventTxtShow; 31 | @Bind(R.id.demo_rxbus_tap_count) 32 | TextView _tapEventCountShow; 33 | private RxBus _rxBus; 34 | 35 | @Override 36 | public View onCreateView(LayoutInflater inflater, 37 | @Nullable ViewGroup container, 38 | @Nullable Bundle savedInstanceState) { 39 | View layout = inflater.inflate(R.layout.fragment_rxbus_bottom, container, false); 40 | ButterKnife.bind(this, layout); 41 | return layout; 42 | } 43 | 44 | @Override 45 | public void onActivityCreated(@Nullable Bundle savedInstanceState) { 46 | super.onActivityCreated(savedInstanceState); 47 | _rxBus = ((MainActivity) getActivity()).getRxBusSingleton(); 48 | } 49 | 50 | @Override 51 | public void onStart() { 52 | super.onStart(); 53 | 54 | //将普通的Observable转换为可连接的Observable 55 | ConnectableObservable publish = _rxBus.toObserverable().publish(); 56 | 57 | publish.compose(this.bindToLifecycle()) 58 | .subscribe(new Action1() { //一个一旦被触发就会显示TapText的监听者 59 | @Override 60 | public void call(Object event) { 61 | if (event instanceof RxBusDemoFragment.TapEvent) { 62 | _showTapText(); 63 | } 64 | } 65 | }); 66 | 67 | publish.compose(this.bindUntilEvent(FragmentEvent.DESTROY)) 68 | .publish(new Func1, Observable>>() {//一个出发后缓存一秒内的点击数并显示的监听者 69 | @Override 70 | public Observable> call(Observable stream) { 71 | return stream.buffer(stream.debounce(1, TimeUnit.SECONDS)); //进行缓冲1秒,打包发送 72 | } 73 | }).observeOn(AndroidSchedulers.mainThread()).subscribe(new Action1>() { 74 | @Override 75 | public void call(List taps) { 76 | _showTapCount(taps.size()); 77 | } 78 | }); 79 | 80 | publish.connect(); //可连接的Observable并不在订阅时触发,而需手动调用connect()方法 81 | } 82 | 83 | @Override 84 | public void onStop() { 85 | super.onStop(); 86 | } 87 | 88 | // ----------------------------------------------------------------------------------- 89 | // Helper to show the text via an animation 90 | 91 | /** 92 | * 显示TapText 93 | */ 94 | private void _showTapText() { 95 | _tapEventTxtShow.setVisibility(View.VISIBLE); 96 | _tapEventTxtShow.setAlpha(1f); 97 | ViewCompat.animate(_tapEventTxtShow).alphaBy(-1f).setDuration(400).start(); 98 | } 99 | 100 | private void _showTapCount(int size) { 101 | _tapEventCountShow.setText(String.valueOf(size)); 102 | _tapEventCountShow.setVisibility(View.VISIBLE); 103 | _tapEventCountShow.setScaleX(1f); 104 | _tapEventCountShow.setScaleY(1f); 105 | ViewCompat.animate(_tapEventCountShow) 106 | .scaleXBy(-1f) 107 | .scaleYBy(-1f) 108 | .setDuration(800) 109 | .setStartDelay(100); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /app/src/main/java/com/che58/ljb/rxjava/rxbus/RxBusDemo_TopFragment.java: -------------------------------------------------------------------------------- 1 | package com.che58.ljb.rxjava.rxbus; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | 9 | import com.che58.ljb.rxjava.R; 10 | import com.che58.ljb.rxjava.act.MainActivity; 11 | import com.trello.rxlifecycle.components.support.RxFragment; 12 | 13 | import butterknife.ButterKnife; 14 | import butterknife.OnClick; 15 | 16 | /** 17 | * RxBus Demo顶部的Fragment 18 | * */ 19 | public class RxBusDemo_TopFragment extends RxFragment { 20 | 21 | private RxBus _rxBus; 22 | 23 | @Override 24 | public View onCreateView(LayoutInflater inflater, 25 | @Nullable ViewGroup container, 26 | @Nullable Bundle savedInstanceState) { 27 | View layout = inflater.inflate(R.layout.fragment_rxbus_top, container, false); 28 | ButterKnife.bind(this, layout); 29 | return layout; 30 | } 31 | 32 | @Override 33 | public void onActivityCreated(@Nullable Bundle savedInstanceState) { 34 | super.onActivityCreated(savedInstanceState); 35 | _rxBus = ((MainActivity) getActivity()).getRxBusSingleton(); 36 | } 37 | 38 | @OnClick(R.id.btn_demo_rxbus_top) 39 | public void onTapButtonClicked() { 40 | if (_rxBus.hasObservers()) { //是否有观察者,有,则发送一个事件 41 | _rxBus.send(new RxBusDemoFragment.TapEvent()); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/src/main/java/com/che58/ljb/rxjava/utils/XgoLog.java: -------------------------------------------------------------------------------- 1 | package com.che58.ljb.rxjava.utils; 2 | 3 | import android.util.Log; 4 | 5 | public final class XgoLog { 6 | 7 | /** 是否允许输出log 8 | * -1: 不允许 9 | * 其他:根据等级允许 10 | * */ 11 | private static int mDebuggable = 10; 12 | 13 | /** 日志输出时的TAG */ 14 | 15 | private static String mTag = "xgo"; 16 | 17 | 18 | /** 日志输出级别NONE */ 19 | public static final int LEVEL_NONE = 0; 20 | 21 | 22 | /** 日志输出级别V */ 23 | 24 | public static final int LEVEL_VERBOSE = 1; 25 | 26 | /** 日志输出级别D */ 27 | 28 | public static final int LEVEL_DEBUG = 2; 29 | 30 | /** 日志输出级别I */ 31 | 32 | public static final int LEVEL_INFO = 3; 33 | 34 | /** 日志输出级别W */ 35 | 36 | public static final int LEVEL_WARN = 4; 37 | 38 | /** 日志输出级别E */ 39 | 40 | public static final int LEVEL_ERROR = 5; 41 | 42 | private XgoLog() throws InstantiationException { 43 | throw new InstantiationException("This class is not created for instantiation"); 44 | } 45 | 46 | /** 以级别为v 的形式输出LOG */ 47 | 48 | public static void v(String msg) { 49 | 50 | if (mDebuggable >= LEVEL_VERBOSE) { 51 | 52 | Log.v(mTag, msg); 53 | 54 | } 55 | 56 | } 57 | 58 | /** 以级别为 d 的形式输出LOG */ 59 | 60 | public static void d(String msg) { 61 | 62 | if (mDebuggable >= LEVEL_DEBUG) { 63 | 64 | Log.d(mTag, msg); 65 | 66 | } 67 | 68 | } 69 | 70 | /** 以级别为 i 的形式输出LOG */ 71 | 72 | public static void i(String msg) { 73 | 74 | if (mDebuggable >= LEVEL_INFO) { 75 | 76 | Log.i(mTag, msg); 77 | 78 | } 79 | 80 | } 81 | 82 | /** 以级别为 w 的形式输出LOG */ 83 | 84 | public static void w(String msg) { 85 | 86 | if (mDebuggable >= LEVEL_WARN) { 87 | 88 | Log.w(mTag, msg); 89 | 90 | } 91 | 92 | } 93 | 94 | /** 以级别为 w 的形式输出Throwable */ 95 | 96 | public static void w(Throwable tr) { 97 | 98 | if (mDebuggable >= LEVEL_WARN) { 99 | 100 | Log.w(mTag, "", tr); 101 | 102 | } 103 | 104 | } 105 | 106 | /** 以级别为 w 的形式输出LOG信息和Throwable */ 107 | 108 | public static void w(String msg, Throwable tr) { 109 | 110 | if (mDebuggable >= LEVEL_WARN && null != msg) { 111 | 112 | Log.w(mTag, msg, tr); 113 | 114 | } 115 | 116 | } 117 | 118 | /** 以级别为 e 的形式输出LOG */ 119 | 120 | public static void e(String msg) { 121 | 122 | if (mDebuggable >= LEVEL_ERROR) { 123 | 124 | Log.e(mTag, msg); 125 | 126 | } 127 | 128 | } 129 | 130 | /** 以级别为 e 的形式输出Throwable */ 131 | 132 | public static void e(Throwable tr) { 133 | 134 | if (mDebuggable >= LEVEL_ERROR) { 135 | 136 | Log.e(mTag, "", tr); 137 | 138 | } 139 | 140 | } 141 | 142 | /** 以级别为 e 的形式输出LOG信息和Throwable */ 143 | 144 | public static void e(String msg, Throwable tr) { 145 | 146 | if (mDebuggable >= LEVEL_ERROR && null != msg) { 147 | 148 | Log.e(mTag, msg, tr); 149 | 150 | } 151 | 152 | } 153 | 154 | } 155 | -------------------------------------------------------------------------------- /app/src/main/java/com/che58/ljb/rxjava/view/ProgressWheel.java: -------------------------------------------------------------------------------- 1 | package com.che58.ljb.rxjava.view; 2 | 3 | import android.content.Context; 4 | import android.content.res.TypedArray; 5 | import android.graphics.Canvas; 6 | import android.graphics.Paint; 7 | import android.graphics.Paint.Style; 8 | import android.graphics.RectF; 9 | import android.os.Parcel; 10 | import android.os.Parcelable; 11 | import android.os.SystemClock; 12 | import android.support.annotation.NonNull; 13 | import android.util.AttributeSet; 14 | import android.util.DisplayMetrics; 15 | import android.util.TypedValue; 16 | import android.view.View; 17 | 18 | import com.che58.ljb.rxjava.R; 19 | 20 | 21 | /** 22 | * A Material style progress wheel, compatible up to 2.2. 23 | * Todd Davies' Progress Wheel https://github.com/Todd-Davies/ProgressWheel 24 | * 25 | * @author Nico Hormazábal 26 | *

27 | * Licensed under the Apache License 2.0 license see: 28 | * http://www.apache.org/licenses/LICENSE-2.0 29 | */ 30 | public class ProgressWheel extends View { 31 | private static final String TAG = ProgressWheel.class.getSimpleName(); 32 | 33 | /** 34 | * ********* 35 | * DEFAULTS * 36 | * ********** 37 | */ 38 | //Sizes (with defaults in DP) 39 | private int circleRadius = 28; 40 | private int barWidth = 4; 41 | private int rimWidth = 4; 42 | 43 | private static final int BAR_LENGTH = 16; 44 | private static final int BAR_MAX_LENGTH = 270; 45 | 46 | private boolean fillRadius; 47 | 48 | private double timeStartGrowing; 49 | private double barSpinCycleTime = 460; 50 | private float barExtraLength; 51 | private boolean barGrowingFromFront = true; 52 | 53 | private long pausedTimeWithoutGrowing; 54 | private static final long PAUSE_GROWING_TIME = 200; 55 | 56 | //Colors (with defaults) 57 | private int barColor = 0xAA000000; 58 | private int rimColor = 0x00FFFFFF; 59 | 60 | //Paints 61 | private final Paint barPaint = new Paint(); 62 | private final Paint rimPaint = new Paint(); 63 | 64 | //Rectangles 65 | private RectF circleBounds = new RectF(); 66 | 67 | //Animation 68 | //The amount of degrees per second 69 | private float spinSpeed = 230.0f; 70 | // The last time the spinner was animated 71 | private long lastTimeAnimated; 72 | 73 | private boolean linearProgress; 74 | 75 | private float mProgress; 76 | private float mTargetProgress; 77 | private boolean isSpinning; 78 | 79 | private ProgressCallback callback; 80 | 81 | /** 82 | * The constructor for the ProgressWheel 83 | * 84 | * @param context 85 | * @param attrs 86 | */ 87 | public ProgressWheel(Context context, AttributeSet attrs) { 88 | super(context, attrs); 89 | 90 | parseAttributes(context.obtainStyledAttributes(attrs, 91 | R.styleable.ProgressWheel)); 92 | } 93 | 94 | /** 95 | * The constructor for the ProgressWheel 96 | * 97 | * @param context 98 | */ 99 | public ProgressWheel(Context context) { 100 | super(context); 101 | } 102 | 103 | //---------------------------------- 104 | //Setting up stuff 105 | //---------------------------------- 106 | 107 | @Override 108 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 109 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 110 | 111 | int viewWidth = circleRadius + this.getPaddingLeft() + this.getPaddingRight(); 112 | int viewHeight = circleRadius + this.getPaddingTop() + this.getPaddingBottom(); 113 | 114 | int widthMode = MeasureSpec.getMode(widthMeasureSpec); 115 | int widthSize = MeasureSpec.getSize(widthMeasureSpec); 116 | int heightMode = MeasureSpec.getMode(heightMeasureSpec); 117 | int heightSize = MeasureSpec.getSize(heightMeasureSpec); 118 | 119 | int width; 120 | int height; 121 | 122 | //Measure Width 123 | if (widthMode == MeasureSpec.EXACTLY) { 124 | //Must be this size 125 | width = widthSize; 126 | } else if (widthMode == MeasureSpec.AT_MOST) { 127 | //Can't be bigger than... 128 | width = Math.min(viewWidth, widthSize); 129 | } else { 130 | //Be whatever you want 131 | width = viewWidth; 132 | } 133 | 134 | //Measure Height 135 | if (heightMode == MeasureSpec.EXACTLY || widthMode == MeasureSpec.EXACTLY) { 136 | //Must be this size 137 | height = heightSize; 138 | } else if (heightMode == MeasureSpec.AT_MOST) { 139 | //Can't be bigger than... 140 | height = Math.min(viewHeight, heightSize); 141 | } else { 142 | //Be whatever you want 143 | height = viewHeight; 144 | } 145 | 146 | setMeasuredDimension(width, height); 147 | } 148 | 149 | /** 150 | * Use onSizeChanged instead of onAttachedToWindow to get the dimensions of the view, 151 | * because this method is called after measuring the dimensions of MATCH_PARENT & WRAP_CONTENT. 152 | * Use this dimensions to setup the bounds and paints. 153 | */ 154 | @Override 155 | protected void onSizeChanged(int w, int h, int oldw, int oldh) { 156 | super.onSizeChanged(w, h, oldw, oldh); 157 | 158 | setupBounds(w, h); 159 | setupPaints(); 160 | invalidate(); 161 | } 162 | 163 | /** 164 | * Set the properties of the paints we're using to 165 | * draw the progress wheel 166 | */ 167 | private void setupPaints() { 168 | barPaint.setColor(barColor); 169 | barPaint.setAntiAlias(true); 170 | barPaint.setStyle(Style.STROKE); 171 | barPaint.setStrokeWidth(barWidth); 172 | 173 | rimPaint.setColor(rimColor); 174 | rimPaint.setAntiAlias(true); 175 | rimPaint.setStyle(Style.STROKE); 176 | rimPaint.setStrokeWidth(rimWidth); 177 | } 178 | 179 | /** 180 | * Set the bounds of the component 181 | */ 182 | private void setupBounds(int layout_width, int layout_height) { 183 | int paddingTop = getPaddingTop(); 184 | int paddingBottom = getPaddingBottom(); 185 | int paddingLeft = getPaddingLeft(); 186 | int paddingRight = getPaddingRight(); 187 | 188 | if (!fillRadius) { 189 | // Width should equal to Height, find the min value to setup the circle 190 | int minValue = Math.min(layout_width - paddingLeft - paddingRight, 191 | layout_height - paddingBottom - paddingTop); 192 | 193 | int circleDiameter = Math.min(minValue, circleRadius * 2 - barWidth * 2); 194 | 195 | // Calc the Offset if needed for centering the wheel in the available space 196 | int xOffset = (layout_width - paddingLeft - paddingRight - circleDiameter) / 2 + paddingLeft; 197 | int yOffset = (layout_height - paddingTop - paddingBottom - circleDiameter) / 2 + paddingTop; 198 | 199 | circleBounds = new RectF(xOffset + barWidth, 200 | yOffset + barWidth, 201 | xOffset + circleDiameter - barWidth, 202 | yOffset + circleDiameter - barWidth); 203 | } else { 204 | circleBounds = new RectF(paddingLeft + barWidth, 205 | paddingTop + barWidth, 206 | layout_width - paddingRight - barWidth, 207 | layout_height - paddingBottom - barWidth); 208 | } 209 | } 210 | 211 | /** 212 | * Parse the attributes passed to the view from the XML 213 | * 214 | * @param a the attributes to parse 215 | */ 216 | private void parseAttributes(TypedArray a) { 217 | // We transform the default values from DIP to pixels 218 | DisplayMetrics metrics = getContext().getResources().getDisplayMetrics(); 219 | barWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, barWidth, metrics); 220 | rimWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, rimWidth, metrics); 221 | circleRadius = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, circleRadius, metrics); 222 | 223 | circleRadius = (int) a.getDimension(R.styleable.ProgressWheel_matProg_circleRadius, circleRadius); 224 | 225 | fillRadius = a.getBoolean(R.styleable.ProgressWheel_matProg_fillRadius, false); 226 | 227 | barWidth = (int) a.getDimension(R.styleable.ProgressWheel_matProg_barWidth, barWidth); 228 | 229 | rimWidth = (int) a.getDimension(R.styleable.ProgressWheel_matProg_rimWidth, rimWidth); 230 | 231 | float baseSpinSpeed = a.getFloat(R.styleable.ProgressWheel_matProg_spinSpeed, spinSpeed / 360.0f); 232 | spinSpeed = baseSpinSpeed * 360; 233 | 234 | barSpinCycleTime = a.getInt(R.styleable.ProgressWheel_matProg_barSpinCycleTime, (int) barSpinCycleTime); 235 | 236 | barColor = a.getColor(R.styleable.ProgressWheel_matProg_barColor, barColor); 237 | 238 | rimColor = a.getColor(R.styleable.ProgressWheel_matProg_rimColor, rimColor); 239 | 240 | linearProgress = a.getBoolean(R.styleable.ProgressWheel_matProg_linearProgress, false); 241 | 242 | if (a.getBoolean(R.styleable.ProgressWheel_matProg_progressIndeterminate, false)) { 243 | spin(); 244 | } 245 | 246 | // Recycle 247 | a.recycle(); 248 | } 249 | 250 | public void setCallback(ProgressCallback progressCallback) { 251 | callback = progressCallback; 252 | 253 | if (!isSpinning) { 254 | runCallback(); 255 | } 256 | } 257 | 258 | //---------------------------------- 259 | //Animation stuff 260 | //---------------------------------- 261 | 262 | protected void onDraw(Canvas canvas) { 263 | super.onDraw(canvas); 264 | 265 | canvas.drawArc(circleBounds, 360, 360, false, rimPaint); 266 | 267 | boolean mustInvalidate = false; 268 | 269 | if (isSpinning) { 270 | //Draw the spinning bar 271 | mustInvalidate = true; 272 | 273 | long deltaTime = (SystemClock.uptimeMillis() - lastTimeAnimated); 274 | float deltaNormalized = deltaTime * spinSpeed / 1000.0f; 275 | 276 | updateBarLength(deltaTime); 277 | 278 | mProgress += deltaNormalized; 279 | if (mProgress > 360) { 280 | mProgress -= 360f; 281 | 282 | // A full turn has been completed 283 | // we run the callback with -1 in case we want to 284 | // do something, like changing the color 285 | runCallback(-1.0f); 286 | } 287 | lastTimeAnimated = SystemClock.uptimeMillis(); 288 | 289 | float from = mProgress - 90; 290 | float length = BAR_LENGTH + barExtraLength; 291 | 292 | if (isInEditMode()) { 293 | from = 0; 294 | length = 135; 295 | } 296 | 297 | canvas.drawArc(circleBounds, from, length, false, 298 | barPaint); 299 | } else { 300 | float oldProgress = mProgress; 301 | 302 | if (mProgress != mTargetProgress) { 303 | //We smoothly increase the progress bar 304 | mustInvalidate = true; 305 | 306 | float deltaTime = (float) (SystemClock.uptimeMillis() - lastTimeAnimated) / 1000; 307 | float deltaNormalized = deltaTime * spinSpeed; 308 | 309 | mProgress = Math.min(mProgress + deltaNormalized, mTargetProgress); 310 | lastTimeAnimated = SystemClock.uptimeMillis(); 311 | } 312 | 313 | if (oldProgress != mProgress) { 314 | runCallback(); 315 | } 316 | 317 | float offset = 0.0f; 318 | float progress = mProgress; 319 | if (!linearProgress) { 320 | float factor = 2.0f; 321 | offset = (float) (1.0f - Math.pow(1.0f - mProgress / 360.0f, 2.0f * factor)) * 360.0f; 322 | progress = (float) (1.0f - Math.pow(1.0f - mProgress / 360.0f, factor)) * 360.0f; 323 | } 324 | 325 | if (isInEditMode()) { 326 | progress = 360; 327 | } 328 | 329 | canvas.drawArc(circleBounds, offset - 90, progress, false, barPaint); 330 | } 331 | 332 | if (mustInvalidate) { 333 | invalidate(); 334 | } 335 | } 336 | 337 | @Override 338 | protected void onVisibilityChanged(@NonNull View changedView, int visibility) { 339 | super.onVisibilityChanged(changedView, visibility); 340 | 341 | if (visibility == VISIBLE) { 342 | lastTimeAnimated = SystemClock.uptimeMillis(); 343 | } 344 | } 345 | 346 | private void updateBarLength(long deltaTimeInMilliSeconds) { 347 | if (pausedTimeWithoutGrowing >= PAUSE_GROWING_TIME) { 348 | timeStartGrowing += deltaTimeInMilliSeconds; 349 | 350 | if (timeStartGrowing > barSpinCycleTime) { 351 | // We completed a size change cycle 352 | // (growing or shrinking) 353 | timeStartGrowing -= barSpinCycleTime; 354 | pausedTimeWithoutGrowing = 0; 355 | barGrowingFromFront = !barGrowingFromFront; 356 | } 357 | 358 | float distance = (float) Math.cos((timeStartGrowing / barSpinCycleTime + 1) * Math.PI) / 2 + 0.5f; 359 | float destLength = (BAR_MAX_LENGTH - BAR_LENGTH); 360 | 361 | if (barGrowingFromFront) { 362 | barExtraLength = distance * destLength; 363 | } else { 364 | float newLength = destLength * (1 - distance); 365 | mProgress += (barExtraLength - newLength); 366 | barExtraLength = newLength; 367 | } 368 | } else { 369 | pausedTimeWithoutGrowing += deltaTimeInMilliSeconds; 370 | } 371 | } 372 | 373 | /** 374 | * Check if the wheel is currently spinning 375 | */ 376 | 377 | public boolean isSpinning() { 378 | return isSpinning; 379 | } 380 | 381 | /** 382 | * Reset the count (in increment mode) 383 | */ 384 | public void resetCount() { 385 | mProgress = 0.0f; 386 | mTargetProgress = 0.0f; 387 | invalidate(); 388 | } 389 | 390 | /** 391 | * Turn off spin mode 392 | */ 393 | public void stopSpinning() { 394 | isSpinning = false; 395 | mProgress = 0.0f; 396 | mTargetProgress = 0.0f; 397 | invalidate(); 398 | } 399 | 400 | /** 401 | * Puts the view on spin mode 402 | */ 403 | public void spin() { 404 | lastTimeAnimated = SystemClock.uptimeMillis(); 405 | isSpinning = true; 406 | invalidate(); 407 | } 408 | 409 | private void runCallback(float value) { 410 | if (callback != null) { 411 | callback.onProgressUpdate(value); 412 | } 413 | } 414 | 415 | private void runCallback() { 416 | if (callback != null) { 417 | float normalizedProgress = (float) Math.round(mProgress * 100 / 360.0f) / 100; 418 | callback.onProgressUpdate(normalizedProgress); 419 | } 420 | } 421 | 422 | /** 423 | * Set the progress to a specific value, 424 | * the bar will smoothly animate until that value 425 | * 426 | * @param progress the progress between 0 and 1 427 | */ 428 | public void setProgress(float progress) { 429 | if (isSpinning) { 430 | mProgress = 0.0f; 431 | isSpinning = false; 432 | 433 | runCallback(); 434 | } 435 | 436 | if (progress > 1.0f) { 437 | progress -= 1.0f; 438 | } else if (progress < 0) { 439 | progress = 0; 440 | } 441 | 442 | if (progress == mTargetProgress) { 443 | return; 444 | } 445 | 446 | // If we are currently in the right position 447 | // we set again the last time animated so the 448 | // animation starts smooth from here 449 | if (mProgress == mTargetProgress) { 450 | lastTimeAnimated = SystemClock.uptimeMillis(); 451 | } 452 | 453 | mTargetProgress = Math.min(progress * 360.0f, 360.0f); 454 | 455 | invalidate(); 456 | } 457 | 458 | /** 459 | * Set the progress to a specific value, 460 | * the bar will be set instantly to that value 461 | * 462 | * @param progress the progress between 0 and 1 463 | */ 464 | public void setInstantProgress(float progress) { 465 | if (isSpinning) { 466 | mProgress = 0.0f; 467 | isSpinning = false; 468 | } 469 | 470 | if (progress > 1.0f) { 471 | progress -= 1.0f; 472 | } else if (progress < 0) { 473 | progress = 0; 474 | } 475 | 476 | if (progress == mTargetProgress) { 477 | return; 478 | } 479 | 480 | mTargetProgress = Math.min(progress * 360.0f, 360.0f); 481 | mProgress = mTargetProgress; 482 | lastTimeAnimated = SystemClock.uptimeMillis(); 483 | invalidate(); 484 | } 485 | 486 | // Great way to save a view's state http://stackoverflow.com/a/7089687/1991053 487 | @Override 488 | public Parcelable onSaveInstanceState() { 489 | Parcelable superState = super.onSaveInstanceState(); 490 | 491 | WheelSavedState ss = new WheelSavedState(superState); 492 | 493 | // We save everything that can be changed at runtime 494 | ss.mProgress = this.mProgress; 495 | ss.mTargetProgress = this.mTargetProgress; 496 | ss.isSpinning = this.isSpinning; 497 | ss.spinSpeed = this.spinSpeed; 498 | ss.barWidth = this.barWidth; 499 | ss.barColor = this.barColor; 500 | ss.rimWidth = this.rimWidth; 501 | ss.rimColor = this.rimColor; 502 | ss.circleRadius = this.circleRadius; 503 | ss.linearProgress = this.linearProgress; 504 | ss.fillRadius = this.fillRadius; 505 | 506 | return ss; 507 | } 508 | 509 | @Override 510 | public void onRestoreInstanceState(Parcelable state) { 511 | if (!(state instanceof WheelSavedState)) { 512 | super.onRestoreInstanceState(state); 513 | return; 514 | } 515 | 516 | WheelSavedState ss = (WheelSavedState) state; 517 | super.onRestoreInstanceState(ss.getSuperState()); 518 | 519 | this.mProgress = ss.mProgress; 520 | this.mTargetProgress = ss.mTargetProgress; 521 | this.isSpinning = ss.isSpinning; 522 | this.spinSpeed = ss.spinSpeed; 523 | this.barWidth = ss.barWidth; 524 | this.barColor = ss.barColor; 525 | this.rimWidth = ss.rimWidth; 526 | this.rimColor = ss.rimColor; 527 | this.circleRadius = ss.circleRadius; 528 | this.linearProgress = ss.linearProgress; 529 | this.fillRadius = ss.fillRadius; 530 | 531 | this.lastTimeAnimated = SystemClock.uptimeMillis(); 532 | } 533 | 534 | //---------------------------------- 535 | //Getters + setters 536 | //---------------------------------- 537 | 538 | /** 539 | * @return the current progress between 0.0 and 1.0, 540 | * if the wheel is indeterminate, then the result is -1 541 | */ 542 | public float getProgress() { 543 | return isSpinning ? -1 : mProgress / 360.0f; 544 | } 545 | 546 | /** 547 | * Sets the determinate progress mode 548 | * 549 | * @param isLinear if the progress should increase linearly 550 | */ 551 | public void setLinearProgress(boolean isLinear) { 552 | linearProgress = isLinear; 553 | if (!isSpinning) { 554 | invalidate(); 555 | } 556 | } 557 | 558 | /** 559 | * @return the radius of the wheel in pixels 560 | */ 561 | public int getCircleRadius() { 562 | return circleRadius; 563 | } 564 | 565 | /** 566 | * Sets the radius of the wheel 567 | * 568 | * @param circleRadius the expected radius, in pixels 569 | */ 570 | public void setCircleRadius(int circleRadius) { 571 | this.circleRadius = circleRadius; 572 | if (!isSpinning) { 573 | invalidate(); 574 | } 575 | } 576 | 577 | /** 578 | * @return the width of the spinning bar 579 | */ 580 | public int getBarWidth() { 581 | return barWidth; 582 | } 583 | 584 | /** 585 | * Sets the width of the spinning bar 586 | * 587 | * @param barWidth the spinning bar width in pixels 588 | */ 589 | public void setBarWidth(int barWidth) { 590 | this.barWidth = barWidth; 591 | if (!isSpinning) { 592 | invalidate(); 593 | } 594 | } 595 | 596 | /** 597 | * @return the color of the spinning bar 598 | */ 599 | public int getBarColor() { 600 | return barColor; 601 | } 602 | 603 | /** 604 | * Sets the color of the spinning bar 605 | * 606 | * @param barColor The spinning bar color 607 | */ 608 | public void setBarColor(int barColor) { 609 | this.barColor = barColor; 610 | setupPaints(); 611 | if (!isSpinning) { 612 | invalidate(); 613 | } 614 | } 615 | 616 | /** 617 | * @return the color of the wheel's contour 618 | */ 619 | public int getRimColor() { 620 | return rimColor; 621 | } 622 | 623 | /** 624 | * Sets the color of the wheel's contour 625 | * 626 | * @param rimColor the color for the wheel 627 | */ 628 | public void setRimColor(int rimColor) { 629 | this.rimColor = rimColor; 630 | setupPaints(); 631 | if (!isSpinning) { 632 | invalidate(); 633 | } 634 | } 635 | 636 | /** 637 | * @return the base spinning speed, in full circle turns per second 638 | * (1.0 equals on full turn in one second), this value also is applied for 639 | * the smoothness when setting a progress 640 | */ 641 | public float getSpinSpeed() { 642 | return spinSpeed / 360.0f; 643 | } 644 | 645 | /** 646 | * Sets the base spinning speed, in full circle turns per second 647 | * (1.0 equals on full turn in one second), this value also is applied for 648 | * the smoothness when setting a progress 649 | * 650 | * @param spinSpeed the desired base speed in full turns per second 651 | */ 652 | public void setSpinSpeed(float spinSpeed) { 653 | this.spinSpeed = spinSpeed * 360.0f; 654 | } 655 | 656 | /** 657 | * @return the width of the wheel's contour in pixels 658 | */ 659 | public int getRimWidth() { 660 | return rimWidth; 661 | } 662 | 663 | /** 664 | * Sets the width of the wheel's contour 665 | * 666 | * @param rimWidth the width in pixels 667 | */ 668 | public void setRimWidth(int rimWidth) { 669 | this.rimWidth = rimWidth; 670 | if (!isSpinning) { 671 | invalidate(); 672 | } 673 | } 674 | 675 | static class WheelSavedState extends BaseSavedState { 676 | private float mProgress; 677 | private float mTargetProgress; 678 | private boolean isSpinning; 679 | private float spinSpeed; 680 | private int barWidth; 681 | private int barColor; 682 | private int rimWidth; 683 | private int rimColor; 684 | private int circleRadius; 685 | private boolean linearProgress; 686 | private boolean fillRadius; 687 | 688 | //required field that makes Parcelables from a Parcel 689 | public static final Creator CREATOR = 690 | new Creator() { 691 | public WheelSavedState createFromParcel(Parcel in) { 692 | return new WheelSavedState(in); 693 | } 694 | 695 | public WheelSavedState[] newArray(int size) { 696 | return new WheelSavedState[size]; 697 | } 698 | }; 699 | 700 | WheelSavedState(Parcelable superState) { 701 | super(superState); 702 | } 703 | 704 | private WheelSavedState(Parcel in) { 705 | super(in); 706 | this.mProgress = in.readFloat(); 707 | this.mTargetProgress = in.readFloat(); 708 | this.isSpinning = in.readByte() != 0; 709 | this.spinSpeed = in.readFloat(); 710 | this.barWidth = in.readInt(); 711 | this.barColor = in.readInt(); 712 | this.rimWidth = in.readInt(); 713 | this.rimColor = in.readInt(); 714 | this.circleRadius = in.readInt(); 715 | this.linearProgress = in.readByte() != 0; 716 | this.fillRadius = in.readByte() != 0; 717 | } 718 | 719 | @Override 720 | public void writeToParcel(Parcel out, int flags) { 721 | super.writeToParcel(out, flags); 722 | out.writeFloat(this.mProgress); 723 | out.writeFloat(this.mTargetProgress); 724 | out.writeByte((byte) (isSpinning ? 1 : 0)); 725 | out.writeFloat(this.spinSpeed); 726 | out.writeInt(this.barWidth); 727 | out.writeInt(this.barColor); 728 | out.writeInt(this.rimWidth); 729 | out.writeInt(this.rimColor); 730 | out.writeInt(this.circleRadius); 731 | out.writeByte((byte) (linearProgress ? 1 : 0)); 732 | out.writeByte((byte) (fillRadius ? 1 : 0)); 733 | } 734 | 735 | } 736 | 737 | public interface ProgressCallback { 738 | /** 739 | * Method to call when the progress reaches a value 740 | * in order to avoid float precision issues, the progress 741 | * is rounded to a float with two decimals. 742 | * 743 | * In indeterminate mode, the callback is called each time 744 | * the wheel completes an animation cycle, with, the progress value is -1.0f 745 | * 746 | * @param progress a double value between 0.00 and 1.00 both included 747 | */ 748 | public void onProgressUpdate(float progress); 749 | } 750 | } 751 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/default_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cn-ljb/rxjava_for_android/30ef3c6bd50eb65c8182391318adb2be5997b0d8/app/src/main/res/drawable-xxhdpi/default_image.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/icon_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cn-ljb/rxjava_for_android/30ef3c6bd50eb65c8182391318adb2be5997b0d8/app/src/main/res/drawable-xxhdpi/icon_back.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/icon_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cn-ljb/rxjava_for_android/30ef3c6bd50eb65c8182391318adb2be5997b0d8/app/src/main/res/drawable-xxhdpi/icon_search.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/pic_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cn-ljb/rxjava_for_android/30ef3c6bd50eb65c8182391318adb2be5997b0d8/app/src/main/res/drawable-xxhdpi/pic_1.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/pic_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cn-ljb/rxjava_for_android/30ef3c6bd50eb65c8182391318adb2be5997b0d8/app/src/main/res/drawable-xxhdpi/pic_2.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/pic_3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cn-ljb/rxjava_for_android/30ef3c6bd50eb65c8182391318adb2be5997b0d8/app/src/main/res/drawable-xxhdpi/pic_3.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/pic_4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cn-ljb/rxjava_for_android/30ef3c6bd50eb65c8182391318adb2be5997b0d8/app/src/main/res/drawable-xxhdpi/pic_4.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cn-ljb/rxjava_for_android/30ef3c6bd50eb65c8182391318adb2be5997b0d8/app/src/main/res/drawable-xxhdpi/x.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/btn_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_buffer.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 |