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 8120e60..1e8243c 100644
--- a/app/src/main/java/com/codingwithmitch/rxjavaflatmapexample/MainActivity.java
+++ b/app/src/main/java/com/codingwithmitch/rxjavaflatmapexample/MainActivity.java
@@ -3,7 +3,9 @@
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;
import io.reactivex.android.schedulers.AndroidSchedulers;
@@ -12,27 +14,36 @@
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;
+import android.widget.ProgressBar;
-import com.codingwithmitch.rxjavaflatmapexample.models.Comment;
import com.codingwithmitch.rxjavaflatmapexample.models.Post;
import com.codingwithmitch.rxjavaflatmapexample.requests.ServiceGenerator;
+
import java.util.List;
-import java.util.Random;
+import java.util.concurrent.TimeUnit;
+
-public class MainActivity extends AppCompatActivity {
+public class MainActivity extends AppCompatActivity implements RecyclerAdapter.OnPostClickListener {
private static final String TAG = "MainActivity";
//ui
private RecyclerView recyclerView;
+ private ProgressBar progressBar;
// vars
private CompositeDisposable disposables = new CompositeDisposable();
private RecyclerAdapter adapter;
+ private PublishSubject publishSubject = PublishSubject.create(); // for selecting a post
+ private static final int PERIOD = 100;
@Override
@@ -40,18 +51,52 @@ 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();
+ }
- getPostsObservable()
- .subscribeOn(Schedulers.io())
- .flatMap(new Function>() {
+ 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 getCommentsObservable(post);
+ 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 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);
+ }
+ })
+ .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());
+ }
+ });
}
})
- .observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer() {
@Override
public void onSubscribe(Disposable d) {
@@ -60,7 +105,8 @@ public void onSubscribe(Disposable d) {
@Override
public void onNext(Post post) {
- updatePost(post);
+ Log.d(TAG, "onNext: done.");
+ navViewPostActivity(post);
}
@Override
@@ -70,57 +116,90 @@ public void onError(Throwable e) {
@Override
public void onComplete() {
+
}
});
}
- 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(final List posts) throws Exception {
- adapter.setPosts(posts);
- return Observable.fromIterable(posts)
- .subscribeOn(Schedulers.io());
- }
- });
- }
-
- private void updatePost(Post post){
- adapter.updatePost(post);
+ .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() {
+
+ }
+ });
}
- 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; // sleep thread for x ms
- Thread.sleep(delay);
- Log.d(TAG, "apply: sleeping thread " + Thread.currentThread().getName() + " for " + String.valueOf(delay)+ "ms");
-
- post.setComments(comments);
- return post;
- }
- })
- .subscribeOn(Schedulers.io());
-
+ @Override
+ protected void onResume() {
+ super.onResume();
+ progressBar.setProgress(0);
+ initSwitchMapDemo();
}
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 onDestroy() {
- super.onDestroy();
+ protected void onPause() {
+ Log.d(TAG, "onPause: called.");
disposables.clear();
+ super.onPause();
+ }
+
+ @Override
+ 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/java/com/codingwithmitch/rxjavaflatmapexample/RecyclerAdapter.java b/app/src/main/java/com/codingwithmitch/rxjavaflatmapexample/RecyclerAdapter.java
index 839aa6f..1515c27 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,42 +57,35 @@ public List getPosts(){
return posts;
}
- public class MyViewHolder extends RecyclerView.ViewHolder{
+ public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
- TextView title, numComments;
- ProgressBar progressBar;
+ OnPostClickListener onPostClickListener;
+ TextView title;
- 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()));
- }
}
- private void showProgressBar(boolean showProgressBar){
- if(showProgressBar) {
- progressBar.setVisibility(View.VISIBLE);
- }
- else{
- 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..d81ca00 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;
@@ -16,8 +14,8 @@ public interface RequestApi {
@GET("posts")
Observable> getPosts();
- @GET("posts/{id}/comments")
- Observable> getComments(
+ @GET("posts/{id}")
+ Observable getPost(
@Path("id") int id
);
}
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
new file mode 100644
index 0000000..fae9e74
--- /dev/null
+++ b/app/src/main/res/layout/activity_view_post.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
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