diff --git a/app/build.gradle b/app/build.gradle index 0627b4d..7224758 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -26,8 +26,10 @@ android { dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'com.jakewharton.rxrelay2:rxrelay:2.1.1' - + implementation 'com.uber.autodispose:autodispose:1.4.0' + implementation 'com.uber.autodispose:autodispose-android-archcomponents:1.4.0' implementation 'io.reactivex.rxjava2:rxjava:2.2.21' + implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' implementation 'androidx.appcompat:appcompat:1.3.1' implementation 'androidx.constraintlayout:constraintlayout:2.0.4' testImplementation 'junit:junit:4.13.2' diff --git a/app/src/main/java/com/tonytang/hello/again/rxjava/MainActivity.java b/app/src/main/java/com/tonytang/hello/again/rxjava/MainActivity.java index 7df9177..094931d 100644 --- a/app/src/main/java/com/tonytang/hello/again/rxjava/MainActivity.java +++ b/app/src/main/java/com/tonytang/hello/again/rxjava/MainActivity.java @@ -1,13 +1,40 @@ package com.tonytang.hello.again.rxjava; -import androidx.appcompat.app.AppCompatActivity; +import static com.uber.autodispose.AutoDispose.autoDisposable; +import static com.uber.autodispose.android.lifecycle.AndroidLifecycleScopeProvider.from; + import android.os.Bundle; +import android.widget.TextView; +import androidx.appcompat.app.AppCompatActivity; +import io.reactivex.android.schedulers.AndroidSchedulers; public class MainActivity extends AppCompatActivity { + private TextView tv_throttle_first; + private TextView tv_throttle_last; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); + tv_throttle_first = findViewById(R.id.tv_throttle_first); + tv_throttle_last = findViewById(R.id.tv_throttle_last); + ThreadInfoStreaming.eventStreaming() + .observeOn(AndroidSchedulers.mainThread()) + .as(autoDisposable(from(this))) + .subscribe(this::renderUI); } + + private void renderUI(ThreadInfo threadInfo) { + switch (threadInfo.source) { + case THROTTLE_FIRST: + tv_throttle_first.setText(threadInfo.toString()); + break; + case THROTTLE_LAST: + tv_throttle_last.setText(threadInfo.toString()); + break; + } + } + + } diff --git a/app/src/main/java/com/tonytang/hello/again/rxjava/Source.java b/app/src/main/java/com/tonytang/hello/again/rxjava/Source.java new file mode 100644 index 0000000..68915a9 --- /dev/null +++ b/app/src/main/java/com/tonytang/hello/again/rxjava/Source.java @@ -0,0 +1,6 @@ +package com.tonytang.hello.again.rxjava; + +public enum Source { + THROTTLE_FIRST, + THROTTLE_LAST +} diff --git a/app/src/main/java/com/tonytang/hello/again/rxjava/ThreadInfo.java b/app/src/main/java/com/tonytang/hello/again/rxjava/ThreadInfo.java new file mode 100644 index 0000000..587de7f --- /dev/null +++ b/app/src/main/java/com/tonytang/hello/again/rxjava/ThreadInfo.java @@ -0,0 +1,23 @@ +package com.tonytang.hello.again.rxjava; + +import androidx.annotation.NonNull; +import java.util.Locale; + +public class ThreadInfo { + + public final long iteration; + public final Source source; + public final String threadName; + + public ThreadInfo(long iteration, Source source, String threadName) { + this.iteration = iteration; + this.source = source; + this.threadName = threadName; + } + + @NonNull + @Override + public String toString() { + return String.format(Locale.US, "%s:%s:%s", iteration, source, threadName); + } +} diff --git a/app/src/main/java/com/tonytang/hello/again/rxjava/ThreadInfoStreaming.java b/app/src/main/java/com/tonytang/hello/again/rxjava/ThreadInfoStreaming.java new file mode 100644 index 0000000..83c2449 --- /dev/null +++ b/app/src/main/java/com/tonytang/hello/again/rxjava/ThreadInfoStreaming.java @@ -0,0 +1,38 @@ +package com.tonytang.hello.again.rxjava; + +import io.reactivex.Observable; +import io.reactivex.android.schedulers.AndroidSchedulers; +import java.util.concurrent.TimeUnit; + +public class ThreadInfoStreaming { + + private ThreadInfoStreaming() { + } + + static Observable eventStreaming() { + return Observable.merge(throttleFirst(), throttleLast()); + } + + private static Observable throttleFirst() { + return rawStream() + .throttleFirst(1, TimeUnit.SECONDS) + .map(iteration -> new ThreadInfo(iteration, Source.THROTTLE_FIRST, + currentThreadName())); + } + + private static Observable throttleLast() { + return rawStream() + .throttleLast(1, TimeUnit.SECONDS) + .map(iteration -> new ThreadInfo(iteration, Source.THROTTLE_LAST, + currentThreadName())); + } + + private static String currentThreadName() { + return Thread.currentThread().getName(); + } + + private static Observable rawStream() { + return Observable.interval(500, TimeUnit.MILLISECONDS) + .observeOn(AndroidSchedulers.mainThread()); + } +} diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 8a0f7e4..547872e 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,21 +1,23 @@ - + + + android:layout_height="wrap_content" + /> - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/test/java/com/tonytang/hello/again/rxjava/ThrottleFirstTest.java b/app/src/test/java/com/tonytang/hello/again/rxjava/ThrottleFirstTest.java new file mode 100644 index 0000000..e7e6016 --- /dev/null +++ b/app/src/test/java/com/tonytang/hello/again/rxjava/ThrottleFirstTest.java @@ -0,0 +1,21 @@ +package com.tonytang.hello.again.rxjava; + +import com.google.common.truth.Truth; +import io.reactivex.Observable; +import io.reactivex.observers.TestObserver; +import io.reactivex.schedulers.Schedulers; +import java.util.concurrent.TimeUnit; +import org.junit.Test; + +public class ThrottleFirstTest { + + @Test + public void without_cache_would_execute_footprint_three_times() { + + TestObserver test = Observable.just(1).throttleLatest(1, TimeUnit.SECONDS, Schedulers.computation()).test(); + Thread thread = test.lastThread(); + Truth.assertThat(thread.getName()).isEqualTo("Test worker"); + + } + +} \ No newline at end of file diff --git a/doc/throttle_first_vs_throttle_last_thread.png b/doc/throttle_first_vs_throttle_last_thread.png new file mode 100644 index 0000000..e5db51a Binary files /dev/null and b/doc/throttle_first_vs_throttle_last_thread.png differ