From c598f82fc2c104cb08e1dfa861c933969de63d57 Mon Sep 17 00:00:00 2001 From: Mitch Tabian Date: Tue, 26 Mar 2019 09:34:02 -0700 Subject: [PATCH 1/5] concat map --- .../rxjavaflatmapexample/MainActivity.java | 48 +++++++++++-------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/com/codingwithmitch/rxjavaflatmapexample/MainActivity.java b/app/src/main/java/com/codingwithmitch/rxjavaflatmapexample/MainActivity.java index 8120e60..0b814ba 100644 --- a/app/src/main/java/com/codingwithmitch/rxjavaflatmapexample/MainActivity.java +++ b/app/src/main/java/com/codingwithmitch/rxjavaflatmapexample/MainActivity.java @@ -3,6 +3,7 @@ import androidx.appcompat.app.AppCompatActivity; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; + import io.reactivex.Observable; import io.reactivex.ObservableSource; import io.reactivex.Observer; @@ -13,6 +14,7 @@ import io.reactivex.functions.Predicate; import io.reactivex.schedulers.Schedulers; + import android.os.Bundle; import android.util.Log; @@ -23,6 +25,7 @@ import java.util.List; import java.util.Random; + public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; @@ -43,12 +46,13 @@ protected void onCreate(Bundle savedInstanceState) { initRecyclerView(); + getPostsObservable() .subscribeOn(Schedulers.io()) - .flatMap(new Function>() { + .concatMap(new Function>() { @Override public ObservableSource apply(Post post) throws Exception { - return getCommentsObservable(post); + return getCommentsObservable(post); // return an updated Observable with comments } }) .observeOn(AndroidSchedulers.mainThread()) @@ -60,6 +64,7 @@ public void onSubscribe(Disposable d) { @Override public void onNext(Post post) { + // update the post in the list updatePost(post); } @@ -70,21 +75,7 @@ public void onError(Throwable e) { @Override public void onComplete() { - } - }); - } - private Observable getPostsObservable(){ - return ServiceGenerator.getRequestApi() - .getPosts() - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .flatMap(new Function, ObservableSource>() { - @Override - public ObservableSource apply(final List posts) throws Exception { - adapter.setPosts(posts); - return Observable.fromIterable(posts) - .subscribeOn(Schedulers.io()); } }); } @@ -93,6 +84,7 @@ private void updatePost(Post post){ adapter.updatePost(post); } + private Observable getCommentsObservable(final Post post){ return ServiceGenerator.getRequestApi() .getComments(post.getId()) @@ -100,24 +92,42 @@ private Observable getCommentsObservable(final Post post){ @Override public Post apply(List comments) throws Exception { - int delay = ((new Random()).nextInt(5) + 1) * 1000; // sleep thread for x ms + int delay = ((new Random()).nextInt(5) + 1) * 1000; Thread.sleep(delay); - Log.d(TAG, "apply: sleeping thread " + Thread.currentThread().getName() + " for " + String.valueOf(delay)+ "ms"); + Log.d(TAG, "apply: sleeping thread: " + Thread.currentThread().getName() + " for " + + String.valueOf(delay) + " ms"); post.setComments(comments); + return post; } }) .subscribeOn(Schedulers.io()); + } + + private Observable getPostsObservable(){ + return ServiceGenerator.getRequestApi() + .getPosts() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .flatMap(new Function, ObservableSource>() { + @Override + public ObservableSource apply(List posts) throws Exception { + adapter.setPosts(posts); + return Observable.fromIterable(posts) + .subscribeOn(Schedulers.io()); + } + }); } + private void initRecyclerView(){ adapter = new RecyclerAdapter(); recyclerView.setLayoutManager(new LinearLayoutManager(this)); recyclerView.setAdapter(adapter); } - + @Override protected void onDestroy() { super.onDestroy(); From 94e9913c3085adc728e54c83c5e178d7e71edd1a Mon Sep 17 00:00:00 2001 From: Mitch Tabian Date: Tue, 26 Mar 2019 12:23:04 -0700 Subject: [PATCH 2/5] switch map --- app/src/main/AndroidManifest.xml | 1 + .../rxjavaflatmapexample/MainActivity.java | 118 +++++++++++++++--- .../rxjavaflatmapexample/RecyclerAdapter.java | 42 +++++-- .../ViewPostActivity.java | 51 ++++++++ .../rxjavaflatmapexample/models/Post.java | 37 +++++- .../requests/RequestApi.java | 7 +- .../main/res/layout/activity_view_post.xml | 22 ++++ 7 files changed, 249 insertions(+), 29 deletions(-) create mode 100644 app/src/main/java/com/codingwithmitch/rxjavaflatmapexample/ViewPostActivity.java create mode 100644 app/src/main/res/layout/activity_view_post.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1e10d54..9e379c4 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -18,6 +18,7 @@ + \ No newline at end of file diff --git a/app/src/main/java/com/codingwithmitch/rxjavaflatmapexample/MainActivity.java b/app/src/main/java/com/codingwithmitch/rxjavaflatmapexample/MainActivity.java index 0b814ba..0c387fe 100644 --- a/app/src/main/java/com/codingwithmitch/rxjavaflatmapexample/MainActivity.java +++ b/app/src/main/java/com/codingwithmitch/rxjavaflatmapexample/MainActivity.java @@ -5,16 +5,22 @@ import androidx.recyclerview.widget.RecyclerView; import io.reactivex.Observable; +import io.reactivex.ObservableEmitter; +import io.reactivex.ObservableOnSubscribe; import io.reactivex.ObservableSource; import io.reactivex.Observer; +import io.reactivex.Single; +import io.reactivex.SingleSource; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.CompositeDisposable; import io.reactivex.disposables.Disposable; import io.reactivex.functions.Function; import io.reactivex.functions.Predicate; import io.reactivex.schedulers.Schedulers; +import io.reactivex.subjects.PublishSubject; +import android.content.Intent; import android.os.Bundle; import android.util.Log; @@ -26,7 +32,7 @@ import java.util.Random; -public class MainActivity extends AppCompatActivity { +public class MainActivity extends AppCompatActivity implements RecyclerAdapter.OnPostClickListener { private static final String TAG = "MainActivity"; @@ -36,6 +42,7 @@ public class MainActivity extends AppCompatActivity { // vars private CompositeDisposable disposables = new CompositeDisposable(); private RecyclerAdapter adapter; + private PublishSubject publishSubject = PublishSubject.create(); @Override @@ -49,16 +56,11 @@ protected void onCreate(Bundle savedInstanceState) { getPostsObservable() .subscribeOn(Schedulers.io()) - .concatMap(new Function>() { - @Override - public ObservableSource apply(Post post) throws Exception { - return getCommentsObservable(post); // return an updated Observable with comments - } - }) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer() { @Override public void onSubscribe(Disposable d) { + Log.d(TAG, "onSubscribe: subscribing."); disposables.add(d); } @@ -76,10 +78,59 @@ public void onError(Throwable e) { @Override public void onComplete() { + } + }); + + publishSubject + .switchMap(new Function>() { + @Override + public ObservableSource apply(Post post) throws Exception { + return ServiceGenerator.getRequestApi() + .getPost(post.getId()) + .subscribeOn(Schedulers.io()) + .map(new Function() { // function that does nothing. Just sleeps the thread + @Override + public Post apply(Post post) throws Exception { + Log.d(TAG, "apply: retrieving individual post data: post id: " + post.getId()); + try { + Thread.sleep(3000); // thread blocking call + } catch (InterruptedException ex) { + // check if the interrupt is due to cancellation + // if so, no need to signal the InterruptedException + } + Log.d(TAG, "apply: sleeping thread: " + Thread.currentThread().getName() + " for 3000 ms"); + + return post; + } + }) + .observeOn(AndroidSchedulers.mainThread()); + } + }) + .subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { + disposables.add(d); + } + + @Override + public void onNext(Post post) { + Log.d(TAG, "onNext: got the post! " + post.getId()); + navViewPostActivity(post); + } + + @Override + public void onError(Throwable e) { + + } + + @Override + public void onComplete() { + } }); } + private void updatePost(Post post){ adapter.updatePost(post); } @@ -93,9 +144,14 @@ private Observable getCommentsObservable(final Post post){ public Post apply(List comments) throws Exception { int delay = ((new Random()).nextInt(5) + 1) * 1000; - Thread.sleep(delay); - Log.d(TAG, "apply: sleeping thread: " + Thread.currentThread().getName() + " for " - + String.valueOf(delay) + " ms"); + try { + Thread.sleep(delay); // thread blocking call + } catch (InterruptedException ex) { + // check if the interrupt is due to cancellation + // if so, no need to signal the InterruptedException + } +// Log.d(TAG, "apply: sleeping thread: " + Thread.currentThread().getName() + " for " +// + String.valueOf(delay) + " ms"); post.setComments(comments); @@ -123,14 +179,48 @@ public ObservableSource apply(List posts) throws Exception { private void initRecyclerView(){ - adapter = new RecyclerAdapter(); + adapter = new RecyclerAdapter(this); recyclerView.setLayoutManager(new LinearLayoutManager(this)); recyclerView.setAdapter(adapter); } + private void navViewPostActivity(Post post){ + Intent intent = new Intent(this, ViewPostActivity.class); + intent.putExtra("post", post); + startActivity(intent); + } + + @Override + protected void onPause() { + Log.d(TAG, "onPause: called."); + disposables.dispose(); + super.onPause(); + } + @Override - protected void onDestroy() { - super.onDestroy(); - disposables.clear(); + public void onPostClick(final int position) { + + Log.d(TAG, "onPostClick: clicked."); + + publishSubject.onNext(adapter.getPosts().get(position)); } } + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/java/com/codingwithmitch/rxjavaflatmapexample/RecyclerAdapter.java b/app/src/main/java/com/codingwithmitch/rxjavaflatmapexample/RecyclerAdapter.java index 839aa6f..1be6f7b 100644 --- a/app/src/main/java/com/codingwithmitch/rxjavaflatmapexample/RecyclerAdapter.java +++ b/app/src/main/java/com/codingwithmitch/rxjavaflatmapexample/RecyclerAdapter.java @@ -19,12 +19,17 @@ public class RecyclerAdapter extends RecyclerView.Adapter posts = new ArrayList<>(); + private OnPostClickListener onPostClickListener; + + public RecyclerAdapter(OnPostClickListener onPostClickListener) { + this.onPostClickListener = onPostClickListener; + } @NonNull @Override public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_post_list_item, null, false); - return new MyViewHolder(view); + return new MyViewHolder(view, onPostClickListener); } @Override @@ -52,29 +57,34 @@ public List getPosts(){ return posts; } - public class MyViewHolder extends RecyclerView.ViewHolder{ + public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { + OnPostClickListener onPostClickListener; TextView title, numComments; ProgressBar progressBar; - public MyViewHolder(@NonNull View itemView) { + public MyViewHolder(@NonNull View itemView, OnPostClickListener onPostClickListener) { super(itemView); title = itemView.findViewById(R.id.title); numComments = itemView.findViewById(R.id.num_comments); progressBar = itemView.findViewById(R.id.progress_bar); + + this.onPostClickListener = onPostClickListener; + + itemView.setOnClickListener(this); } public void bind(Post post){ title.setText(post.getTitle()); - if(post.getComments() == null){ - showProgressBar(true); - numComments.setText(""); - } - else{ - showProgressBar(false); - numComments.setText(String.valueOf(post.getComments().size())); - } +// if(post.getComments() == null){ +// showProgressBar(true); +// numComments.setText(""); +// } +// else{ +// showProgressBar(false); +// numComments.setText(String.valueOf(post.getComments().size())); +// } } private void showProgressBar(boolean showProgressBar){ @@ -85,9 +95,17 @@ private void showProgressBar(boolean showProgressBar){ progressBar.setVisibility(View.GONE); } } + + @Override + public void onClick(View v) { + onPostClickListener.onPostClick(getAdapterPosition()); + } } -} + public interface OnPostClickListener{ + void onPostClick(int position); + } +} diff --git a/app/src/main/java/com/codingwithmitch/rxjavaflatmapexample/ViewPostActivity.java b/app/src/main/java/com/codingwithmitch/rxjavaflatmapexample/ViewPostActivity.java new file mode 100644 index 0000000..d3382da --- /dev/null +++ b/app/src/main/java/com/codingwithmitch/rxjavaflatmapexample/ViewPostActivity.java @@ -0,0 +1,51 @@ +package com.codingwithmitch.rxjavaflatmapexample; + +import android.os.Bundle; +import android.widget.TextView; + + +import com.codingwithmitch.rxjavaflatmapexample.models.Post; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +public class ViewPostActivity extends AppCompatActivity { + + private static final String TAG = "ViewPostActivity"; + + private TextView text; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_view_post); + text = findViewById(R.id.text); + + getIncomingIntent(); + } + + private void getIncomingIntent(){ + if(getIntent().hasExtra("post")){ + Post post = getIntent().getParcelableExtra("post"); + text.setText(post.getTitle()); + } + } +} + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/java/com/codingwithmitch/rxjavaflatmapexample/models/Post.java b/app/src/main/java/com/codingwithmitch/rxjavaflatmapexample/models/Post.java index dc0348b..e880d24 100644 --- a/app/src/main/java/com/codingwithmitch/rxjavaflatmapexample/models/Post.java +++ b/app/src/main/java/com/codingwithmitch/rxjavaflatmapexample/models/Post.java @@ -1,11 +1,14 @@ package com.codingwithmitch.rxjavaflatmapexample.models; +import android.os.Parcel; +import android.os.Parcelable; + import com.google.gson.annotations.Expose; import com.google.gson.annotations.SerializedName; import java.util.List; -public class Post { +public class Post implements Parcelable { @SerializedName("userId") @Expose() @@ -33,6 +36,25 @@ public Post(int userId, int id, String title, String body, List comment this.comments = comments; } + protected Post(Parcel in) { + userId = in.readInt(); + id = in.readInt(); + title = in.readString(); + body = in.readString(); + } + + public static final Creator CREATOR = new Creator() { + @Override + public Post createFromParcel(Parcel in) { + return new Post(in); + } + + @Override + public Post[] newArray(int size) { + return new Post[size]; + } + }; + public int getUserId() { return userId; } @@ -82,4 +104,17 @@ public String toString() { ", body='" + body + '\'' + '}'; } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(userId); + dest.writeInt(id); + dest.writeString(title); + dest.writeString(body); + } } diff --git a/app/src/main/java/com/codingwithmitch/rxjavaflatmapexample/requests/RequestApi.java b/app/src/main/java/com/codingwithmitch/rxjavaflatmapexample/requests/RequestApi.java index de08754..ff2a9d7 100644 --- a/app/src/main/java/com/codingwithmitch/rxjavaflatmapexample/requests/RequestApi.java +++ b/app/src/main/java/com/codingwithmitch/rxjavaflatmapexample/requests/RequestApi.java @@ -5,9 +5,7 @@ import java.util.List; -import io.reactivex.Flowable; import io.reactivex.Observable; -import okhttp3.ResponseBody; import retrofit2.http.GET; import retrofit2.http.Path; @@ -20,4 +18,9 @@ public interface RequestApi { Observable> getComments( @Path("id") int id ); + + @GET("posts/{id}") + Observable getPost( + @Path("id") int id + ); } diff --git a/app/src/main/res/layout/activity_view_post.xml b/app/src/main/res/layout/activity_view_post.xml new file mode 100644 index 0000000..a5a4c70 --- /dev/null +++ b/app/src/main/res/layout/activity_view_post.xml @@ -0,0 +1,22 @@ + + + + + + + + + \ No newline at end of file From d86c7b1618782fd8600b1870f64c9488cbe8370b Mon Sep 17 00:00:00 2001 From: Mitch Tabian Date: Tue, 26 Mar 2019 12:27:39 -0700 Subject: [PATCH 3/5] switch map --- .../rxjavaflatmapexample/MainActivity.java | 88 +++++-------------- .../rxjavaflatmapexample/RecyclerAdapter.java | 22 +---- .../requests/RequestApi.java | 5 -- .../main/res/layout/layout_post_list_item.xml | 50 ++--------- 4 files changed, 32 insertions(+), 133 deletions(-) diff --git a/app/src/main/java/com/codingwithmitch/rxjavaflatmapexample/MainActivity.java b/app/src/main/java/com/codingwithmitch/rxjavaflatmapexample/MainActivity.java index 0c387fe..5a55b3c 100644 --- a/app/src/main/java/com/codingwithmitch/rxjavaflatmapexample/MainActivity.java +++ b/app/src/main/java/com/codingwithmitch/rxjavaflatmapexample/MainActivity.java @@ -52,34 +52,7 @@ protected void onCreate(Bundle savedInstanceState) { recyclerView = findViewById(R.id.recycler_view); initRecyclerView(); - - - getPostsObservable() - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(new Observer() { - @Override - public void onSubscribe(Disposable d) { - Log.d(TAG, "onSubscribe: subscribing."); - disposables.add(d); - } - - @Override - public void onNext(Post post) { - // update the post in the list - updatePost(post); - } - - @Override - public void onError(Throwable e) { - Log.e(TAG, "onError: ", e); - } - - @Override - public void onComplete() { - - } - }); + retrievePosts(); publishSubject .switchMap(new Function>() { @@ -136,45 +109,32 @@ private void updatePost(Post post){ } - private Observable getCommentsObservable(final Post post){ - return ServiceGenerator.getRequestApi() - .getComments(post.getId()) - .map(new Function, Post>() { - @Override - public Post apply(List comments) throws Exception { - - int delay = ((new Random()).nextInt(5) + 1) * 1000; - try { - Thread.sleep(delay); // thread blocking call - } catch (InterruptedException ex) { - // check if the interrupt is due to cancellation - // if so, no need to signal the InterruptedException - } -// Log.d(TAG, "apply: sleeping thread: " + Thread.currentThread().getName() + " for " -// + String.valueOf(delay) + " ms"); - - post.setComments(comments); - - return post; - } - }) - .subscribeOn(Schedulers.io()); - } - - - private Observable getPostsObservable(){ - return ServiceGenerator.getRequestApi() + private void retrievePosts(){ + ServiceGenerator.getRequestApi() .getPosts() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) - .flatMap(new Function, ObservableSource>() { - @Override - public ObservableSource apply(List posts) throws Exception { - adapter.setPosts(posts); - return Observable.fromIterable(posts) - .subscribeOn(Schedulers.io()); - } - }); + .subscribe(new Observer>() { + @Override + public void onSubscribe(Disposable d) { + disposables.add(d); + } + + @Override + public void onNext(List posts) { + adapter.setPosts(posts); + } + + @Override + public void onError(Throwable e) { + Log.e(TAG, "onError: ", e); + } + + @Override + public void onComplete() { + + } + }); } diff --git a/app/src/main/java/com/codingwithmitch/rxjavaflatmapexample/RecyclerAdapter.java b/app/src/main/java/com/codingwithmitch/rxjavaflatmapexample/RecyclerAdapter.java index 1be6f7b..1515c27 100644 --- a/app/src/main/java/com/codingwithmitch/rxjavaflatmapexample/RecyclerAdapter.java +++ b/app/src/main/java/com/codingwithmitch/rxjavaflatmapexample/RecyclerAdapter.java @@ -60,14 +60,11 @@ public List getPosts(){ public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { OnPostClickListener onPostClickListener; - TextView title, numComments; - ProgressBar progressBar; + TextView title; public MyViewHolder(@NonNull View itemView, OnPostClickListener onPostClickListener) { super(itemView); title = itemView.findViewById(R.id.title); - numComments = itemView.findViewById(R.id.num_comments); - progressBar = itemView.findViewById(R.id.progress_bar); this.onPostClickListener = onPostClickListener; @@ -77,23 +74,6 @@ public MyViewHolder(@NonNull View itemView, OnPostClickListener onPostClickListe public void bind(Post post){ title.setText(post.getTitle()); -// if(post.getComments() == null){ -// showProgressBar(true); -// numComments.setText(""); -// } -// else{ -// showProgressBar(false); -// numComments.setText(String.valueOf(post.getComments().size())); -// } - } - - private void showProgressBar(boolean showProgressBar){ - if(showProgressBar) { - progressBar.setVisibility(View.VISIBLE); - } - else{ - progressBar.setVisibility(View.GONE); - } } @Override diff --git a/app/src/main/java/com/codingwithmitch/rxjavaflatmapexample/requests/RequestApi.java b/app/src/main/java/com/codingwithmitch/rxjavaflatmapexample/requests/RequestApi.java index ff2a9d7..d81ca00 100644 --- a/app/src/main/java/com/codingwithmitch/rxjavaflatmapexample/requests/RequestApi.java +++ b/app/src/main/java/com/codingwithmitch/rxjavaflatmapexample/requests/RequestApi.java @@ -14,11 +14,6 @@ public interface RequestApi { @GET("posts") Observable> getPosts(); - @GET("posts/{id}/comments") - Observable> getComments( - @Path("id") int id - ); - @GET("posts/{id}") Observable getPost( @Path("id") int id diff --git a/app/src/main/res/layout/layout_post_list_item.xml b/app/src/main/res/layout/layout_post_list_item.xml index 74dc20d..bec30e5 100644 --- a/app/src/main/res/layout/layout_post_list_item.xml +++ b/app/src/main/res/layout/layout_post_list_item.xml @@ -3,52 +3,16 @@ android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content" - android:weightSum="100" android:padding="20dp"> - - - - - - - - - - - - - - - - - + android:id="@+id/title" + android:text="this is a title" + android:textColor="#000" + android:textSize="17sp" + /> \ No newline at end of file From 6ad1a930129a1c922caf9cb0697bff397a2ae28d Mon Sep 17 00:00:00 2001 From: Mitch Tabian Date: Tue, 26 Mar 2019 14:14:25 -0700 Subject: [PATCH 4/5] switch map --- .../rxjavaflatmapexample/MainActivity.java | 81 ++++++++++++------- app/src/main/res/layout/activity_main.xml | 17 +++- .../main/res/layout/activity_view_post.xml | 3 +- 3 files changed, 70 insertions(+), 31 deletions(-) diff --git a/app/src/main/java/com/codingwithmitch/rxjavaflatmapexample/MainActivity.java b/app/src/main/java/com/codingwithmitch/rxjavaflatmapexample/MainActivity.java index 5a55b3c..7d481bb 100644 --- a/app/src/main/java/com/codingwithmitch/rxjavaflatmapexample/MainActivity.java +++ b/app/src/main/java/com/codingwithmitch/rxjavaflatmapexample/MainActivity.java @@ -14,22 +14,29 @@ import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.CompositeDisposable; import io.reactivex.disposables.Disposable; +import io.reactivex.functions.BiFunction; import io.reactivex.functions.Function; import io.reactivex.functions.Predicate; import io.reactivex.schedulers.Schedulers; import io.reactivex.subjects.PublishSubject; +import android.app.Service; import android.content.Intent; import android.os.Bundle; import android.util.Log; +import android.widget.ProgressBar; import com.codingwithmitch.rxjavaflatmapexample.models.Comment; import com.codingwithmitch.rxjavaflatmapexample.models.Post; import com.codingwithmitch.rxjavaflatmapexample.requests.ServiceGenerator; +import org.reactivestreams.Subscription; + import java.util.List; import java.util.Random; +import java.util.concurrent.Callable; +import java.util.concurrent.TimeUnit; public class MainActivity extends AppCompatActivity implements RecyclerAdapter.OnPostClickListener { @@ -38,11 +45,13 @@ public class MainActivity extends AppCompatActivity implements RecyclerAdapter.O //ui private RecyclerView recyclerView; + private ProgressBar progressBar; // vars private CompositeDisposable disposables = new CompositeDisposable(); private RecyclerAdapter adapter; - private PublishSubject publishSubject = PublishSubject.create(); + private PublishSubject publishSubject = PublishSubject.create(); // for selecting a post + private static final int PERIOD = 100; @Override @@ -50,33 +59,50 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); recyclerView = findViewById(R.id.recycler_view); + progressBar = findViewById(R.id.progress_bar); initRecyclerView(); retrievePosts(); + } + private void initSwitchMapDemo(){ publishSubject + + // apply switchmap operator so only one Observable can be used at a time. + // it clears the previous one .switchMap(new Function>() { @Override - public ObservableSource apply(Post post) throws Exception { - return ServiceGenerator.getRequestApi() - .getPost(post.getId()) - .subscribeOn(Schedulers.io()) - .map(new Function() { // function that does nothing. Just sleeps the thread + public ObservableSource apply(final Post post) throws Exception { + return Observable + + // simulate slow network speed with interval + takeWhile + filter operators + .interval(PERIOD, TimeUnit.MILLISECONDS) + .subscribeOn(AndroidSchedulers.mainThread()) + .takeWhile(new Predicate() { // stop the process if more than 5 seconds passes @Override - public Post apply(Post post) throws Exception { - Log.d(TAG, "apply: retrieving individual post data: post id: " + post.getId()); - try { - Thread.sleep(3000); // thread blocking call - } catch (InterruptedException ex) { - // check if the interrupt is due to cancellation - // if so, no need to signal the InterruptedException - } - Log.d(TAG, "apply: sleeping thread: " + Thread.currentThread().getName() + " for 3000 ms"); - - return post; + public boolean test(Long aLong) throws Exception { + Log.d(TAG, "test: " + Thread.currentThread().getName() + ", " + aLong); + progressBar.setMax(3000 - PERIOD); + progressBar.setProgress(Integer.parseInt(String.valueOf((aLong * PERIOD) + PERIOD))); + return aLong <= (3000 / PERIOD); } }) - .observeOn(AndroidSchedulers.mainThread()); + .filter(new Predicate() { + @Override + public boolean test(Long aLong) throws Exception { + return aLong >= (3000 / PERIOD); + } + }) + + // flatmap to convert Long from the interval operator into a Observable + .subscribeOn(Schedulers.io()) + .flatMap(new Function>() { + @Override + public ObservableSource apply(Long aLong) throws Exception { + return ServiceGenerator.getRequestApi() + .getPost(post.getId()); + } + }); } }) .subscribe(new Observer() { @@ -87,13 +113,13 @@ public void onSubscribe(Disposable d) { @Override public void onNext(Post post) { - Log.d(TAG, "onNext: got the post! " + post.getId()); + Log.d(TAG, "onNext: done."); navViewPostActivity(post); } @Override public void onError(Throwable e) { - + Log.e(TAG, "onError: ", e); } @Override @@ -103,12 +129,6 @@ public void onComplete() { }); } - - private void updatePost(Post post){ - adapter.updatePost(post); - } - - private void retrievePosts(){ ServiceGenerator.getRequestApi() .getPosts() @@ -137,6 +157,12 @@ public void onComplete() { }); } + @Override + protected void onResume() { + super.onResume(); + progressBar.setProgress(0); + initSwitchMapDemo(); + } private void initRecyclerView(){ adapter = new RecyclerAdapter(this); @@ -153,7 +179,7 @@ private void navViewPostActivity(Post post){ @Override protected void onPause() { Log.d(TAG, "onPause: called."); - disposables.dispose(); + disposables.clear(); super.onPause(); } @@ -162,6 +188,7 @@ public void onPostClick(final int position) { Log.d(TAG, "onPostClick: clicked."); + // submit the selected post object to be queried publishSubject.onNext(adapter.getPosts().get(position)); } } diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 0b0e52a..11ad072 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,17 +1,28 @@ - + + - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_view_post.xml b/app/src/main/res/layout/activity_view_post.xml index a5a4c70..fae9e74 100644 --- a/app/src/main/res/layout/activity_view_post.xml +++ b/app/src/main/res/layout/activity_view_post.xml @@ -5,7 +5,8 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context=".MainActivity"> + tools:context=".MainActivity" + android:padding="15dp"> Date: Tue, 26 Mar 2019 14:15:02 -0700 Subject: [PATCH 5/5] switch map --- .../rxjavaflatmapexample/MainActivity.java | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/codingwithmitch/rxjavaflatmapexample/MainActivity.java b/app/src/main/java/com/codingwithmitch/rxjavaflatmapexample/MainActivity.java index 7d481bb..1e8243c 100644 --- a/app/src/main/java/com/codingwithmitch/rxjavaflatmapexample/MainActivity.java +++ b/app/src/main/java/com/codingwithmitch/rxjavaflatmapexample/MainActivity.java @@ -5,37 +5,29 @@ import androidx.recyclerview.widget.RecyclerView; import io.reactivex.Observable; -import io.reactivex.ObservableEmitter; -import io.reactivex.ObservableOnSubscribe; + import io.reactivex.ObservableSource; import io.reactivex.Observer; -import io.reactivex.Single; -import io.reactivex.SingleSource; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.CompositeDisposable; import io.reactivex.disposables.Disposable; -import io.reactivex.functions.BiFunction; import io.reactivex.functions.Function; import io.reactivex.functions.Predicate; import io.reactivex.schedulers.Schedulers; import io.reactivex.subjects.PublishSubject; -import android.app.Service; + import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.widget.ProgressBar; -import com.codingwithmitch.rxjavaflatmapexample.models.Comment; import com.codingwithmitch.rxjavaflatmapexample.models.Post; import com.codingwithmitch.rxjavaflatmapexample.requests.ServiceGenerator; -import org.reactivestreams.Subscription; import java.util.List; -import java.util.Random; -import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit;