Retrofit & RxJava multiple requests complete

If you don't want to do something specific with the combined results, then merge() is enough:

Observable<RegionalNews> regionalNews = ...;
Observable<NationalNews> nationalNews = ...;

Observable
.merge(regionalNews, nationalNews)
.ignoreElements()
.observeOn(AndroidSchedulers.mainThread())
.doOnComplete(() -> { /* show alert */ })
.subscribe()

You can use zip operator to call 2 requests async and save or process their data on response.

For example.

Below are two Observable

Observable<ResponseOne> responseOneObservable = getRetrofitClient().getDataOne()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());

Observable<ResponseTwo> responseTwoObservable = getRetrofitClient().getDataTwo()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());

Using zip operator on above two Observable as below.

Observable<ArrayList<TestData>> testDataObservable = Observable.zip(responseOneObservable, responseTwoObservable, new Func2<ResponseOne, ResponseTwo, ArrayList<TestData>>() {
            @Override
                public ArrayList<TestData> call(ResponseOne responseOne, ResponseTwo responseTwo) {
                  ArrayList<TestData> testDataList = new ArrayList();
                      // process data from response responseOne & responseTwo
                  return testDataList;
            } 
    })
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(new Subscriber<ArrayList<TestData>>() {

        @Override
        public void onNext(ArrayList<TestData> testDataList) {

        }

        @Override
        public void onCompleted() {
            Log.d(TAG, "onCompleted" ); 
            // you can show alert here or do something when completed 
        }

        @Override
        public void onError(Throwable t) {
            Log.d(TAG, "onError Throwable: " + t.toString() );
        }
    });

Well it depends, as always. Do you need to process the returned values down the chain, or just save it?

In this implementation I use Single and Completable. You subscribe to the completable and you will get notified when both Singles finished.

@Test
public void name() throws Exception {
        TestScheduler testScheduler = new TestScheduler();
        Single<Long> request1 = Single.timer(1000, TimeUnit.MILLISECONDS, testScheduler)
                .doOnSuccess(aLong -> {
                    System.out.println("save to db.");
                });
        Single<Long> request2 = Single.timer(500, TimeUnit.MILLISECONDS, testScheduler)
                .doOnSuccess(aLong -> {
                    System.out.println("save to db.");
                });

        Completable completable = Single.zip(request1, request2, (aLong, aLong2) -> aLong).toCompletable();

        TestObserver<Void> test = completable.test();

        testScheduler.advanceTimeBy(1010, TimeUnit.MILLISECONDS);

        test.assertComplete();
}

You also can use flatMapCompletable instead of doOnSuccess

@Test
public void name() throws Exception {
    TestScheduler testScheduler = new TestScheduler();
    Completable request1 = Single.timer(1000, TimeUnit.MILLISECONDS, testScheduler)
            .flatMapCompletable(this::saveToDb);

    Completable request2 = Single.timer(500, TimeUnit.MILLISECONDS, testScheduler)
            .flatMapCompletable(this::saveToDb);

    // need to cheat here, becuase completeable does not provide zip
    Completable completable = Single.zip(request1.toSingle(() -> 1), request1.toSingle(() -> 1), (aLong, aLong2) -> aLong)
            .toCompletable();

    TestObserver<Void> test = completable.test();

    testScheduler.advanceTimeBy(1010, TimeUnit.MILLISECONDS);

    test.assertComplete();
}

private Completable saveToDb(long value) {
    return Completable.complete();
}

zip is the way to combine observables. Combining their results is just a consequence.

If you want to wait for both observables to finish (complete), the easiest way is to use zip. You just don't have to use the results of your requests in the combining function. Just use this function as a way to emit something different when both of those calls finish. When this function emits an item:

[...] do something when all requests completed (show alert for example)

For example like this (executing someOtherCall when both of those requests finish):

Observable<Integer> obs1 = ...;
Observable<Long> obs2 = ...;

Observable.zip(obs1, obs2, new Func2<Integer, Long, String>() {
    @Override
    public String call(Integer integer, Long aLong) {
        return "something completely different";
    }
}).flatMap(new Func1<String, Observable<Float>>() {
    @Override
    public Observable<Float> call(String s) {
        return performSomeOtherCall();
    }
}).subscribe(...);