├── .gitignore
├── .idea
├── caches
│ └── build_file_checksums.ser
├── codeStyles
│ └── Project.xml
├── gradle.xml
├── misc.xml
├── modules.xml
├── runConfigurations.xml
└── vcs.xml
├── LICENSE
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── motondon
│ │ └── rxjavademoapp
│ │ └── ApplicationTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── motondon
│ │ │ └── rxjavademoapp
│ │ │ └── view
│ │ │ ├── adapter
│ │ │ ├── CategoryItemsAdapter.kt
│ │ │ ├── MainActivityAdapter.kt
│ │ │ └── SimpleStringAdapter.kt
│ │ │ ├── backpressure
│ │ │ ├── BackpressureBasicExampleActivity.kt
│ │ │ ├── BackpressureManualRequestExampleActivity.kt
│ │ │ ├── BackpressureReactivePullExampleActivity.kt
│ │ │ └── BackpressureSpecificOperatorsExampleActivity.kt
│ │ │ ├── base
│ │ │ ├── BaseActivity.kt
│ │ │ └── HotObservablesBaseActivity.kt
│ │ │ ├── generalexamples
│ │ │ ├── BroadcastSystemStatusExampleActivity.kt
│ │ │ ├── DrawingExampleActivity.kt
│ │ │ ├── ServerPollingAfterDataProcessingExampleActivity.kt
│ │ │ ├── ServerPollingExampleActivity.kt
│ │ │ └── TypingIndicatorExampleActivity.kt
│ │ │ ├── hotobservables
│ │ │ ├── HotObservableCacheExampleActivity.kt
│ │ │ ├── HotObservableConnectExampleActivity.kt
│ │ │ ├── HotObservableRefCountExampleActivity.kt
│ │ │ └── HotObservableReplayExampleActivity.kt
│ │ │ ├── main
│ │ │ ├── CategoryItem.kt
│ │ │ ├── ExampleByCategoryActivity.kt
│ │ │ └── MainActivity.kt
│ │ │ ├── operators
│ │ │ ├── AggregateOperatorsExampleActivity.kt
│ │ │ ├── CombiningObservablesExampleActivity.kt
│ │ │ ├── ConcatMapAndFlatMapExampleActivity.kt
│ │ │ ├── ConditionalOperatorsExampleActivity.kt
│ │ │ ├── ErrorHandlingExampleActivity.kt
│ │ │ ├── FilteringExampleActivity.kt
│ │ │ ├── JoinExampleActivity.kt
│ │ │ ├── MoreFilteringOperatorsExampleActivity.kt
│ │ │ ├── RetryExampleActivity.kt
│ │ │ ├── TimeoutExampleActivity.kt
│ │ │ └── TransformingOperatorsExampleActivity.kt
│ │ │ └── parallelization
│ │ │ └── ParallelizationExampleActivity.kt
│ └── res
│ │ ├── drawable-hdpi
│ │ └── ic_keyboard_arrow_down_black_24dp.png
│ │ ├── drawable-mdpi
│ │ └── ic_keyboard_arrow_down_black_24dp.png
│ │ ├── drawable-xhdpi
│ │ └── ic_keyboard_arrow_down_black_24dp.png
│ │ ├── drawable-xxhdpi
│ │ └── ic_keyboard_arrow_down_black_24dp.png
│ │ ├── drawable-xxxhdpi
│ │ └── ic_keyboard_arrow_down_black_24dp.png
│ │ ├── drawable
│ │ ├── background_spinner.xml
│ │ ├── battery_charging_ac.png
│ │ ├── battery_charging_usb.png
│ │ ├── battery_status_almost_full.png
│ │ ├── battery_status_empty.png
│ │ ├── battery_status_full.png
│ │ ├── battery_status_half.png
│ │ ├── battery_status_low.png
│ │ ├── battery_status_very_low.png
│ │ ├── brush.png
│ │ ├── eraser.png
│ │ ├── ic_movie_placeholder.png
│ │ ├── ic_no_cover.png
│ │ ├── ic_toggle_off.png
│ │ ├── ic_toggle_on.png
│ │ ├── list_item_background.xml
│ │ ├── new_file.png
│ │ ├── toggle_selector.xml
│ │ ├── toggle_state_off.xml
│ │ └── toggle_state_on.xml
│ │ ├── layout
│ │ ├── activity_backpressure_basic_example.xml
│ │ ├── activity_backpressure_manual_request_example.xml
│ │ ├── activity_backpressure_reactive_pull_example.xml
│ │ ├── activity_backpressure_specific_operators_example.xml
│ │ ├── activity_example_by_category.xml
│ │ ├── activity_general_broadcast_system_status_example.xml
│ │ ├── activity_general_drawing_example.xml
│ │ ├── activity_general_server_polling_after_data_processing_example.xml
│ │ ├── activity_general_server_polling_example.xml
│ │ ├── activity_general_typing_indicator.xml
│ │ ├── activity_hot_observable_cache_example.xml
│ │ ├── activity_hot_observable_connect_example.xml
│ │ ├── activity_hot_observable_refcount_example.xml
│ │ ├── activity_hot_observable_replay_example.xml
│ │ ├── activity_main.xml
│ │ ├── activity_operators_aggregate_operators_example.xml
│ │ ├── activity_operators_combining_observables_example.xml
│ │ ├── activity_operators_concatmap_flatmap_example.xml
│ │ ├── activity_operators_conditional_operators_example.xml
│ │ ├── activity_operators_error_handling_example.xml
│ │ ├── activity_operators_filtering_example.xml
│ │ ├── activity_operators_join_example.xml
│ │ ├── activity_operators_more_filtering_example.xml
│ │ ├── activity_operators_retry_and_retrywhen_example.xml
│ │ ├── activity_operators_timeout_example.xml
│ │ ├── activity_operators_transforming_operators_example.xml
│ │ ├── activity_parallelization_example.xml
│ │ ├── item_cardview_options.xml
│ │ ├── item_category_list.xml
│ │ └── item_list_single.xml
│ │ ├── menu
│ │ ├── menu_main.xml
│ │ └── menu_reactive_ui_drawing_example.xml
│ │ ├── mipmap-hdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-mdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxxhdpi
│ │ └── ic_launcher.png
│ │ ├── values-w820dp
│ │ └── dimens.xml
│ │ └── values
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── motondon
│ └── rxjavademoapp
│ └── ExampleUnitTest.kt
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── projectFilesBackup
└── .idea
│ └── workspace.xml
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 |
--------------------------------------------------------------------------------
/.idea/caches/build_file_checksums.ser:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JoaoMotondon/RxJavaDemoApp/2cf453c3778c480226a8391cde00127b091c391a/.idea/caches/build_file_checksums.ser
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
18 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # RxJava for Android (100+ Examples Pack) - 🔹Now in Kotlin!!! 🔹
2 | This repository is intended to provide in a single place (i.e. a single Android app) over than 100 examples of RxJava for Android which you can use as a reference when dealing with RxJava.
3 |
4 | # **_UPDATE: This project was entirely convert to Kotlin._**
5 |
6 | 
7 | 
8 |
9 | 
10 | 
11 |
12 | In order to make it easy to find the examples throughout the app, we divided them in different categories. They are:
13 | - **Operators Examples:** Basically it contains examples of operators used to filtering, combining, transforming data, etc as well as some error handling examples.
14 | - **Backpressure Examples:** Contain different approaches to deal with backpressure.
15 | - **Hot Observable Examples:** Show how to use Hot Observables by using operators such as cache, replay, etc.
16 | - **Parallelization:** Demonstrate how to do real parallelization using RxJava operators and schedulers.
17 | - **General Examples:** Contain some examples that do not fit in any of the previous categories.
18 |
19 | Some examples were already covered into details in one of the articles of our RxJava series (you can find the links below), while some other were based on external articles, so you can go directly to those articles and see the the authors' explanations.
20 |
21 | It's worth mentioning whenever an example was based on an external article, we added a reference to the sources, so all the credits go to the authors.
22 |
23 | You can find details about this repository [here](http://androidahead.com/2018/04/06/rxjava-for-android-100-examples-pack/).
24 |
25 | Here is a list of all covered examples on the demo app and the articles on which they were based:
26 |
27 | - **Operators Examples**
28 | - [Filtering Operators](http://androidahead.com/2017/09/11/rxjava-operators-part-1-filtering-operators/) (12 examples)
29 | - [More about Filtering Operators](http://androidahead.com/2017/09/25/rxjava-operators-part-2-more-about-filtering-operators/) (5 examples)
30 | - [Combining Observables](http://androidahead.com/2017/10/17/rxjava-operators-part-3-combining-observables/) (9 examples)
31 | - [Conditional Operators](http://androidahead.com/2017/10/31/rxjava-operators-part-4-conditional-operators/) (10 examples)
32 | - [Transforming Operators](http://androidahead.com/2017/11/16/rxjava-operators-part-5-transforming-operators/) (9 examples)
33 | - [Timeout Operator](http://androidahead.com/2017/12/05/rxjava-operators-part-6-timeout-operator/) (7 examples)
34 | - [Mathematical and Aggregate Operators](http://androidahead.com/2017/12/21/rxjava-operators-part-7-mathematical-and-aggregate-operators/) (7 examples)
35 | - [Join Operator](http://androidahead.com/2018/01/09/rxjava-operators-part-8-join-operator/) (1 examples)
36 | - [Retry and RetryWhen](http://blog.danlew.net/2016/01/25/rxjavas-repeatwhen-and-retrywhen-explained/) (6 examples)
37 | - [ConcatMap and FlatMap](http://fernandocejas.com/2015/01/11/rxjava-observable-tranformation-concatmap-vs-flatmap/) (2 examples)
38 | - [Error Handling](http://blog.danlew.net/2015/12/08/error-handling-in-rxjava/) (5 examples)
39 |
40 | - **Back Pressure Examples**
41 | - [Backpressure](http://androidahead.com/2018/01/30/rxjava-operators-part-9-backpressure/) (8 examples)
42 |
43 | - **Hot Observable Examples**
44 | - [Hot Observables](http://androidahead.com/2018/02/17/rxjava-operators-part-10-hot-observables/)` (6 examples)
45 |
46 | - **Parallelization Examples**
47 | - [Achiving Parallelization](http://tomstechnicalblog.blogspot.com.br/2015/11/rxjava-achieving-parallelization.html) and [Maximizing parallelization](http://tomstechnicalblog.blogspot.com.br/2016/02/rxjava-maximizing-parallelization.html) (8 examples)
48 |
49 | - **General Examples**
50 | - [Simulate Server Polling](https://medium.com/@v.danylo/server-polling-and-retrying-failed-operations-with-retrofit-and-rxjava-8bcc7e641a5a) (4 examples) - This example is useful when we need to poll a server periodically until it finishes a certain task.
51 | - [Server Polling After Local Data Processing](https://github.com/ReactiveX/RxJava/issues/448) (3 examples) - This example is useful when we need to poll a server and process some data locally, and only after finish local processing, poll the server again.
52 | - [Typing Indicator](http://androidahead.com/2017/04/03/typing-indicator-using-rxjava/) (1 example)
53 | - [Drawing Example](http://choruscode.blogspot.com.br/2014/07/rxjava-for-ui-events-on-android-example.html) (1 example) - This example shows how to react to mouse events as well as listen for SeekBar and menu item click events by using RxBindings library.
54 | - Broadcast System Status (1 example) - This example shows how to listen for broadcast system messages by using RxBroadcast library.
55 |
56 | # License
57 | This project is licensed under the Apache-2.0 - see the [LICENSE](LICENSE) file for details
58 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'kotlin-android'
3 | apply plugin: 'kotlin-android-extensions'
4 |
5 | android {
6 | compileSdkVersion 26
7 |
8 | defaultConfig {
9 | applicationId "com.motondon.rxjavademoapp"
10 | minSdkVersion 21
11 | targetSdkVersion 26
12 | versionCode 1
13 | versionName "1.0"
14 |
15 | }
16 |
17 | buildTypes {
18 | release {
19 | minifyEnabled false
20 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
21 | }
22 | }
23 | }
24 |
25 | dependencies {
26 | implementation fileTree(dir: 'libs', include: ['*.jar'])
27 | testImplementation'junit:junit:4.12'
28 | implementation"org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
29 | implementation 'com.android.support:appcompat-v7:26.1.0'
30 | implementation 'com.android.support:design:26.1.0'
31 | implementation 'com.android.support:recyclerview-v7:26.1.0'
32 | implementation 'com.android.support:cardview-v7:26.1.0'
33 |
34 | // Coroutines dependencies
35 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:0.19.2"
36 |
37 | // RxJava dependency
38 | implementation 'io.reactivex:rxjava:1.1.9'
39 |
40 | // RxAndroid dependency
41 | implementation 'io.reactivex:rxandroid:1.2.1'
42 |
43 | // RxBindings dependency
44 | implementation 'com.jakewharton.rxbinding:rxbinding:0.4.0'
45 |
46 | // RxBroadcast dependency
47 | implementation 'com.cantrowitz:rxbroadcast:1.0.0'
48 |
49 | // Mathematical operators dependency
50 | implementation 'io.reactivex:rxjava-math:1.0.0'
51 | }
52 |
--------------------------------------------------------------------------------
/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_dev_tools\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/motondon/rxjavademoapp/ApplicationTest.kt:
--------------------------------------------------------------------------------
1 | package com.motondon.rxjavademoapp
2 |
3 | import android.app.Application
4 | import android.test.ApplicationTestCase
5 |
6 | /**
7 | * [Testing Fundamentals](http://d.android.com/tools/testing/testing_android.html)
8 | */
9 | class ApplicationTest : ApplicationTestCase(Application::class.java)
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
27 |
28 |
32 |
33 |
37 |
38 |
42 |
43 |
47 |
48 |
52 |
53 |
57 |
58 |
62 |
63 |
67 |
68 |
72 |
73 |
77 |
78 |
82 |
83 |
87 |
88 |
92 |
93 |
97 |
98 |
102 |
103 |
107 |
108 |
112 |
113 |
117 |
118 |
122 |
123 |
127 |
128 |
129 |
133 |
134 |
138 |
139 |
143 |
144 |
148 |
149 |
153 |
154 |
155 |
156 |
157 |
--------------------------------------------------------------------------------
/app/src/main/java/com/motondon/rxjavademoapp/view/adapter/CategoryItemsAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.motondon.rxjavademoapp.view.adapter
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 | import android.support.v7.widget.RecyclerView
6 | import android.view.LayoutInflater
7 | import android.view.View
8 | import android.view.ViewGroup
9 |
10 | import com.motondon.rxjavademoapp.R
11 | import com.motondon.rxjavademoapp.view.main.CategoryItem
12 | import kotlinx.android.synthetic.main.item_category_list.view.*
13 |
14 | class CategoryItemsAdapter(private val mContext: Context, private val mCategoryItemList: List) : RecyclerView.Adapter() {
15 |
16 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
17 | val v = LayoutInflater.from(mContext).inflate(R.layout.item_category_list, parent, false)
18 | return ViewHolder(v)
19 | }
20 |
21 | override fun onBindViewHolder(holder: ViewHolder, position: Int) {
22 | holder.bind(position)
23 | }
24 |
25 | override fun getItemCount(): Int {
26 | return mCategoryItemList.size
27 | }
28 |
29 | inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
30 |
31 | fun bind(position: Int) {
32 | itemView.mCategoryItemName.text = mCategoryItemList[position].mExampleName
33 | itemView.mCategoryItemDetails.text = mCategoryItemList[position].mExampleDetails
34 |
35 | // When user clicks on an example, extract a class that implements that example and call it by using an intent.
36 | itemView.setOnClickListener { _ ->
37 | val exampleIntent = Intent(mContext, mCategoryItemList[position].mExampleActivityClass)
38 | exampleIntent.putExtra("TITLE", mCategoryItemList[position].mExampleName)
39 |
40 | mContext.startActivity(exampleIntent)
41 | }
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/app/src/main/java/com/motondon/rxjavademoapp/view/adapter/MainActivityAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.motondon.rxjavademoapp.view.adapter
2 |
3 | import android.content.Intent
4 | import android.support.v4.util.Pair
5 | import android.support.v7.widget.RecyclerView
6 | import android.view.LayoutInflater
7 | import android.view.View
8 | import android.view.ViewGroup
9 |
10 | import com.motondon.rxjavademoapp.R
11 | import com.motondon.rxjavademoapp.view.main.ExampleByCategoryActivity
12 | import com.motondon.rxjavademoapp.view.main.CategoryItem
13 | import com.motondon.rxjavademoapp.view.main.MainActivity
14 |
15 | import java.util.ArrayList
16 |
17 | import kotlinx.android.synthetic.main.item_cardview_options.view.*
18 |
19 | class MainActivityAdapter(private val mMainActivity: MainActivity, mExampleCategoriesList: List, Pair>>) : RecyclerView.Adapter() {
20 |
21 | private var mExampleCategoriesList = ArrayList, Pair>>()
22 |
23 | init {
24 | this.mExampleCategoriesList = mExampleCategoriesList as ArrayList, Pair>>
25 | }
26 |
27 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
28 | val view = LayoutInflater.from(parent.context).inflate(R.layout.item_cardview_options, parent, false)
29 | return ViewHolder(view)
30 | }
31 |
32 | override fun onBindViewHolder(holder: ViewHolder, position: Int) {
33 | holder.bind(position)
34 | }
35 |
36 | override fun getItemCount(): Int {
37 | return mExampleCategoriesList.size
38 | }
39 |
40 | inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
41 | fun bind(position: Int) {
42 | // Not too much to say here. We just get the item and set a listener for it. When user clicks on it, he will be redirected
43 | // to the activity that implements the selected example.
44 | val categoriesDetailsList = mExampleCategoriesList[position]
45 |
46 | val categoryItemList = categoriesDetailsList.first
47 | val item = categoriesDetailsList.second
48 |
49 | itemView.mCategoryName.text = item.first
50 | itemView.mCategoryDetails.text = item.second
51 |
52 | itemView.setOnClickListener { _ ->
53 | val exampleByCategoryIntent = Intent(mMainActivity.applicationContext, ExampleByCategoryActivity::class.java)
54 |
55 | exampleByCategoryIntent.putExtra("CATEGORY_ITEMS", categoryItemList as ArrayList<*>)
56 | exampleByCategoryIntent.putExtra("TITLE", itemView.mCategoryName.text.toString())
57 |
58 | mMainActivity.startActivity(exampleByCategoryIntent)
59 | }
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/app/src/main/java/com/motondon/rxjavademoapp/view/adapter/SimpleStringAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.motondon.rxjavademoapp.view.adapter
2 |
3 | import android.content.Context
4 | import android.support.v7.widget.RecyclerView
5 | import android.view.LayoutInflater
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import android.widget.Toast
9 |
10 | import com.motondon.rxjavademoapp.R
11 |
12 | import java.util.ArrayList
13 | import kotlinx.android.synthetic.main.item_list_single.view.*
14 |
15 | /**
16 | * Adapter used to map a String to a text view.
17 | */
18 | class SimpleStringAdapter(private val mContext: Context) : RecyclerView.Adapter() {
19 | private val mStrings = ArrayList()
20 |
21 | fun setStrings(newStrings: List) {
22 | mStrings.clear()
23 | mStrings.addAll(newStrings)
24 | notifyDataSetChanged()
25 | }
26 |
27 | fun addString(newString: String) {
28 | mStrings.add(newString)
29 | notifyDataSetChanged()
30 | }
31 |
32 | fun clear() {
33 | mStrings.clear()
34 | notifyDataSetChanged()
35 | }
36 |
37 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
38 | val view = LayoutInflater.from(parent.context).inflate(R.layout.item_list_single, parent, false)
39 | return ViewHolder(view)
40 | }
41 |
42 | override fun onBindViewHolder(holder: ViewHolder, position: Int) {
43 | holder.bind(position)
44 | }
45 |
46 | override fun getItemCount(): Int {
47 | return mStrings.size
48 | }
49 |
50 | inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
51 | fun bind(position: Int) {
52 | itemView.mItemName.text = mStrings[position]
53 | itemView.setOnClickListener { Toast.makeText(mContext, mStrings[position], Toast.LENGTH_SHORT).show() }
54 | }
55 |
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/app/src/main/java/com/motondon/rxjavademoapp/view/backpressure/BackpressureBasicExampleActivity.kt:
--------------------------------------------------------------------------------
1 | package com.motondon.rxjavademoapp.view.backpressure
2 |
3 | import android.os.Bundle
4 | import android.util.Log
5 |
6 | import android.widget.Toast
7 |
8 | import com.motondon.rxjavademoapp.R
9 | import com.motondon.rxjavademoapp.view.base.BaseActivity
10 |
11 | import java.util.concurrent.TimeUnit
12 |
13 | import kotlinx.android.synthetic.main.activity_backpressure_basic_example.*
14 | import rx.Observable
15 |
16 | import rx.Subscriber
17 | import rx.Subscription
18 | import rx.android.schedulers.AndroidSchedulers
19 |
20 | /**
21 | *
22 | * This activity shows two examples: one that emits items faster than they can be consumed. Quickly it will finish with a MissingBackpressureException.
23 | * The second one adds the throttleLast() operator to the chain in order to try to alliviate emitted items downstream to try to avoid that exception.
24 | *
25 | */
26 | class BackpressureBasicExampleActivity : BaseActivity() {
27 |
28 | override fun onCreate(savedInstanceState: Bundle?) {
29 | super.onCreate(savedInstanceState)
30 | setContentView(R.layout.activity_backpressure_basic_example)
31 |
32 | btnMissingBackpressureExceptionTest.setOnClickListener { onMissingBackPressureExceptionButtonClick() }
33 | btnThrottleOperatorTest.setOnClickListener { onThrottleOperatorButtonClick() }
34 |
35 | supportActionBar?.title = intent.getStringExtra("TITLE")
36 | }
37 |
38 | private fun resetData() {
39 | tvEmittedNumbers.text = ""
40 | tvResult.text = ""
41 | }
42 |
43 | private fun onMissingBackPressureExceptionButtonClick() {
44 | if (isUnsubscribed()) {
45 | Log.v(TAG, "onMissingBackPressureExceptionButtonClick()")
46 | resetData()
47 | mSubscription = starMissingBackpressureExceptionTest()
48 | } else {
49 | Toast.makeText(applicationContext, "Test is already running", Toast.LENGTH_LONG).show()
50 | }
51 | }
52 |
53 | private fun onThrottleOperatorButtonClick() {
54 | if (isUnsubscribed()) {
55 | Log.v(TAG, "onThrottleOperatorButtonClick()")
56 | resetData()
57 | tvEmittedNumbers.text = "Check the logs to see all emitted items"
58 | startThrottleOperatorTest()
59 | } else {
60 | Toast.makeText(applicationContext, "Test is already running", Toast.LENGTH_LONG).show()
61 | }
62 | }
63 |
64 | /**
65 | * This example will throw a MissingBackPressureException since the Observable is emitting items much faster
66 | * than they can be consumed.
67 | *
68 | * @return
69 | */
70 | private fun starMissingBackpressureExceptionTest(): Subscription {
71 |
72 | // Emit one item per millisecond...
73 | return Observable
74 | .interval(1, TimeUnit.MILLISECONDS)
75 |
76 | .doOnNext { number ->
77 | Log.v(TAG, "oOnNext() - Emitted number: $number")
78 | val w = AndroidSchedulers.mainThread().createWorker()
79 | w.schedule { tvEmittedNumbers.text = "${tvEmittedNumbers.text} $number" }
80 | }
81 |
82 | .compose(applySchedulers())
83 |
84 | // Sleep for 100ms for each emitted item. This will make we receive a BackpressureMissingException quickly.
85 | .subscribe(resultSubscriber(100))
86 | }
87 |
88 | /**
89 | * By using throttleLast operator (which is pretty much similar to collect) we reduce the chances to get a
90 | * MissingBackpressureException, since it will only emit the last item emitted in a certain period of time.
91 | *
92 | * For this example we are using throttleLast intervalDuration to 100ms, which might be enough to let observer to
93 | * process all emitted items. If we change intervalDuration to a small value (e.g.: 10ms), although we will still
94 | * use throttleLast operator, it will not be enough to prevent buffer's capacity to be full. Try both values to see
95 | * that in action.
96 | *
97 | * @return
98 | */
99 | private fun startThrottleOperatorTest(): Subscription {
100 |
101 | return Observable
102 | .interval(1, TimeUnit.MILLISECONDS)
103 |
104 | .doOnNext { number ->
105 | Log.v(TAG, "doOnNext() - Emitted number: $number")
106 |
107 | // For this example we will not print emitted items on the GUI, since it would freeze it. Check the logs to see all emitted items
108 | // final Scheduler.Worker w = AndroidSchedulers.mainThread().createWorker();
109 | // w.schedule(() -> tvEmittedNumbers.setText(tvEmittedNumbers.getText() + " " + number));
110 | }
111 |
112 | // Using throttleLast intervalDuration equals to 100ms, we will probably not end up in an exception, since our subscriber will be able to
113 | // process all emitted items accordingly. If we change it to 10ms, it will quickly throw a MissingBackpressureException.
114 | .throttleLast(100, TimeUnit.MILLISECONDS)
115 |
116 | // Just for log purpose
117 | .compose(showDebugMessages("throttleLast(100)"))
118 |
119 | // Just adding some boundaries here
120 | .take(20)
121 |
122 | .compose(applySchedulers())
123 |
124 | // Finally subscribe it.
125 | .subscribe(resultSubscriber(100))
126 | }
127 |
128 | private fun resultSubscriber(timeToSleep: Int): Subscriber {
129 | return object : Subscriber() {
130 |
131 | override fun onCompleted() {
132 | Log.v(TAG, "subscribe.onCompleted")
133 | val w2 = AndroidSchedulers.mainThread().createWorker()
134 | w2.schedule { tvResult.text = "${tvResult.text} - onCompleted" }
135 | }
136 |
137 | override fun onError(e: Throwable) {
138 | Log.v(TAG, "subscribe.doOnError: $e")
139 | val w2 = AndroidSchedulers.mainThread().createWorker()
140 | w2.schedule { tvResult.text = "${tvResult.text} - doOnError$e" }
141 | }
142 |
143 | override fun onNext(number: Long?) {
144 | Log.v(TAG, "subscribe.onNext $number")
145 | val w2 = AndroidSchedulers.mainThread().createWorker()
146 | w2.schedule { tvResult.text = "${tvResult.text} $number" }
147 |
148 | try {
149 | Thread.sleep(timeToSleep.toLong())
150 | } catch (e: InterruptedException) {
151 | Log.v(TAG, "subscribe.onNext. We got a InterruptedException!")
152 | }
153 | }
154 | }
155 | }
156 |
157 | companion object {
158 | private val TAG = BackpressureBasicExampleActivity::class.java.simpleName
159 | }
160 | }
161 |
--------------------------------------------------------------------------------
/app/src/main/java/com/motondon/rxjavademoapp/view/backpressure/BackpressureReactivePullExampleActivity.kt:
--------------------------------------------------------------------------------
1 | package com.motondon.rxjavademoapp.view.backpressure
2 |
3 | import android.os.Bundle
4 | import android.util.Log
5 | import android.widget.Toast
6 |
7 | import com.motondon.rxjavademoapp.R
8 | import com.motondon.rxjavademoapp.view.base.BaseActivity
9 |
10 | import java.util.concurrent.TimeUnit
11 |
12 | import kotlinx.android.synthetic.main.activity_backpressure_reactive_pull_example.*
13 | import rx.Observable
14 |
15 | import rx.Subscriber
16 | import rx.Subscription
17 | import rx.android.schedulers.AndroidSchedulers
18 |
19 |
20 | class BackpressureReactivePullExampleActivity : BaseActivity() {
21 |
22 | override fun onCreate(savedInstanceState: Bundle?) {
23 | super.onCreate(savedInstanceState)
24 | setContentView(R.layout.activity_backpressure_reactive_pull_example)
25 |
26 | btnSubscriberWithRequestMethodCallTest.setOnClickListener { onSubscriberWithRequestMethodCallButtonClick() }
27 |
28 | supportActionBar?.title = intent.getStringExtra("TITLE")
29 | }
30 |
31 | private fun resetData() {
32 | tvEmittedNumbers.text = ""
33 | tvResult.text = ""
34 | }
35 |
36 | private fun onSubscriberWithRequestMethodCallButtonClick() {
37 | if (isUnsubscribed()) {
38 | Log.v(TAG, "onSubscriberWithRequestMethodCallButtonClick()")
39 | resetData()
40 | startSubscriberWithRequestMethodCallTest()
41 | } else {
42 | Toast.makeText(applicationContext, "Test is already running", Toast.LENGTH_LONG).show()
43 | }
44 | }
45 |
46 | private fun emitNumbers(numberOfItemsToEmit: Int, timeToSleep: Int): Observable {
47 | Log.v(TAG, "emitNumbers()")
48 |
49 | return Observable
50 | .range(0, numberOfItemsToEmit)
51 | .doOnNext { number ->
52 | try {
53 | Log.v(TAG, "emitNumbers() - Emitting number: $number")
54 | Thread.sleep(timeToSleep.toLong())
55 |
56 | val w = AndroidSchedulers.mainThread().createWorker()
57 | w.schedule { tvEmittedNumbers.text = "${tvEmittedNumbers.text} $number" }
58 |
59 | } catch (e: InterruptedException) {
60 | Log.v(TAG, "Got an InterruptedException!")
61 | }
62 | }
63 | }
64 |
65 | /**
66 | * This example demonstrates how to use Subscriber::request() method. Since our subscriber was initialized by calling
67 | * Subscriber::request(1), that means one item will be requested at a time. Later, in Subscriber's onNext, only after
68 | * it processes an item, another one will be requested.
69 | *
70 | * @return
71 | */
72 | private fun startSubscriberWithRequestMethodCallTest(): Subscription {
73 |
74 | return Observable
75 | .timer(0, TimeUnit.SECONDS)
76 | .flatMap { _ -> emitNumbers(20, 10) }
77 |
78 | // Since our subscriber will request for item, this is one way on how we can log it.
79 | .doOnRequest { number -> Log.v(TAG, "Requested $number") }
80 |
81 | // Subscribe our subscriber which will request for items.
82 | .subscribe(resultSubscriber())
83 | }
84 |
85 | private fun resultSubscriber(): Subscriber {
86 | return object : Subscriber() {
87 |
88 | override fun onStart() {
89 | request(1)
90 | }
91 |
92 | override fun onCompleted() {
93 | Log.v(TAG, "subscribe.onCompleted")
94 | val w2 = AndroidSchedulers.mainThread().createWorker()
95 | w2.schedule { tvResult.text = "${tvResult.text} - onCompleted" }
96 | }
97 |
98 | override fun onError(e: Throwable) {
99 | Log.v(TAG, "subscribe.doOnError: $e")
100 | val w2 = AndroidSchedulers.mainThread().createWorker()
101 | w2.schedule { tvResult.text = "${tvResult.text} - doOnError$e" }
102 | }
103 |
104 | override fun onNext(number: Int?) {
105 | Log.v(TAG, "subscribe.onNext $number")
106 |
107 | try {
108 | // Sleep for a while. We could do whatever we want here prior to request a new item. This is totally
109 | // up to us
110 | Thread.sleep(500)
111 |
112 | // Now, after "processing" the item, request observable to emit another one
113 | request(1)
114 | } catch (e: InterruptedException) {
115 | Log.v(TAG, "subscribe.onNext. We got a InterruptedException!")
116 | }
117 |
118 | val w2 = AndroidSchedulers.mainThread().createWorker()
119 | w2.schedule { tvResult.text = tvResult.text.toString() + " " + number }
120 | }
121 | }
122 | }
123 |
124 | companion object {
125 | private val TAG = BackpressureReactivePullExampleActivity::class.java.simpleName
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/app/src/main/java/com/motondon/rxjavademoapp/view/base/BaseActivity.kt:
--------------------------------------------------------------------------------
1 | package com.motondon.rxjavademoapp.view.base
2 |
3 | import android.content.Intent
4 | import android.support.v4.app.NavUtils
5 | import android.support.v7.app.AppCompatActivity
6 | import android.util.Log
7 | import android.view.MenuItem
8 | import android.widget.TextView
9 |
10 | import rx.Observable
11 | import rx.Subscriber
12 | import rx.Subscription
13 | import rx.android.schedulers.AndroidSchedulers
14 | import rx.schedulers.Schedulers
15 |
16 | open class BaseActivity : AppCompatActivity() {
17 |
18 | protected var mSubscription: Subscription? = null
19 |
20 | override fun onOptionsItemSelected(item: MenuItem): Boolean {
21 | when (item.itemId) {
22 | // Respond to the action bar's Up/Home button
23 | android.R.id.home -> {
24 | val intent = NavUtils.getParentActivityIntent(this)
25 | intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
26 | NavUtils.navigateUpTo(this, intent)
27 | return true
28 | }
29 | }
30 | return super.onOptionsItemSelected(item)
31 | }
32 |
33 | protected fun resultSubscriber(view: TextView): Subscriber {
34 | return object : Subscriber() {
35 |
36 | override fun onCompleted() {
37 | Log.v(TAG, "subscribe.onCompleted")
38 | view.text = "${view.text} - onCompleted"
39 | }
40 |
41 | override fun onError(e: Throwable) {
42 | Log.v(TAG, "subscribe.doOnError: ${e.message}")
43 | view.text = "${view.text} - doOnError"
44 | }
45 |
46 | override fun onNext(number: T) {
47 | Log.v(TAG, "subscribe.onNext")
48 | view.text = "${view.text} $number"
49 | }
50 | }
51 | }
52 |
53 | /**
54 | * Print log messages for some side effects methods (or utility methods).
55 | *
56 | * Note that, when calling this method by using Java 7, we must inform explicitly the type T. Otherwise it will assume the Object type, which
57 | * is not compatible,and we will get an error. But when using Java 8, this is no longer needed, since the compiler will infer the correct type.
58 | * This is called a type witness.
59 | *
60 | * From the docs:
61 | *
62 | * "The Java SE 7 compiler [...] requires a value for the type argument T so it starts with the value Object. Consequently, the invocation
63 | * of Collections.emptyList returns a value of type List */
72 | protected fun showDebugMessages(operatorName: String): Observable.Transformer {
73 |
74 | return Observable.Transformer { observable ->
75 | observable
76 | .doOnSubscribe { Log.v(TAG, "$operatorName.doOnSubscribe") }
77 | .doOnUnsubscribe { Log.v(TAG, "$operatorName.doOnUnsubscribe") }
78 | .doOnNext { doOnNext -> Log.v(TAG, "$operatorName.doOnNext. Data: $doOnNext") }
79 | .doOnCompleted { Log.v(TAG, "$operatorName.doOnCompleted") }
80 | .doOnTerminate { Log.v(TAG, "$operatorName.doOnTerminate") }
81 | .doOnError { throwable -> Log.v(TAG, "$operatorName.doOnError: ${throwable.message}") }
82 | }
83 | }
84 |
85 | /**
86 | * Code downloaded from: http://blog.danlew.net/2015/03/02/dont-break-the-chain/
87 | *
88 | * @param
89 | * @return
90 | */
91 | protected fun applySchedulers(): Observable.Transformer {
92 | return Observable.Transformer { observable ->
93 | observable.subscribeOn(Schedulers.computation())
94 | .observeOn(AndroidSchedulers.mainThread())
95 | }
96 | }
97 |
98 | protected fun isUnsubscribed(): Boolean {
99 | return mSubscription?.let {
100 | it.isUnsubscribed
101 | } ?: true
102 | }
103 |
104 | companion object {
105 | private val TAG = BaseActivity::class.java.simpleName
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/app/src/main/java/com/motondon/rxjavademoapp/view/base/HotObservablesBaseActivity.kt:
--------------------------------------------------------------------------------
1 | package com.motondon.rxjavademoapp.view.base
2 |
3 | import android.util.Log
4 | import android.widget.Toast
5 |
6 | import rx.Subscription
7 | import rx.observables.ConnectableObservable
8 |
9 | open class HotObservablesBaseActivity : BaseActivity() {
10 |
11 | protected var connectable: ConnectableObservable? = null
12 | protected var firstSubscription: Subscription? = null
13 | protected var secondSubscription: Subscription? = null
14 |
15 | /**
16 | * When unsubscribing a subscriber, that means it will stop receiving emitted items.
17 | *
18 | */
19 | protected fun unsubscribeFirst(showMessage: Boolean) {
20 | Log.v(TAG, "unsubscribeFirst()")
21 |
22 | firstSubscription?.let {
23 | if (!it.isUnsubscribed) {
24 | Log.v(TAG, "unsubscribeFirst() - Calling unsubscribe...")
25 | it.unsubscribe()
26 | } else {
27 | if (showMessage) {
28 | Toast.makeText(applicationContext, "Subscriber not started", Toast.LENGTH_SHORT).show()
29 | }
30 | }
31 | } ?: run {
32 | if (showMessage) {
33 | Toast.makeText(applicationContext, "Subscriber not started", Toast.LENGTH_SHORT).show()
34 | }
35 | }
36 | }
37 |
38 | /**
39 | * When unsubscribing a subscriber, that means it will stop receiving emitted items.
40 | *
41 | */
42 | protected fun unsubscribeSecond(showMessage: Boolean) {
43 | Log.v(TAG, "unsubscribeSecond()")
44 |
45 | secondSubscription?.let {
46 | if (!it.isUnsubscribed) {
47 | Log.v(TAG, "unsubscribeSecond() - Calling unsubscribe...")
48 | it.unsubscribe()
49 | } else {
50 | if (showMessage) {
51 | Toast.makeText(applicationContext, "Subscriber not started", Toast.LENGTH_SHORT).show()
52 | }
53 | }
54 | } ?: run {
55 | if (showMessage) {
56 | Toast.makeText(applicationContext, "Subscriber not started", Toast.LENGTH_SHORT).show()
57 | }
58 | }
59 | }
60 |
61 | protected fun isFirstSubscriptionUnsubscribed(): Boolean {
62 | return firstSubscription?.let {
63 | it.isUnsubscribed
64 | } ?: true
65 | }
66 |
67 | protected fun isSecondSubscriptionUnsubscribed(): Boolean {
68 | return secondSubscription?.let {
69 | it.isUnsubscribed
70 | } ?: true
71 | }
72 |
73 | companion object {
74 | private val TAG = HotObservablesBaseActivity::class.java.simpleName
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/app/src/main/java/com/motondon/rxjavademoapp/view/hotobservables/HotObservableCacheExampleActivity.kt:
--------------------------------------------------------------------------------
1 | package com.motondon.rxjavademoapp.view.hotobservables
2 |
3 | import android.os.Bundle
4 | import android.support.v7.app.ActionBar
5 | import android.util.Log
6 | import android.widget.TextView
7 | import android.widget.Toast
8 |
9 | import com.motondon.rxjavademoapp.R
10 | import com.motondon.rxjavademoapp.view.base.HotObservablesBaseActivity
11 |
12 | import java.util.concurrent.TimeUnit
13 |
14 | import kotlinx.android.synthetic.main.activity_hot_observable_cache_example.*
15 | import rx.Observable
16 | import rx.Scheduler
17 | import rx.Subscription
18 | import rx.android.schedulers.AndroidSchedulers
19 |
20 | /**
21 | * This example demonstrates how to use ConnectableObservable::cache() operator.
22 | *
23 | * It ensures that all observers see the same sequence of emitted items, even if they subscribe after the Observable has begun emitting items.
24 | *
25 | */
26 | class HotObservableCacheExampleActivity : HotObservablesBaseActivity() {
27 |
28 | private var observable: Observable? = null
29 |
30 | override fun onCreate(savedInstanceState: Bundle?) {
31 | super.onCreate(savedInstanceState)
32 | setContentView(R.layout.activity_hot_observable_cache_example)
33 |
34 | btnCache.setOnClickListener{ onCacheButtonClick() }
35 | btnSubscribeFirst.setOnClickListener{ onSubscribeFirstButtonClick() }
36 | btnSubscribeSecond.setOnClickListener{ onSubscribeSecondButtonClick() }
37 | btnUnsubscribeFirst.setOnClickListener{ onUnsubscribeFirstButtonClick() }
38 | btnUnsubscribeSecond.setOnClickListener{ onUnsubscribeSecondButtonClick() }
39 |
40 | supportActionBar?.title = intent.getStringExtra("TITLE")
41 | }
42 |
43 | private fun resetData() {
44 | tvEmittedNumbers.text = ""
45 | tvResultFirstSubscription.text = ""
46 | tvResultSecondSubscription.text = ""
47 | }
48 |
49 | private fun onCacheButtonClick() {
50 | if (isUnsubscribed()) {
51 | Log.v(TAG, "onCacheButtonClick()")
52 | resetData()
53 | cache()
54 | } else {
55 | Toast.makeText(applicationContext, "Test is already running", Toast.LENGTH_SHORT).show()
56 | }
57 | }
58 |
59 | private fun onSubscribeFirstButtonClick() {
60 |
61 | if (observable == null) {
62 | Log.v(TAG, "onSubscribeFirstButtonClick() - Cannot start a subscriber. You must first call cache().")
63 |
64 | Toast.makeText(applicationContext, "You must first call cache()", Toast.LENGTH_SHORT).show()
65 | return
66 | }
67 |
68 | if (isFirstSubscriptionUnsubscribed()) {
69 | Log.v(TAG, "onSubscribeFirstButtonClick()")
70 | firstSubscription = subscribeFirst()
71 | } else {
72 | Toast.makeText(applicationContext, "First subscriber already started", Toast.LENGTH_SHORT).show()
73 | }
74 | }
75 |
76 | private fun onSubscribeSecondButtonClick() {
77 |
78 | if (observable == null) {
79 | Log.v(TAG, "onSubscribeFirstButtonClick() - Cannot start a subscriber. You must first call cache().")
80 |
81 | Toast.makeText(applicationContext, "You must first call cache()", Toast.LENGTH_SHORT).show()
82 | return
83 | }
84 | if (isSecondSubscriptionUnsubscribed()) {
85 | Log.v(TAG, "onSubscribeSecondButtonClick()")
86 | secondSubscription = subscribeSecond()
87 | } else {
88 | Toast.makeText(applicationContext, "Second subscriber already started", Toast.LENGTH_SHORT).show()
89 | }
90 | }
91 |
92 | private fun onUnsubscribeFirstButtonClick() {
93 | Log.v(TAG, "onUnsubscribeFirstButtonClick()")
94 | unsubscribeFirst(true)
95 | }
96 |
97 | private fun onUnsubscribeSecondButtonClick() {
98 | Log.v(TAG, "onUnsubscribeSecondButtonClick()")
99 | unsubscribeSecond(true)
100 | }
101 |
102 | /**
103 | * When calling cache, that will NOT make observable to start emit items. It will only start emitting items when a first
104 | * subscriber subscribes to it. Then, it will receive all cached items.
105 | *
106 | * Just using take(30) in order to prevent it to emit forever.
107 | *
108 | * @return
109 | */
110 | private fun cache() {
111 | Log.v(TAG, "cache()")
112 |
113 | // cache returns Observable that is connected as long as there are subscribers to it.
114 | observable = Observable
115 | .interval(750, TimeUnit.MILLISECONDS)
116 | .doOnNext { number ->
117 | val w = AndroidSchedulers.mainThread().createWorker()
118 | w.schedule { tvEmittedNumbers.text = "${tvEmittedNumbers.text} $number" }
119 | }
120 |
121 | // Prevent our observable to emit forever
122 | .take(30)
123 |
124 | .cache()
125 | }
126 |
127 | /**
128 | * If this is the first mSubscription, it will make observable to start emitting items. But, if there is
129 | * already another mSubscription, it means that observable has already started emitting items and collecting them.
130 | * So, after we subscribe to it, it will first receive all collected items.
131 | *
132 | * @return
133 | */
134 | private fun subscribeFirst(): Subscription? {
135 | Log.v(TAG, "subscribeFirst()")
136 |
137 | return observable?.let {
138 | it
139 | .compose(applySchedulers())
140 | .subscribe(this@HotObservableCacheExampleActivity.resultSubscriber(tvResultFirstSubscription))
141 | } ?: null
142 | }
143 |
144 | /**
145 | * If this is the first mSubscription, it will make observable to start emitting items. But, if there is
146 | * already another mSubscription, it means that observable has already started emitting items and collecting them.
147 | * So, after we subscribe to it, it will first receive all collected items.
148 | *
149 | * @return
150 | */
151 | private fun subscribeSecond(): Subscription? {
152 | Log.v(TAG, "subscribeSecond()")
153 |
154 | return observable?.let {
155 | it
156 | .compose(applySchedulers())
157 | .subscribe(resultSubscriber(tvResultSecondSubscription))
158 | } ?: null
159 | }
160 |
161 | companion object {
162 | private val TAG = HotObservableCacheExampleActivity::class.java.simpleName
163 | }
164 | }
165 |
--------------------------------------------------------------------------------
/app/src/main/java/com/motondon/rxjavademoapp/view/hotobservables/HotObservableConnectExampleActivity.kt:
--------------------------------------------------------------------------------
1 | package com.motondon.rxjavademoapp.view.hotobservables
2 |
3 | import android.os.Bundle
4 | import android.support.v7.app.ActionBar
5 | import android.util.Log
6 | import android.widget.TextView
7 | import android.widget.Toast
8 |
9 | import com.motondon.rxjavademoapp.R
10 | import com.motondon.rxjavademoapp.view.base.HotObservablesBaseActivity
11 |
12 | import java.util.concurrent.TimeUnit
13 |
14 | import kotlinx.android.synthetic.main.activity_hot_observable_connect_example.*
15 | import rx.Observable
16 | import rx.Scheduler
17 | import rx.Subscription
18 | import rx.android.schedulers.AndroidSchedulers
19 |
20 | /**
21 | * This example demonstrates how to use ConnectableObservable::connect() operator.
22 | *
23 | */
24 | class HotObservableConnectExampleActivity : HotObservablesBaseActivity() {
25 |
26 | override fun onCreate(savedInstanceState: Bundle?) {
27 | super.onCreate(savedInstanceState)
28 | setContentView(R.layout.activity_hot_observable_connect_example)
29 |
30 | btnConnect.setOnClickListener{ onConnectButtonClick() }
31 | btnSubscribeFirst.setOnClickListener{ onSubscribeFirstButtonClick() }
32 | btnSubscribeSecond.setOnClickListener{ onSubscribeSecondButtonClick() }
33 | btnUnsubscribeFirst.setOnClickListener{ onUnsubscribeFirstButtonClick() }
34 | btnUnsubscribeSecond.setOnClickListener{ onUnsubscribeSecondButtonClick() }
35 | btnDisconnect.setOnClickListener{ onDisconnectButtonClick() }
36 |
37 | supportActionBar?.title = intent.getStringExtra("TITLE")
38 |
39 | // We will create the ConnectableObservable in the onCreate() method, so it will be available for the two
40 | // subscribers to subscribe to it, even before call ConnectionObservable::connect().
41 | connectable = Observable
42 | .interval(500, TimeUnit.MILLISECONDS)
43 | .doOnNext { number ->
44 | val w = AndroidSchedulers.mainThread().createWorker()
45 | w.schedule { tvEmittedNumbers.text = "${tvEmittedNumbers.text} $number" }
46 | }
47 |
48 | // This will convert the Observable to a ConnectableObservable
49 | .publish()
50 | }
51 |
52 | private fun resetData() {
53 | tvEmittedNumbers.text = ""
54 | tvResultFirstSubscription.text = ""
55 | tvResultSecondSubscription.text = ""
56 | }
57 |
58 | private fun onConnectButtonClick() {
59 | if (isUnsubscribed()) {
60 | Log.v(TAG, "onConnectButtonClick()")
61 | resetData()
62 | mSubscription = connect()
63 | } else {
64 | Toast.makeText(applicationContext, "Test is already running", Toast.LENGTH_SHORT).show()
65 | }
66 | }
67 |
68 | private fun onSubscribeFirstButtonClick() {
69 | if (isFirstSubscriptionUnsubscribed()) {
70 | Log.v(TAG, "onSubscribeFirstButtonClick()")
71 | firstSubscription = subscribeFirst()
72 | } else {
73 | Toast.makeText(applicationContext, "First subscriber already started", Toast.LENGTH_SHORT).show()
74 | }
75 | }
76 |
77 | private fun onSubscribeSecondButtonClick() {
78 | if (isSecondSubscriptionUnsubscribed()) {
79 | Log.v(TAG, "onSubscribeSecondButtonClick()")
80 | secondSubscription = subscribeSecond()
81 | } else {
82 | Toast.makeText(applicationContext, "Second subscriber already started", Toast.LENGTH_SHORT).show()
83 | }
84 | }
85 |
86 | private fun onUnsubscribeFirstButtonClick() {
87 | Log.v(TAG, "onUnsubscribeFirstButtonClick()")
88 | unsubscribeFirst(true)
89 | }
90 |
91 | private fun onUnsubscribeSecondButtonClick() {
92 | Log.v(TAG, "onUnsubscribeSecondButtonClick()")
93 | unsubscribeSecond(true)
94 | }
95 |
96 | private fun onDisconnectButtonClick() {
97 | Log.v(TAG, "onDisconnectButtonClick()")
98 |
99 | mSubscription?.let {
100 | if (!it.isUnsubscribed) {
101 | unsubscribeFirst(false)
102 | unsubscribeSecond(false)
103 | disconnect()
104 | }
105 | } ?: Toast.makeText(applicationContext, "Observable not connected", Toast.LENGTH_SHORT).show()
106 | }
107 |
108 | /**
109 | * From the docs:
110 | *
111 | * "A Connectable Observable resembles an ordinary Observable, except that it does not begin emitting items when
112 | * it is subscribed to, but only when its connect() method is called."
113 | *
114 | * This means that when user clicks on "connect" button, if there is already any subscriber subscribed to it, it will start
115 | * receiving emitted items, otherwise, emitted items will be discarded.
116 | *
117 | * After connecting to the observable, new subscribers will only receive new emitted items.
118 | *
119 | * @return
120 | */
121 | private fun connect(): Subscription? {
122 | Log.v(TAG, "connect()")
123 |
124 | // This will instruct the connectable observable to begin emitting items. If there is any subscriber subscribed to it,
125 | // it will start receiving items.
126 | return connectable?.connect()
127 | }
128 |
129 | /**
130 | * If observable is already connected, when this button is pressed, this subscriber will start receiving items. If there is no
131 | * connection yet, nothing will happen (until a mSubscription)
132 | *
133 | * @return
134 | */
135 | private fun subscribeFirst(): Subscription? {
136 | Log.v(TAG, "subscribeFirst()")
137 |
138 | return connectable?.let {
139 | it
140 | .compose(applySchedulers())
141 | .subscribe(resultSubscriber(tvResultFirstSubscription))
142 | } ?: null
143 | }
144 |
145 | /**
146 | * If observable is already connected, when this button is pressed, this subscriber will start receiving items. If there is no
147 | * connection yet, nothing will happen (until a mSubscription)
148 | *
149 | * @return
150 | */
151 | private fun subscribeSecond(): Subscription? {
152 | Log.v(TAG, "subscribeSecond()")
153 |
154 | return connectable?.let {
155 | it
156 | .compose(applySchedulers())
157 | .subscribe(resultSubscriber(tvResultSecondSubscription))
158 | } ?: null
159 | }
160 |
161 | /**
162 | * By unsubscribing the mSubscription returned by the connect() method, all subscriptions will stop receiving items.
163 | *
164 | */
165 | private fun disconnect() {
166 | Log.v(TAG, "disconnect()")
167 | mSubscription?.unsubscribe()
168 | mSubscription = null
169 | }
170 |
171 | companion object {
172 | private val TAG = HotObservableConnectExampleActivity::class.java.simpleName
173 | }
174 | }
175 |
--------------------------------------------------------------------------------
/app/src/main/java/com/motondon/rxjavademoapp/view/hotobservables/HotObservableRefCountExampleActivity.kt:
--------------------------------------------------------------------------------
1 | package com.motondon.rxjavademoapp.view.hotobservables
2 |
3 | import android.os.Bundle
4 | import android.support.v7.app.ActionBar
5 | import android.util.Log
6 | import android.widget.TextView
7 | import android.widget.Toast
8 |
9 | import com.motondon.rxjavademoapp.R
10 | import com.motondon.rxjavademoapp.view.base.HotObservablesBaseActivity
11 |
12 | import java.util.concurrent.TimeUnit
13 |
14 | import kotlinx.android.synthetic.main.activity_hot_observable_refcount_example.*
15 | import rx.Observable
16 | import rx.Scheduler
17 | import rx.Subscription
18 | import rx.android.schedulers.AndroidSchedulers
19 |
20 | /**
21 | * This example demonstrates how to use ConnectableObservable::refCount() operator.
22 | *
23 | * refCount keeps a reference to all the subscribers subscribed to it. When we call refCount, observable does not start emitting items, but only when
24 | * the first subscriber subscribe to it.
25 | *
26 | */
27 | class HotObservableRefCountExampleActivity : HotObservablesBaseActivity() {
28 |
29 | // This is the Observable returned by the refCount() method call. Subscribers must use it to subscribe.
30 | private var observable: Observable? = null
31 |
32 | override fun onCreate(savedInstanceState: Bundle?) {
33 | super.onCreate(savedInstanceState)
34 | setContentView(R.layout.activity_hot_observable_refcount_example)
35 |
36 | btnRefCount.setOnClickListener{ onRefCountButtonClick() }
37 | btnSubscribeFirst.setOnClickListener{ onSubscribeFirstButtonClick() }
38 | btnSubscribeSecond.setOnClickListener{ onSubscribeSecondButtonClick() }
39 | btnUnsubscribeFirst.setOnClickListener{ onUnsubscribeFirstButtonClick() }
40 | btnUnsubscribeSecond.setOnClickListener{ onUnsubscribeSecondButtonClick() }
41 |
42 | supportActionBar?.title = intent.getStringExtra("TITLE")
43 |
44 | // Just start our Hot Observable. Note that this will NOT make it to start emitting items
45 | connectable = Observable
46 | .interval(500, TimeUnit.MILLISECONDS)
47 | .doOnNext { number ->
48 | val w = AndroidSchedulers.mainThread().createWorker()
49 | w.schedule { tvEmittedNumbers.text = "${tvEmittedNumbers.text} $number" }
50 | }
51 |
52 | // This will convert the Observable to a ConnectableObservable
53 | .publish()
54 | }
55 |
56 | private fun resetData() {
57 | tvEmittedNumbers.text = ""
58 | tvResultFirstSubscription.text = ""
59 | tvResultSecondSubscription.text = ""
60 | }
61 |
62 | private fun onRefCountButtonClick() {
63 |
64 | if (isFirstSubscriptionUnsubscribed() && (isSecondSubscriptionUnsubscribed())) {
65 |
66 | Log.v(TAG, "onRefCountButtonClick()")
67 | resetData()
68 | refCount()
69 | } else {
70 | Toast.makeText(applicationContext, "Test is already running", Toast.LENGTH_SHORT).show()
71 | }
72 | }
73 |
74 | private fun onSubscribeFirstButtonClick() {
75 | if (observable == null) {
76 | Log.v(TAG, "onSubscribeFirstButtonClick() - Cannot start a subscriber. You must first call refCount().")
77 |
78 | // When using refCount, we must subscribe our subscriber's upon the Observable returned by the refCount, and not on the
79 | // ConnectableObservable returned by the publish() (as we do when using connect() operator).
80 | Toast.makeText(applicationContext, "You must first call refCount()", Toast.LENGTH_SHORT).show()
81 | return
82 | }
83 |
84 | if (isFirstSubscriptionUnsubscribed()) {
85 |
86 | // Just clean up GUI in order to make things clear.
87 | secondSubscription?.let {
88 | if (it.isUnsubscribed) resetData()
89 | }
90 |
91 | Log.v(TAG, "onSubscribeFirstButtonClick()")
92 | firstSubscription = subscribeFirst()
93 |
94 | } else {
95 | Toast.makeText(applicationContext, "First subscriber already started", Toast.LENGTH_SHORT).show()
96 | }
97 | }
98 |
99 | private fun onSubscribeSecondButtonClick() {
100 | if (observable == null) {
101 | Log.v(TAG, "onSubscribeSecondButtonClick() - Cannot start a subscriber. You must first call refCount().")
102 |
103 | // When using refCount, we must subscribe our subscriber's upon the Observable returned by the refCount, and not on the
104 | // ConnectableObservable returned by the publish() (as we do when using connect() operator).
105 | Toast.makeText(applicationContext, "You must first call refCount()", Toast.LENGTH_SHORT).show()
106 | return
107 | }
108 |
109 | if (isSecondSubscriptionUnsubscribed()) {
110 |
111 | // Just clean up GUI in order to make things clear.
112 | firstSubscription?.let {
113 | if (it.isUnsubscribed) resetData()
114 | }
115 |
116 | Log.v(TAG, "onSubscribeSecondButtonClick()")
117 | secondSubscription = subscribeSecond()
118 |
119 | } else {
120 | Toast.makeText(applicationContext, "Second subscriber already started", Toast.LENGTH_SHORT).show()
121 | }
122 | }
123 |
124 | /**
125 | * When unsubscribing a subscriber, if there is no more subscriber subscribed to the observable, it will stop emit items.
126 | *
127 | */
128 | private fun onUnsubscribeFirstButtonClick() {
129 | Log.v(TAG, "onUnsubscribeFirstButtonClick()")
130 | unsubscribeFirst(true)
131 | }
132 |
133 | /**
134 | * When unsubscribing a subscriber, if there is no more subscriber subscribed to the observable, it will stop emit items.
135 | *
136 | */
137 | private fun onUnsubscribeSecondButtonClick() {
138 | Log.v(TAG, "onUnsubscribeSecondButtonClick()")
139 | unsubscribeSecond(true)
140 | }
141 |
142 | private fun refCount() {
143 | Log.v(TAG, "refCount()")
144 |
145 | // refCount returns Observable that is connected as long as there are subscribers to it.
146 | observable = connectable?.refCount()
147 | }
148 |
149 | /**
150 | * If this is the first subscriber to subscribe to the observable, it will make observable to start emitting items.
151 | *
152 | * @return
153 | */
154 | private fun subscribeFirst(): Subscription? {
155 | Log.v(TAG, "subscribeFirst()")
156 |
157 | return observable?.let {
158 | it
159 | .compose(applySchedulers())
160 | .subscribe(resultSubscriber(tvResultFirstSubscription))
161 | } ?: null
162 | }
163 |
164 | /**
165 | * If this is the first subscriber to subscribe to the observable, it will make observable to start emitting items.
166 | *
167 | * @return
168 | */
169 | private fun subscribeSecond(): Subscription? {
170 | Log.v(TAG, "subscribeSecond()")
171 |
172 | return observable?.let {
173 | it
174 | .compose(applySchedulers())
175 | .subscribe(resultSubscriber(tvResultSecondSubscription))
176 | } ?: null
177 | }
178 |
179 | companion object {
180 | private val TAG = HotObservableRefCountExampleActivity::class.java.simpleName
181 | }
182 | }
183 |
--------------------------------------------------------------------------------
/app/src/main/java/com/motondon/rxjavademoapp/view/main/CategoryItem.kt:
--------------------------------------------------------------------------------
1 | package com.motondon.rxjavademoapp.view.main
2 |
3 | import android.app.Activity
4 |
5 | import java.io.Serializable
6 |
7 | /**
8 | * Pair consisting of the name of an example and the activity corresponding to the example.
9 | *
10 | */
11 | class CategoryItem(
12 | val mExampleActivityClass: Class, val mExampleName: String, val mExampleDetails: String) : Serializable
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/java/com/motondon/rxjavademoapp/view/main/ExampleByCategoryActivity.kt:
--------------------------------------------------------------------------------
1 | package com.motondon.rxjavademoapp.view.main
2 |
3 | import android.os.Bundle
4 | import android.support.v7.app.AppCompatActivity
5 | import android.support.v7.widget.LinearLayoutManager
6 |
7 | import com.motondon.rxjavademoapp.R
8 | import com.motondon.rxjavademoapp.view.adapter.CategoryItemsAdapter
9 |
10 | import java.util.ArrayList
11 |
12 | import kotlinx.android.synthetic.main.activity_example_by_category.*
13 |
14 | class ExampleByCategoryActivity : AppCompatActivity() {
15 |
16 | private var title: String? = null
17 | private var categoryItems = ArrayList()
18 |
19 | override fun onCreate(savedInstanceState: Bundle?) {
20 | super.onCreate(savedInstanceState)
21 | setContentView(R.layout.activity_example_by_category)
22 |
23 | if (supportActionBar != null) {
24 |
25 | if (savedInstanceState != null) {
26 | title = savedInstanceState.getString("TITLE")
27 | categoryItems = savedInstanceState.getSerializable("CATEGORY_ITEMS") as ArrayList
28 | } else {
29 | title = intent.extras?.getString("TITLE")
30 |
31 | // Get the examples lists from the intent and set it to the adapter. They will be available to users and will allow them to
32 | // click over an option and be redirected to an activity which implements that example.
33 | categoryItems = intent.extras?.getSerializable("CATEGORY_ITEMS") as ArrayList
34 | }
35 | supportActionBar?.title = title
36 | }
37 |
38 | examplesByCategoryList.setHasFixedSize(true)
39 | examplesByCategoryList.layoutManager = LinearLayoutManager(this)
40 | examplesByCategoryList.adapter = CategoryItemsAdapter(this, categoryItems)
41 | }
42 |
43 | override fun onSaveInstanceState(outState: Bundle) {
44 | super.onSaveInstanceState(outState)
45 |
46 | outState.putString("TITLE", title)
47 | outState.putSerializable("CATEGORY_ITEMS", categoryItems)
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/app/src/main/java/com/motondon/rxjavademoapp/view/operators/ConcatMapAndFlatMapExampleActivity.kt:
--------------------------------------------------------------------------------
1 | package com.motondon.rxjavademoapp.view.operators
2 |
3 | import android.content.ContentValues.TAG
4 | import android.os.Bundle
5 | import android.util.Log
6 | import android.widget.TextView
7 | import android.widget.Toast
8 |
9 | import com.motondon.rxjavademoapp.R
10 | import com.motondon.rxjavademoapp.R.id.*
11 | import com.motondon.rxjavademoapp.view.base.BaseActivity
12 |
13 | import java.util.concurrent.TimeUnit
14 |
15 | import kotlinx.android.synthetic.main.activity_operators_concatmap_flatmap_example.*
16 | import rx.Observable
17 | import rx.Subscription
18 | import rx.android.schedulers.AndroidSchedulers
19 |
20 | /**
21 | * Examples on this activity are based on the following article:
22 | *
23 | * http://fernandocejas.com/2015/01/11/rxjava-observable-tranformation-concatmap-vs-flatmap/
24 | *
25 | * Please, visit it in order to get more details about it.
26 | *
27 | */
28 | class ConcatMapAndFlatMapExampleActivity : BaseActivity() {
29 |
30 | override fun onCreate(savedInstanceState: Bundle?) {
31 | super.onCreate(savedInstanceState)
32 | setContentView(R.layout.activity_operators_concatmap_flatmap_example)
33 |
34 | btnFlatMapTest.setOnClickListener { onFlatMapTestButtonClick() }
35 | btnConcatMapTest.setOnClickListener { onConcatMapTestButtonClick() }
36 |
37 | supportActionBar?.title = intent.getStringExtra("TITLE")
38 | }
39 |
40 | private fun onFlatMapTestButtonClick() {
41 |
42 | if (isUnsubscribed()) {
43 | Log.v(TAG, "onFlatMapTestButtonClick")
44 | tvOriginalEmittedItems.text = ""
45 | tvFlatMapResult.text = ""
46 | mSubscription = flatMapTest()
47 | } else {
48 | Toast.makeText(applicationContext, "Test is already running", Toast.LENGTH_SHORT).show()
49 | }
50 | }
51 |
52 | private fun onConcatMapTestButtonClick() {
53 |
54 | if (isUnsubscribed()) {
55 | Log.v(TAG, "onConcatMapTestButtonClick")
56 | tvOriginalEmittedItems.text = ""
57 | tvConcatMapResult.text = ""
58 | mSubscription = concatMapTest()
59 | } else {
60 | Toast.makeText(applicationContext, "Test is already running", Toast.LENGTH_SHORT).show()
61 | }
62 | }
63 |
64 | private fun emitData(): Observable {
65 |
66 | return Observable
67 | .range(1, 50)
68 | .doOnNext { number ->
69 | try {
70 | Log.v(TAG, "emitData() - Emitting number: $number")
71 | Thread.sleep(20)
72 |
73 | } catch (e: InterruptedException) {
74 | Log.v(TAG, "Got an InterruptedException!")
75 | }
76 |
77 | val w = AndroidSchedulers.mainThread().createWorker()
78 | w.schedule { tvOriginalEmittedItems.text = "${tvOriginalEmittedItems.text} $number" }
79 | }
80 | }
81 |
82 | /**
83 | * This is a very simple test just to demonstrate how flatMap operator works.
84 | *
85 | * Basically (and according to the documentation), FlatMap merges the emissions of these Observables, so that they may interleave.
86 | *
87 | * @return
88 | */
89 | private fun flatMapTest(): Subscription {
90 |
91 | return emitData()
92 |
93 | .flatMap { data ->
94 | Observable
95 |
96 | .just(data)
97 |
98 | .compose(showDebugMessages("just"))
99 |
100 | // Just adding a delay here, so that we can better see elements being emitted in the GUI
101 | .delay(200, TimeUnit.MILLISECONDS)
102 |
103 | .compose(showDebugMessages("delay"))
104 | }
105 |
106 | // Just for log purpose
107 | .compose(showDebugMessages("flatMap"))
108 |
109 | .map { data -> "$data" }
110 |
111 | // Just for log purpose
112 | .compose(showDebugMessages("map"))
113 |
114 | // Now, apply on which thread observable will run and also on which one it will be observed.
115 | .compose(applySchedulers())
116 |
117 | // Finally subscribe it.
118 | .subscribe(resultSubscriber(tvFlatMapResult))
119 | }
120 |
121 | /**
122 | * This example is similar to the flatMapTest, but as the name implies, it uses concatMap operator instead.
123 | *
124 | * Note that concatMap() uses concat operator so that it cares about the order of the emitted elements.
125 | *
126 | * @return
127 | */
128 | private fun concatMapTest(): Subscription {
129 |
130 | return emitData()
131 |
132 | .concatMap { data ->
133 | // Here we added some log messages allowing us to analyse the concatMap() operator behavior.
134 | // We can see in the log messages that concatMap emits its items as they are received (after applies its function)
135 | Observable
136 |
137 | .just(data)
138 |
139 | .compose(showDebugMessages("just"))
140 |
141 | // Just adding a delay here, so that we can better see elements being emitted in the GUI
142 | .delay(200, TimeUnit.MILLISECONDS)
143 |
144 | .compose(showDebugMessages("delay"))
145 | }
146 |
147 | // Just for log purpose
148 | .compose(showDebugMessages("concatMap"))
149 |
150 | .map { data -> data.toString() }
151 |
152 | // Just for log purpose
153 | .compose(showDebugMessages("map"))
154 |
155 | // Now, apply on which thread observable will run and also on which one it will be observed.
156 | .compose(applySchedulers())
157 |
158 | // Finally subscribe it.
159 | .subscribe(resultSubscriber(tvConcatMapResult))
160 | }
161 |
162 | companion object {
163 | private val TAG = ConcatMapAndFlatMapExampleActivity::class.java.simpleName
164 | }
165 | }
166 |
--------------------------------------------------------------------------------
/app/src/main/java/com/motondon/rxjavademoapp/view/operators/JoinExampleActivity.kt:
--------------------------------------------------------------------------------
1 | package com.motondon.rxjavademoapp.view.operators
2 |
3 | import android.os.Bundle
4 | import android.support.v7.app.ActionBar
5 | import android.util.Log
6 | import android.view.WindowManager
7 | import android.widget.EditText
8 | import android.widget.TextView
9 | import android.widget.Toast
10 |
11 | import com.motondon.rxjavademoapp.R
12 | import com.motondon.rxjavademoapp.R.id.*
13 | import com.motondon.rxjavademoapp.view.base.BaseActivity
14 |
15 | import java.util.Arrays
16 | import java.util.concurrent.TimeUnit
17 |
18 | import kotlinx.android.synthetic.main.activity_operators_join_example.*
19 | import rx.Observable
20 | import rx.Scheduler
21 | import rx.Subscription
22 | import rx.android.schedulers.AndroidSchedulers
23 | import rx.schedulers.Schedulers
24 |
25 | /**
26 | * This activity allows users to test different values for join operator:
27 | * - left Observable emission delay
28 | * - right Observable emission delay
29 | * - left window duration
30 | * - right window duration
31 | * - left Observable number of items to emit
32 | * - right Observable number of items to emit
33 | *
34 | */
35 | class JoinExampleActivity : BaseActivity() {
36 |
37 | private var leftDelayBetweenEmission: Int = 0
38 | private var rightDelayBetweenEmission: Int = 0
39 | private var leftWindowDuration: Int = 0
40 | private var rightWindowDuration: Int = 0
41 | private var leftNumberOfItemsToEmit: Int = 0
42 | private var rightNumberOfItemsToEmit: Int = 0
43 |
44 | override fun onCreate(savedInstanceState: Bundle?) {
45 | super.onCreate(savedInstanceState)
46 | setContentView(R.layout.activity_operators_join_example)
47 |
48 | btnJoinOperatorTest.setOnClickListener{ onSstartJoinOperatorTestButtonClick() }
49 | btnStopTest.setOnClickListener{ onStopSubscription() }
50 |
51 | supportActionBar?.title = intent.getStringExtra("TITLE")
52 |
53 | // Prevent keyboard to be visible when activity resumes.
54 | window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN)
55 | }
56 |
57 | private fun resetData() {
58 | tvEmittedNumbers.text = ""
59 | tvResult.text = ""
60 | }
61 |
62 | private fun onSstartJoinOperatorTestButtonClick() {
63 | if (isUnsubscribed()) {
64 | Log.v(TAG, "onSstartJoinOperatorTestButtonClick()")
65 | resetData()
66 | readData()
67 | mSubscription = startJoinOperatorTest()
68 | } else {
69 | Toast.makeText(applicationContext, "Test is already running", Toast.LENGTH_SHORT).show()
70 | }
71 | }
72 |
73 | private fun onStopSubscription() {
74 | mSubscription?.unsubscribe()
75 | }
76 |
77 | private fun readData() {
78 | leftDelayBetweenEmission = Integer.parseInt(etLeftObservableDelayBetweenEmission.text.toString())
79 | if (leftDelayBetweenEmission < 0) {
80 | leftDelayBetweenEmission = 0
81 | } else if (leftDelayBetweenEmission > 5000) {
82 | leftDelayBetweenEmission = 5000
83 | }
84 | Log.v(TAG, "readData() - leftDelayBetweenEmission: $leftDelayBetweenEmission")
85 |
86 | rightDelayBetweenEmission = Integer.parseInt(etRightObservableDelayBetweenEmission.text.toString())
87 | if (rightDelayBetweenEmission < 0) {
88 | rightDelayBetweenEmission = 0
89 | } else if (rightDelayBetweenEmission > 5000) {
90 | rightDelayBetweenEmission = 5000
91 | }
92 | Log.v(TAG, "readData() - rightDelayBetweenEmission: $rightDelayBetweenEmission")
93 |
94 | if (etLeftWindowDuration.text.toString().isEmpty()) {
95 | leftWindowDuration = NEVER_CLOSE
96 | } else {
97 | leftWindowDuration = Integer.parseInt(etLeftWindowDuration.text.toString())
98 | if (leftWindowDuration < 0) {
99 | leftWindowDuration = 0
100 | } else if (leftWindowDuration > 5000) {
101 | leftWindowDuration = 5000
102 | }
103 | }
104 | Log.v(TAG, "readData() - leftWindowDuration: $leftWindowDuration")
105 |
106 | if (etRightWindowDuration.text.toString().isEmpty()) {
107 | rightWindowDuration = NEVER_CLOSE
108 | } else {
109 | rightWindowDuration = Integer.parseInt(etRightWindowDuration.text.toString())
110 | if (rightWindowDuration < 0) {
111 | rightWindowDuration = 0
112 | } else if (rightWindowDuration > 5000) {
113 | rightWindowDuration = 5000
114 | }
115 | }
116 | Log.v(TAG, "readData() - rightWindowDuration: $rightWindowDuration")
117 |
118 | leftNumberOfItemsToEmit = Integer.parseInt(etLeftObservableNumberOfItemsToEmit.text.toString())
119 | if (leftNumberOfItemsToEmit < 1) {
120 | leftNumberOfItemsToEmit = 1
121 | } else if (leftNumberOfItemsToEmit > 40) {
122 | leftNumberOfItemsToEmit = 40
123 | }
124 | Log.v(TAG, "readData() - leftNumberOfItemsToEmit: $leftNumberOfItemsToEmit")
125 |
126 | rightNumberOfItemsToEmit = Integer.parseInt(etRightObservableNumberOfItemsToEmit.text.toString())
127 | if (rightNumberOfItemsToEmit < 1) {
128 | rightNumberOfItemsToEmit = 1
129 | } else if (rightNumberOfItemsToEmit > 40) {
130 | rightNumberOfItemsToEmit = 40
131 | }
132 | Log.v(TAG, "readData() - rightNumberOfItemsToEmit: $rightNumberOfItemsToEmit")
133 | }
134 |
135 | private fun emitItems(numberOfItemsToBeEmitted: Int, delayBetweenEmission: Int, caption: String): Observable {
136 | return Observable.interval(delayBetweenEmission.toLong(), TimeUnit.MILLISECONDS)
137 | .map { number -> number.toInt() }
138 | .doOnNext { number ->
139 | Log.v(TAG, "emitItems() - $caption Observable. Emitting number: $number")
140 | val w = AndroidSchedulers.mainThread().createWorker()
141 | w.schedule { tvEmittedNumbers.text = "${tvEmittedNumbers.text} $number" }
142 |
143 | }
144 | .take(numberOfItemsToBeEmitted)
145 | .subscribeOn(Schedulers.newThread())
146 | }
147 |
148 |
149 | private fun startJoinOperatorTest(): Subscription {
150 |
151 | val left = emitItems(leftNumberOfItemsToEmit, leftDelayBetweenEmission, "left")
152 | val right = emitItems(rightNumberOfItemsToEmit, rightDelayBetweenEmission, "right")
153 |
154 | return left
155 | .join>(right,
156 | { _ ->
157 | if (leftWindowDuration === NEVER_CLOSE) {
158 | return@join Observable.never()
159 | } else {
160 | return@join Observable.timer(leftWindowDuration.toLong(), TimeUnit.MILLISECONDS).compose(showDebugMessages("leftDuration")).subscribeOn(Schedulers.computation())
161 | }
162 | },
163 | { _ ->
164 | if (rightWindowDuration === NEVER_CLOSE) {
165 | return@join Observable.never()
166 | } else {
167 | return@join Observable.timer(rightWindowDuration.toLong(), TimeUnit.MILLISECONDS).compose(showDebugMessages("rightDuration")).subscribeOn(Schedulers.computation())
168 | }
169 | },
170 | { l, r ->
171 | Log.v(TAG, "join() - Joining left number: $l with right number: $r")
172 | Arrays.asList(l.toInt(), r.toInt())
173 | }
174 | )
175 | .compose(applySchedulers())
176 | .subscribe(resultSubscriber(tvResult))
177 | }
178 |
179 | companion object {
180 |
181 | private val TAG = JoinExampleActivity::class.java.simpleName
182 | private const val NEVER_CLOSE = -1
183 | }
184 | }
185 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_keyboard_arrow_down_black_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JoaoMotondon/RxJavaDemoApp/2cf453c3778c480226a8391cde00127b091c391a/app/src/main/res/drawable-hdpi/ic_keyboard_arrow_down_black_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_keyboard_arrow_down_black_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JoaoMotondon/RxJavaDemoApp/2cf453c3778c480226a8391cde00127b091c391a/app/src/main/res/drawable-mdpi/ic_keyboard_arrow_down_black_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_keyboard_arrow_down_black_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JoaoMotondon/RxJavaDemoApp/2cf453c3778c480226a8391cde00127b091c391a/app/src/main/res/drawable-xhdpi/ic_keyboard_arrow_down_black_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_keyboard_arrow_down_black_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JoaoMotondon/RxJavaDemoApp/2cf453c3778c480226a8391cde00127b091c391a/app/src/main/res/drawable-xxhdpi/ic_keyboard_arrow_down_black_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/ic_keyboard_arrow_down_black_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JoaoMotondon/RxJavaDemoApp/2cf453c3778c480226a8391cde00127b091c391a/app/src/main/res/drawable-xxxhdpi/ic_keyboard_arrow_down_black_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/background_spinner.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
-
6 |
7 |
8 |
9 |
10 | -
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/battery_charging_ac.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JoaoMotondon/RxJavaDemoApp/2cf453c3778c480226a8391cde00127b091c391a/app/src/main/res/drawable/battery_charging_ac.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/battery_charging_usb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JoaoMotondon/RxJavaDemoApp/2cf453c3778c480226a8391cde00127b091c391a/app/src/main/res/drawable/battery_charging_usb.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/battery_status_almost_full.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JoaoMotondon/RxJavaDemoApp/2cf453c3778c480226a8391cde00127b091c391a/app/src/main/res/drawable/battery_status_almost_full.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/battery_status_empty.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JoaoMotondon/RxJavaDemoApp/2cf453c3778c480226a8391cde00127b091c391a/app/src/main/res/drawable/battery_status_empty.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/battery_status_full.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JoaoMotondon/RxJavaDemoApp/2cf453c3778c480226a8391cde00127b091c391a/app/src/main/res/drawable/battery_status_full.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/battery_status_half.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JoaoMotondon/RxJavaDemoApp/2cf453c3778c480226a8391cde00127b091c391a/app/src/main/res/drawable/battery_status_half.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/battery_status_low.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JoaoMotondon/RxJavaDemoApp/2cf453c3778c480226a8391cde00127b091c391a/app/src/main/res/drawable/battery_status_low.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/battery_status_very_low.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JoaoMotondon/RxJavaDemoApp/2cf453c3778c480226a8391cde00127b091c391a/app/src/main/res/drawable/battery_status_very_low.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/brush.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JoaoMotondon/RxJavaDemoApp/2cf453c3778c480226a8391cde00127b091c391a/app/src/main/res/drawable/brush.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/eraser.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JoaoMotondon/RxJavaDemoApp/2cf453c3778c480226a8391cde00127b091c391a/app/src/main/res/drawable/eraser.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_movie_placeholder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JoaoMotondon/RxJavaDemoApp/2cf453c3778c480226a8391cde00127b091c391a/app/src/main/res/drawable/ic_movie_placeholder.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_no_cover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JoaoMotondon/RxJavaDemoApp/2cf453c3778c480226a8391cde00127b091c391a/app/src/main/res/drawable/ic_no_cover.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_toggle_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JoaoMotondon/RxJavaDemoApp/2cf453c3778c480226a8391cde00127b091c391a/app/src/main/res/drawable/ic_toggle_off.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_toggle_on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JoaoMotondon/RxJavaDemoApp/2cf453c3778c480226a8391cde00127b091c391a/app/src/main/res/drawable/ic_toggle_on.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/list_item_background.xml:
--------------------------------------------------------------------------------
1 |
3 | -
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/new_file.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JoaoMotondon/RxJavaDemoApp/2cf453c3778c480226a8391cde00127b091c391a/app/src/main/res/drawable/new_file.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/toggle_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/toggle_state_off.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
10 |
11 |
12 |
13 | -
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/toggle_state_on.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
10 |
11 |
12 |
13 | -
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_backpressure_basic_example.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
16 |
17 |
21 |
22 |
29 |
30 |
35 |
36 |
42 |
43 |
48 |
49 |
50 |
54 |
55 |
61 |
62 |
63 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_backpressure_manual_request_example.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
16 |
17 |
21 |
22 |
29 |
30 |
35 |
36 |
42 |
43 |
48 |
49 |
55 |
56 |
61 |
62 |
63 |
68 |
69 |
75 |
76 |
83 |
84 |
91 |
92 |
93 |
94 |
99 |
100 |
106 |
107 |
114 |
115 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_backpressure_reactive_pull_example.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
16 |
17 |
21 |
22 |
29 |
30 |
35 |
36 |
42 |
43 |
48 |
49 |
50 |
54 |
55 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_backpressure_specific_operators_example.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
16 |
17 |
21 |
22 |
29 |
30 |
35 |
36 |
42 |
43 |
48 |
49 |
56 |
57 |
62 |
63 |
67 |
68 |
74 |
75 |
81 |
82 |
88 |
89 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_example_by_category.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_general_broadcast_system_status_example.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
15 |
16 |
17 |
27 |
28 |
32 |
33 |
40 |
41 |
48 |
49 |
55 |
56 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
81 |
82 |
86 |
87 |
94 |
95 |
102 |
103 |
107 |
108 |
114 |
115 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_general_drawing_example.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
15 |
20 |
21 |
27 |
28 |
34 |
35 |
41 |
42 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_general_server_polling_after_data_processing_example.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
17 |
18 |
26 |
27 |
33 |
34 |
41 |
42 |
48 |
49 |
55 |
56 |
61 |
62 |
68 |
69 |
75 |
76 |
82 |
83 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_general_server_polling_example.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
18 |
19 |
26 |
27 |
28 |
29 |
34 |
35 |
43 |
44 |
45 |
46 |
52 |
53 |
58 |
59 |
65 |
66 |
72 |
73 |
79 |
80 |
86 |
87 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_general_typing_indicator.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
16 |
23 |
24 |
31 |
32 |
38 |
39 |
46 |
47 |
54 |
55 |
56 |
57 |
61 |
62 |
72 |
73 |
77 |
78 |
85 |
86 |
92 |
93 |
94 |
100 |
101 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
124 |
125 |
129 |
130 |
138 |
139 |
145 |
146 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_hot_observable_cache_example.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
16 |
17 |
23 |
24 |
29 |
30 |
36 |
37 |
42 |
43 |
49 |
50 |
55 |
56 |
63 |
64 |
70 |
71 |
78 |
79 |
86 |
87 |
88 |
89 |
95 |
96 |
103 |
104 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_hot_observable_connect_example.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
16 |
17 |
23 |
24 |
29 |
30 |
36 |
37 |
42 |
43 |
49 |
50 |
55 |
56 |
63 |
64 |
70 |
71 |
78 |
79 |
86 |
87 |
88 |
89 |
95 |
96 |
103 |
104 |
111 |
112 |
113 |
114 |
120 |
121 |
122 |
123 |
124 |
125 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_hot_observable_refcount_example.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
16 |
17 |
23 |
24 |
29 |
30 |
36 |
37 |
42 |
43 |
49 |
50 |
55 |
56 |
63 |
64 |
70 |
71 |
78 |
79 |
86 |
87 |
88 |
89 |
95 |
96 |
103 |
104 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_hot_observable_replay_example.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
16 |
17 |
23 |
24 |
29 |
30 |
36 |
37 |
42 |
43 |
49 |
50 |
55 |
56 |
63 |
64 |
70 |
71 |
77 |
78 |
85 |
86 |
92 |
93 |
100 |
101 |
108 |
109 |
110 |
111 |
117 |
118 |
125 |
126 |
133 |
134 |
135 |
136 |
142 |
143 |
144 |
145 |
146 |
147 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
16 |
17 |
22 |
23 |
24 |
25 |
30 |
31 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_operators_aggregate_operators_example.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
16 |
17 |
21 |
22 |
29 |
30 |
35 |
36 |
42 |
43 |
48 |
49 |
55 |
56 |
62 |
63 |
69 |
70 |
76 |
77 |
83 |
84 |
90 |
91 |
97 |
98 |
99 |
100 |
101 |
102 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_operators_combining_observables_example.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
17 |
18 |
25 |
26 |
31 |
32 |
38 |
39 |
44 |
45 |
48 |
49 |
53 |
54 |
60 |
61 |
67 |
68 |
74 |
75 |
81 |
82 |
83 |
89 |
90 |
96 |
97 |
103 |
104 |
110 |
111 |
117 |
118 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_operators_concatmap_flatmap_example.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
13 |
14 |
19 |
20 |
21 |
26 |
27 |
33 |
34 |
40 |
41 |
46 |
47 |
53 |
54 |
59 |
60 |
66 |
67 |
73 |
74 |
80 |
81 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_operators_conditional_operators_example.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
17 |
18 |
25 |
26 |
31 |
32 |
38 |
39 |
44 |
45 |
46 |
49 |
50 |
54 |
55 |
61 |
62 |
68 |
69 |
75 |
76 |
82 |
83 |
89 |
90 |
96 |
97 |
103 |
104 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_operators_error_handling_example.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
17 |
18 |
25 |
26 |
31 |
32 |
38 |
39 |
44 |
45 |
48 |
49 |
53 |
54 |
61 |
62 |
68 |
69 |
75 |
76 |
82 |
83 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_operators_filtering_example.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
18 |
19 |
26 |
27 |
33 |
34 |
41 |
42 |
47 |
48 |
54 |
55 |
60 |
61 |
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_operators_more_filtering_example.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
17 |
18 |
25 |
26 |
31 |
32 |
38 |
39 |
44 |
45 |
48 |
49 |
53 |
54 |
61 |
62 |
68 |
69 |
75 |
76 |
82 |
83 |
89 |
90 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_operators_retry_and_retrywhen_example.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
15 |
16 |
20 |
21 |
26 |
27 |
28 |
29 |
33 |
34 |
41 |
42 |
47 |
48 |
54 |
55 |
60 |
61 |
62 |
63 |
68 |
69 |
74 |
75 |
81 |
82 |
88 |
89 |
95 |
96 |
102 |
103 |
109 |
110 |
116 |
117 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_operators_timeout_example.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
16 |
17 |
21 |
22 |
29 |
30 |
35 |
36 |
42 |
43 |
48 |
49 |
56 |
57 |
63 |
64 |
70 |
71 |
77 |
78 |
84 |
85 |
91 |
92 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_operators_transforming_operators_example.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
18 |
19 |
26 |
27 |
33 |
34 |
41 |
42 |
47 |
48 |
54 |
55 |
60 |
61 |
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_parallelization_example.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
18 |
19 |
25 |
26 |
32 |
33 |
39 |
40 |
44 |
45 |
51 |
52 |
57 |
58 |
59 |
60 |
64 |
65 |
73 |
74 |
75 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_cardview_options.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
19 |
20 |
24 |
25 |
32 |
33 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_category_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
19 |
20 |
24 |
25 |
32 |
33 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_list_single.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_reactive_ui_drawing_example.xml:
--------------------------------------------------------------------------------
1 |
36 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JoaoMotondon/RxJavaDemoApp/2cf453c3778c480226a8391cde00127b091c391a/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JoaoMotondon/RxJavaDemoApp/2cf453c3778c480226a8391cde00127b091c391a/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JoaoMotondon/RxJavaDemoApp/2cf453c3778c480226a8391cde00127b091c391a/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JoaoMotondon/RxJavaDemoApp/2cf453c3778c480226a8391cde00127b091c391a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JoaoMotondon/RxJavaDemoApp/2cf453c3778c480226a8391cde00127b091c391a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #2196F3
4 | #3F51B5
5 | #303F9F
6 | #FF4081
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | RxJavaDemoApp
3 | RxJava (100+ Examples Pack)
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/test/java/com/motondon/rxjavademoapp/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.motondon.rxjavademoapp
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * To work on unit tests, switch the Test Artifact in the Build Variants view.
9 | */
10 | class ExampleUnitTest {
11 | @Test
12 | @Throws(Exception::class)
13 | fun addition_isCorrect() {
14 | assertEquals(4, (2 + 2).toLong())
15 | }
16 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | ext.kotlin_version = '1.2.10'
5 | repositories {
6 | jcenter()
7 | google()
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:3.1.0'
11 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | jcenter()
18 | google()
19 | }
20 | }
21 |
22 | task clean(type: Delete) {
23 | delete rootProject.buildDir
24 | }
25 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 | org.gradle.jvmargs=-Xmx1536m
15 |
16 | # When configured, Gradle will run in incubating parallel mode.
17 | # This option should only be used with decoupled projects. More details, visit
18 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
19 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JoaoMotondon/RxJavaDemoApp/2cf453c3778c480226a8391cde00127b091c391a/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Apr 03 10:09:28 BRT 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------