Upgrade to Pro — share decks privately, control downloads, hide ads and more …

RxJava + Android

Mike Drabic
February 10, 2015

RxJava + Android

From Charlotte Android Devs Meetup - 2/10/2015

Mike Drabic

February 10, 2015
Tweet

Other Decks in Programming

Transcript

  1. Observable.create(new Observable.OnSubscribe<String>() {
 @Override
 public void call(Subscriber<? super String> subscriber)

    {
 subscriber.onNext("one");
 subscriber.onNext("two");
 subscriber.onNext("three");
 subscriber.onCompleted();
 }
 });
  2. Observable.create(new Observable.OnSubscribe<String>() {
 @Override
 public void call(Subscriber<? super String> subscriber)

    {
 subscriber.onNext("one");
 subscriber.onNext("two");
 subscriber.onNext("three");
 subscriber.onCompleted();
 }
 });
  3. Observable.create(new Observable.OnSubscribe<String>() {
 @Override
 public void call(Subscriber<? super String> sub)

    {
 subscriber.onNext("one");
 subscriber.onNext("two");
 subscriber.onNext("three");
 subscriber.onCompleted(); 
 }
 })
 .subscribe(/* observer, subscriber, or action implementations */);
  4. Observable.create(new Observable.OnSubscribe<String>() {
 @Override
 public void call(Subscriber<? super String> sub)

    {
 subscriber.onNext("one");
 subscriber.onNext("two");
 subscriber.onNext("three");
 subscriber.onCompleted(); 
 }
 })
 .subscribe(new Action1<String>() {
 @Override
 public void call(String s) {
 System.out.println("onNext(): " + s);
 }
 }, new Action1<Throwable>() {
 @Override
 public void call(Throwable throwable) {
 System.out.println("onError()");
 }
 }, new Action0() {
 @Override
 public void call() {
 System.out.println("onCompleted()!");
 }
 });
  5. Observable.create(new Observable.OnSubscribe<String>() {
 @Override
 public void call(Subscriber<? super String> sub)

    {
 subscriber.onNext("one");
 subscriber.onNext("two");
 subscriber.onNext("three");
 subscriber.onCompleted(); 
 }
 })
 .subscribe(new Action1<String>() {
 @Override
 public void call(String s) {
 System.out.println("onNext(): " + s);
 }
 }, new Action1<Throwable>() {
 @Override
 public void call(Throwable throwable) {
 System.out.println("onError()");
 }
 }, new Action0() {
 @Override
 public void call() {
 System.out.println("onCompleted()!");
 }
 }); onNext(): one onNext(): two onNext(): three onCompleted()
  6. RxJava Example Some Organization’s REST API Get all members in

    the organization Get each member’s avatar
  7. public class MemberService {
 
 public Observable<Member> getMembers() {
 //todo


    } public Observable<Bitmap> getAvatar(final Member member) { //todo }
 }
  8. public class MemberService {
 
 public Observable<Member> getMembers() {
 return

    Observable.create(new Observable.OnSubscribe<Member>() {
 @Override
 public void call(Subscriber<? super Member> subscriber) { //todo make sure we emit items and complete //todo handle errors 
 }
 });
 } public Observable<Bitmap> getAvatar(final Member member) { //todo }
 }
  9. public class MemberService {
 
 public Observable<Member> getMembers() {
 return

    Observable.create(new Observable.OnSubscribe<Member>() {
 @Override
 public void call(Subscriber<? super Member> subscriber) { //todo make sure we emit items and complete //todo handle errors 
 }
 });
 } public Observable<Bitmap> getAvatar(final Member member) { Observable.create(new Observable.OnSubscribe<Member>() {
 @Override
 public void call(Subscriber<? super Member> subscriber) { //todo make sure we emit items and complete //todo handle errors 
 }
 }); }
 }
  10. public class MemberService {
 
 public Observable<Member> getMembers() {
 return

    Observable.create(new Observable.OnSubscribe<Member>() {
 @Override
 public void call(Subscriber<? super Member> subscriber) { //todo make sure we emit items and complete //todo handle errors }
 });
 } /* getAvatar() omitted */
 }
  11. public class MemberService {
 
 public Observable<Member> getMembers() {
 return

    Observable.create(new Observable.OnSubscribe<Member>() {
 @Override
 public void call(Subscriber<? super Member> subscriber) { //todo make sure we emit items and complete //todo handle errors //getAllMembers sends HTTP request, parses response, etc List<Member> members = getAllMembers();
 }
 });
 } /* getAvatar() omitted */
 }
  12. public class MemberService {
 
 public Observable<Member> getMembers() {
 return

    Observable.create(new Observable.OnSubscribe<Member>() {
 @Override
 public void call(Subscriber<? super Member> subscriber) { //todo make sure we emit items and complete //todo handle errors //getAllMembers sends HTTP request, parses response, etc List<Member> members = getAllMembers(); for (Member member : members) {
 subscriber.onNext(member);
 } subscriber.onCompleted();
 }
 });
 } /* getAvatar() omitted */
 }
  13. public class MemberService {
 
 public Observable<Member> getMembers() { 


    return Observable.create(new Observable.OnSubscribe<Member>() { 
 @Override 
 public void call(Subscriber<? super Member> subscriber) {
 //todo handle errors
 //getAllMembers sends HTTP request, parses response, etc
 List<Member> members = getAllMembers();
 for (Member member : members) {
 subscriber.onNext(member); 
 }
 subscriber.onCompleted(); 
 } 
 }); }
 /* getAvatar() omitted */
 }

  14. public class MemberService {
 
 public Observable<Member> getMembers() { 


    return Observable.create(new Observable.OnSubscribe<Member>() { 
 @Override 
 public void call(Subscriber<? super Member> subscriber) {
 //todo handle errors
 //getAllMembers sends HTTP request, parses response, etc
 List<Member> members = getAllMembers();
 for (Member member : members) {
 subscriber.onNext(member); 
 }
 subscriber.onCompleted(); 
 } 
 }); }
 /* getAvatar() omitted */
 }

  15. public class MemberService {
 
 public Observable<Member> getMembers() {
 return

    Observable.create(new Observable.OnSubscribe<Member>() {
 
 @Override
 public void call(Subscriber<? super Member> subscriber) {
 //todo handle errors
 try {
 //getAllMembers sends HTTP request, parses response, etc
 List<Member> members = getAllMembers();
 for (Member member : members) {
 subscriber.onNext(member);
 }
 subscriber.onCompleted();
 } catch (Exception e) {
 //todo
 }
 }
 });
 } /* getAvatar() omitted */ }
  16. public class MemberService {
 
 public Observable<Member> getMembers() {
 return

    Observable.create(new Observable.OnSubscribe<Member>() {
 
 @Override
 public void call(Subscriber<? super Member> subscriber) {
 //todo handle errors
 try {
 //getAllMembers sends HTTP request, parses response, etc
 List<Member> members = getAllMembers();
 for (Member member : members) {
 subscriber.onNext(member);
 }
 subscriber.onCompleted();
 } catch (Exception e) {
 subscriber.onError(e); }
 }
 });
 } /* getAvatar() omitted */ }
  17. public class MemberService {
 
 /* getMembers() omitted */ public

    Observable<Bitmap> getAvatar(final Member member) {
 return Observable.create(new Observable.OnSubscribe<Bitmap>() {
 
 @Override
 public void call(Subscriber<? super Bitmap> subscriber) {
 try {
 //getMemberAvatar sends request, and converts response to a bitmap. Bitmap avatar = getMemberAvatar(member);
 subscriber.onNext(avatar);
 subscriber.onCompleted();
 } catch (Exception e) {
 subscriber.onError(e);
 }
 } 
 });
 }
 }
  18. public class MyFragment extends Fragment{
 private MemberService service;
 
 public

    void onCreate(Bundle savedInstance) { super.onCreate(savedInstance);
 Observable<Member> membersObservable = service.getMembers();
 //todo combine or chain these together
 Observable<Bitmap> avatarObservable = service.getAvatar(/* ??? */);
 }
 }
  19. public class MyFragment extends Fragment{
 private MemberService service;
 
 public

    void onCreate(Bundle savedInstance) { super.onCreate(savedInstance);
 Observable<Member> membersObservable = service.getMembers();
 //todo combine or chain these together
 Observable<Bitmap> avatarObservable = service.getAvatar(/* ??? */);
 }
 }
  20. public class MyFragment extends Fragment{
 private MemberService service;
 
 public

    void onCreate(Bundle savedInstance) { super.onCreate(savedInstance);
 Observable<Member> membersObservable = service.getMembers();
 }
 }
  21. public class MyFragment extends Fragment{
 private MemberService service;
 
 public

    void onCreate(Bundle savedInstance) { super.onCreate(savedInstance);
 Observable<Member> membersObservable = service.getMembers(); 
 membersObservable.flatMap(new Func1<Member, Observable<Member>>() {
 @Override
 public Observable<Member> call(Member member) {
 //todo }
 }); }
 }
  22. public class MyFragment extends Fragment{
 private MemberService service;
 
 public

    void onCreate(Bundle savedInstance) { super.onCreate(savedInstance);
 Observable<Member> membersObservable = service.getMembers(); 
 membersObservable.flatMap(new Func1<Member, Observable<Member>>() {
 @Override
 public Observable<Member> call(Member member) {
 //todo }
 }); }
 }
  23. public class MyFragment extends Fragment{
 private MemberService service;
 
 public

    void onCreate(Bundle savedInstance) { super.onCreate(savedInstance);
 Observable<Member> membersObservable = service.getMembers(); 
 membersObservable.flatMap(new Func1<Member, Observable<Member>>() {
 @Override
 public Observable<Member> call(Member member) {
 //todo }
 }); }
 }
  24. public class MyFragment extends Fragment{
 private MemberService service;
 
 public

    void onCreate(Bundle savedInstance) { super.onCreate(savedInstance);
 Observable<Member> membersObservable = service.getMembers(); 
 membersObservable.flatMap(new Func1<Member, Observable<Member>>() {
 @Override
 public Observable<Member> call(Member member) {
 return Observable.zip(?, ?, ?); }
 }); } }
  25. public class MyFragment extends Fragment{
 private MemberService service;
 
 public

    void onCreate(Bundle savedInstance) { super.onCreate(savedInstance);
 Observable<Member> membersObservable = service.getMembers(); 
 membersObservable.flatMap(new Func1<Member, Observable<Member>>() {
 @Override
 public Observable<Member> call(Member member) { Observable<Member> theMember = Observable.just(member);
 Observable<Bitmap> theAvatar = service.getAvatar(member);
 return Observable.zip(theMember, theAvatar, ?); }
 }); } }
  26. public class MyFragment extends Fragment{
 private MemberService service;
 
 public

    void onCreate(Bundle savedInstance) { super.onCreate(savedInstance);
 Observable<Member> membersObservable = service.getMembers(); 
 membersObservable.flatMap(new Func1<Member, Observable<Member>>() {
 @Override
 public Observable<Member> call(Member member) {
 Observable<Member> theMember = Observable.just(member);
 Observable<Bitmap> theAvatar = service.getAvatar(member);
 Func2<Member, Bitmap, Member> zipFunc = getZipFunc();
 return Observable.zip(theMember, theAvatar, zipFunc); }
 }); } private Func2<Member, Bitmap, Member> getZipFunc() {
 return new Func2<Member, Bitmap, Member>() {
 @Override
 public Member call(Member member, Bitmap avatar) {
 member.setAvatar(avatar);
 return member;
 }
 };
 }
 }
  27. public class MyFragment extends Fragment{
 private MemberService service;
 
 public

    void onCreate(Bundle savedInstance) {
 super.onCreate(savedInstance);
 //Get observable that will fetch all the members Observable<Member> membersObservable = service.getMembers(); //for each member, fetch the url, update the model, return the model membersObservable.flatMap(new Func1<Member, Observable<Member>>() {
 @Override
 public Observable<Member> call(Member member) {
 Observable<Member> theMember = Observable.just(member);
 Observable<Bitmap> theAvatar = service.getAvatar(member);
 Func2<Member, Bitmap, Member> zipFunc = getZipFunc();
 return Observable.zip(theMember, theAvatar, zipFunc);
 }
 });
 }
 
 private Func2<Member, Bitmap, Member> getZipFunc() {
 return new Func2<Member, Bitmap, Member>() {
 @Override
 public Member call(Member member, Bitmap avatar) {
 member.setAvatar(avatar);
 return member;
 }
 };
 } }
  28. RxJava ✓ Standard mechanism for error recovery ✓ Multiple ways

    in which individual tasks can be composed
  29. public class MyFragment extends Fragment{
 private MemberService service;
 
 public

    void onCreate(Bundle savedInstance) {
 super.onCreate(savedInstance);
 //Get observable that will fetch all the members Observable<Member> membersObservable = service.getMembers(); //for each member, fetch the url, update the model, return the model membersObservable.flatMap(new Func1<Member, Observable<Member>>() {
 @Override
 public Observable<Member> call(Member member) {
 Observable<Member> theMember = Observable.just(member);
 Observable<Bitmap> theAvatar = service.getAvatar(member);
 Func2<Member, Bitmap, Member> zipFunc = getZipFunc();
 return Observable.zip(theMember, theAvatar, zipFunc);
 }
 });
 }
 
 private Func2<Member, Bitmap, Member> getZipFunc() {
 return new Func2<Member, Bitmap, Member>() {
 @Override
 public Member call(Member member, Bitmap avatar) {
 member.setAvatar(avatar);
 return member;
 }
 };
 } }
  30. public class MyFragment extends Fragment{
 private MemberService service;
 
 public

    void onCreate(Bundle savedInstance) {
 super.onCreate(savedInstance);
 //Get observable that will fetch all the members Observable<Member> membersObservable = service.getMembers(); //for each member, fetch the url, update the model, return the model membersObservable.flatMap(new Func1<Member, Observable<Member>>() {
 @Override
 public Observable<Member> call(Member member) {
 Observable<Member> theMember = Observable.just(member);
 Observable<Bitmap> theAvatar = service.getAvatar(member);
 Func2<Member, Bitmap, Member> zipFunc = getZipFunc();
 return Observable.zip(theMember, theAvatar, zipFunc);
 }
 }) .subscribe(new Action1<Member>() {
 @Override
 public void call(Member member) {
 //adapter.add(member) which will update a ListView?
 }
 }, new Action1<Throwable>() {
 @Override
 public void call(Throwable throwable) {
 //show an AlertDialog to the user? 
 }
 });
 } /* getZipFunc() omitted */ }
  31. public class AnotherFragment extends Fragment {
 public void onCreate(Bundle savedInstance)

    {
 super.onCreate();
 Observable.just("Some long running work")
 .subscribe(new Action1<String>() {
 @Override
 public void call(String s) {
 System.out.println(s);
 }
 });
 } //TODO - Fix leaky subscription!!!!
 }
  32. public class AnotherFragment extends Fragment {
 
 private CompositeSubscription subscriptions

    = new CompositeSubscription();
 
 public void onCreate(Bundle savedInstance) {
 super.onCreate();
 Subscription subscription = Observable.just("Some long running work")
 .subscribe(new Action1<String>() {
 @Override
 public void call(String s) {
 System.out.println(s);
 }
 });
 subscriptions.add(subscription);
 }
 
 public void onDestroy() {
 subscriptions.unsubscribe();
 super.onDestory();
 }
 }
  33. RxJava ✓ Standard mechanism for error recovery ✓ Multiple ways

    in which individual task can be composed ✓ Hassle-free way of accessing a Context
  34. Observable.create(new Observable.OnSubscribe<String>() {
 @Override
 public void call(Subscriber<? super String> subscriber)

    {
 String threadId = String.valueOf(Thread.currentThread().getId());
 System.out.println("Working on: " + threadId);
 subscriber.onNext("Hello");
 subscriber.onNext("World");
 subscriber.onCompleted();
 }
 })
 .subscribe(new Action1<String>() {
 @Override
 public void call(String s) {
 String threadId = String.valueOf(Thread.currentThread().getId());
 System.out.println("onNext() Thread ID: " + threadId);
 }
 });
  35. Observable.create(new Observable.OnSubscribe<String>() {
 @Override
 public void call(Subscriber<? super String> subscriber)

    {
 String threadId = String.valueOf(Thread.currentThread().getId());
 System.out.println("Working on: " + threadId);
 subscriber.onNext("Hello");
 subscriber.onNext("World");
 subscriber.onCompleted();
 }
 })
 .subscribe(new Action1<String>() {
 @Override
 public void call(String s) {
 String threadId = String.valueOf(Thread.currentThread().getId());
 System.out.println("onNext() Thread ID: " + threadId);
 }
 }); Main/UI Thread ID: 1 Working on Thread ID: 1 onNext() Thread ID: 1 onNext() Thread ID: 1
  36. Observable.create(new Observable.OnSubscribe<String>() {
 @Override
 public void call(Subscriber<? super String> subscriber)

    {
 String threadId = String.valueOf(Thread.currentThread().getId());
 System.out.println("Working on Thread ID: " + threadId);
 subscriber.onNext("Hello");
 subscriber.onNext("World");
 subscriber.onCompleted();
 }
 })
 .observerOn(Schedulers.newThread())
 .subscribe(new Action1<String>() {
 @Override
 public void call(String s) {
 String threadId = String.valueOf(Thread.currentThread().getId());
 System.out.println("onNext() Thread ID: " + threadId);
 }
 });
  37. Observable.create(new Observable.OnSubscribe<String>() {
 @Override
 public void call(Subscriber<? super String> subscriber)

    {
 String threadId = String.valueOf(Thread.currentThread().getId());
 System.out.println("Working on Thread ID: " + threadId);
 subscriber.onNext("Hello");
 subscriber.onNext("World");
 subscriber.onCompleted();
 }
 })
 .observerOn(Schedulers.newThread())
 .subscribe(new Action1<String>() {
 @Override
 public void call(String s) {
 String threadId = String.valueOf(Thread.currentThread().getId());
 System.out.println("onNext() Thread ID: " + threadId);
 }
 }); Main/UI Thread ID: 1 Working on Thread ID: 1 onNext() Thread ID: 11 onNext() Thread ID: 11
  38. Observable.create(new Observable.OnSubscribe<String>() {
 @Override
 public void call(Subscriber<? super String> subscriber)

    {
 String threadId = String.valueOf(Thread.currentThread().getId());
 System.out.println("Working on Thread ID: " + threadId);
 subscriber.onNext("Hello");
 subscriber.onNext("World");
 subscriber.onCompleted();
 }
 })
 .subscribeOn(Schedulers.newThread()) .observeOn(Schedulers.newThread())
 .subscribe(new Action1<String>() {
 @Override
 public void call(String s) {
 String threadId = String.valueOf(Thread.currentThread().getId());
 System.out.println("onNext() Thread ID: " + threadId);
 }
 });
  39. Observable.create(new Observable.OnSubscribe<String>() {
 @Override
 public void call(Subscriber<? super String> subscriber)

    {
 String threadId = String.valueOf(Thread.currentThread().getId());
 System.out.println("Working on Thread ID: " + threadId);
 subscriber.onNext("Hello");
 subscriber.onNext("World");
 subscriber.onCompleted();
 }
 })
 .subscribeOn(Schedulers.newThread())
 .subscribeOn(Schedulers.newThread())
 .subscribe(new Action1<String>() {
 @Override
 public void call(String s) {
 String threadId = String.valueOf(Thread.currentThread().getId());
 System.out.println("onNext() Thread ID: " + threadId);
 }
 }); Main/UI Thread ID: 1 Working on Thread ID: 12 onNext() Thread ID: 11 onNext() Thread ID: 11
  40. public class MyFragment extends Fragment{
 private MemberService service;
 
 public

    void onCreate(Bundle savedInstance) {
 super.onCreate(savedInstance);
 //Get observable that will fetch all the members Observable<Member> membersObservable = service.getMembers(); membersObservable.flatMap(new Func1<Member, Observable<Member>>() {
 @Override
 public Observable<Member> call(Member member) {
 Observable<Member> theMember = Observable.just(member);
 Observable<Bitmap> theAvatar = service.getAvatar(member);
 Func2<Member, Bitmap, Member> zipFunc = getZipFunc();
 return Observable.zip(theMember, theAvatar, zipFunc);
 }
 }) .subscribe(new Action1<Member>() {
 @Override
 public void call(Member member) {
 //adapter.add(member) which will update a ListView?
 }
 }, new Action1<Throwable>() {
 @Override
 public void call(Throwable throwable) {
 //show an AlertDialog to the user? 
 }
 });
 } } }
  41. public class MyFragment extends Fragment{
 private MemberService service;
 
 public

    void onCreate(Bundle savedInstance) {
 super.onCreate(savedInstance);
 //Get observable that will fetch all the members Observable<Member> membersObservable = service.getMembers(); membersObservable.flatMap(new Func1<Member, Observable<Member>>() {
 @Override
 public Observable<Member> call(Member member) {
 Observable<Member> theMember = Observable.just(member);
 Observable<Bitmap> theAvatar = service.getPhotoUrl(member);
 Func2<Member, Bitmap, Member> zipFunc = getZipFunc();
 return Observable.zip(theMember, theAvatar, zipFunc);
 }
 }) .subscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Action1<Member>() {
 @Override
 public void call(Member member) {
 //adapter.add(member) which will update a ListView?
 }
 }, new Action1<Throwable>() {
 @Override
 public void call(Throwable throwable) {
 //show an AlertDialog to the user? 
 }
 });
 } }
  42. RxJava ✓ Standard mechanism for error recovery ✓ Multiple ways

    in which individual task can be composed ✓ Near hassle-free way of using a Context ✓ Easy control over thread scheduling
  43. FlatMap applies a function to the output of a source

    observable and returns an observable that emits anything
  44. List<String> nums = new ArrayList<>();
 nums.add("1");
 nums.add("2");
 nums.add("3");
 
 Observable.just(nums)


    .flatMap(new Func1<List<String>, Observable<String>>() {
 @Override
 public Observable<String> call(List<String> nums) {
 return Observable.from(nums);
 }
 }) .subscribe(new Action1<String>() {
 @Override
 public void call(Integer s) {
 System.out.println("onNext():" + s);
 }
 });
  45. List<String> nums = new ArrayList<>();
 nums.add("1");
 nums.add("2");
 nums.add("3");
 
 Observable.just(nums)


    .flatMap(new Func1<List<String>, Observable<String>>() {
 @Override
 public Observable<String> call(List<String> nums) {
 return Observable.from(nums);
 }
 }) .subscribe(new Action1<String>() {
 @Override
 public void call(Integer s) {
 System.out.println("onNext():" + s);
 }
 }); onNext(): 1 onNext(): 2 onNext(): 3
  46. List<String> nums = new ArrayList<>();
 nums.add("1");
 nums.add("2");
 nums.add("3");
 
 Observable.just(nums)


    .flatMap(new Func1<List<String>, Observable<?>>() {
 @Override
 public Observable<?> call(List<String> nums) {
 //todo return whatever observable we want!!!
 }
 });
  47. List<String> nums = new ArrayList<>();
 nums.add("1");
 nums.add("2");
 nums.add("3");
 
 Observable.just(nums)


    .flatMap(new Func1<List<String>, Observable<Integer>>() {
 @Override
 public Observable<Integer> call(List<String> nums) { List<Integer> asInts = new ArrayList<>();
 for (String num : nums) {
 asInts.add(Integer.parseInt(num));
 }
 return Observable.from(asInts);
 }
 }) .subscribe(new Action1<Integer>() {
 @Override
 public void call(Integer integer) {
 System.out.println("onNext():" + integer.toString());
 }
 }); onNext(): 1 onNext(): 2 onNext(): 3
  48. Zip combines the emissions of two or more observables via

    a function and returns an observable that emits the result of this function.
  49. Observable<Integer> numbers = Observable.just(1, 2, 3);
 Observable<String> letters = Observable.just("A",

    "B", “C"); 
 Observable.zip(numbers, letters, new Func2<Integer, String, SimpleEntry>() {
 @Override
 public SimpleEntry<Integer, String> call(Integer key, String value) {
 return new SimpleEntry<>(key, value);
 }
 })
 .subscribe(new Action1<SimpleEntry>() {
 @Override
 public void call(SimpleEntry entry) {
 System.out.println(entry.getKey() + " :: " + entry.getValue());
 }
 });
  50. Observable<Integer> numbers = Observable.just(1, 2, 3);
 Observable<String> letters = Observable.just("A",

    "B", “C"); 
 Observable.zip(numbers, letters, new Func2<Integer, String, SimpleEntry>() {
 @Override
 public SimpleEntry<Integer, String> call(Integer key, String value) {
 return new SimpleEntry<>(key, value);
 }
 })
 .subscribe(new Action1<SimpleEntry>() {
 @Override
 public void call(SimpleEntry entry) {
 System.out.println(entry.getKey() + " :: " + entry.getValue());
 }
 });
  51. Observable<Integer> numbers = Observable.just(1, 2, 3);
 Observable<String> letters = Observable.just("A",

    "B", “C"); 
 Observable.zip(numbers, letters, new Func2<Integer, String, SimpleEntry>() {
 @Override
 public SimpleEntry<Integer, String> call(Integer key, String value) {
 return new SimpleEntry<>(key, value);
 }
 })
 .subscribe(new Action1<SimpleEntry>() {
 @Override
 public void call(SimpleEntry entry) {
 System.out.println(“OnNext(): ” + entry.getKey() + " :: " + entry.getValue());
 }
 }); onNext(): 1 :: A onNext(): 2 :: B onNext(): 3 :: C