Cách tôi nghĩ về nó là bạn sử dụng flatMap
khi hàm bạn muốn đặt bên trong số map()
trả về số Observable
. Trong trường hợp đó, bạn vẫn có thể thử sử dụng map()
nhưng sẽ không thực tế. Hãy để tôi cố gắng giải thích tại sao.
Nếu trong trường hợp này, bạn quyết định gắn bó với map
, bạn sẽ nhận được Observable<Observable<Something>>
. Ví dụ trong trường hợp của bạn, nếu chúng ta sử dụng một thư viện RxGson tưởng tượng, đó quay trở lại một Observable<String>
từ nó toJson()
phương pháp (thay vì chỉ đơn giản là trả lại một String
) nó sẽ trông như thế này:
Observable.from(jsonFile).map(new Func1<File, Observable<String>>() {
@Override public Observable<String>> call(File file) {
return new RxGson().toJson(new FileReader(file), Object.class);
}
}); // you get Observable<Observable<String>> here
Tại thời điểm này nó sẽ là khá khéo léo để subscribe()
đến một quan sát như vậy. Bên trong nó, bạn sẽ nhận được một Observable<String>
mà bạn sẽ lại cần phải subscribe()
để lấy giá trị. Đó là không thực tế hoặc tốt đẹp để xem xét.
Vì vậy, để làm cho nó hữu ích một ý tưởng là "làm phẳng" điều này quan sát được các quan sát (bạn có thể bắt đầu thấy tên _flat_Map đến từ đâu). RxJava cung cấp một vài cách để làm phẳng các quan sát và vì mục đích đơn giản cho phép giả sử merge là những gì chúng ta muốn. Hợp nhất về cơ bản có một loạt các quan sát và phát ra bất cứ khi nào bất kỳ trong số họ phát ra. (Rất nhiều người sẽ cho switch sẽ là một mặc định tốt hơn Nhưng nếu bạn đang phát ra chỉ là một giá trị, nó không quan trọng anyway..)
Vì vậy, việc sửa đổi đoạn trước, chúng tôi sẽ nhận được:
Observable.from(jsonFile).map(new Func1<File, Observable<String>>() {
@Override public Observable<String>> call(File file) {
return new RxGson().toJson(new FileReader(file), Object.class);
}
}).merge(); // you get Observable<String> here
Điều này hữu ích hơn rất nhiều, bởi vì đăng ký vào đó (hoặc ánh xạ, hoặc lọc, hoặc ...) bạn chỉ nhận được giá trị String
. (Ngoài ra, nhớ bạn, biến thể như vậy của merge()
không tồn tại trong RxJava, nhưng nếu bạn hiểu ý tưởng hợp nhất thì tôi hy vọng bạn cũng hiểu cách thức đó sẽ hoạt động.)
Vì vậy, về cơ bản vì vậy merge()
có lẽ chỉ bao giờ hữu ích khi nó thành công một map()
trả lại một quan sát được và do đó bạn không phải gõ lại nhiều lần, flatMap()
được tạo ra như một cách viết tắt. Nó áp dụng hàm ánh xạ giống như bình thường map()
, nhưng sau đó thay vì phát ra các giá trị trả về, nó cũng "làm phẳng" (hoặc hợp nhất) chúng.
Đó là trường hợp sử dụng chung. Nó hữu dụng nhất trong một codebase sử dụng Rx allover nơi và bạn có nhiều phương thức trả về các quan sát, mà bạn muốn kết nối với các phương thức khác trả về các quan sát.
Trong trường hợp sử dụng của bạn, điều này cũng hữu ích vì map()
chỉ có thể chuyển đổi một giá trị được phát ra trong onNext()
thành giá trị khác được phát ra trong onNext()
. Nhưng nó không thể biến đổi nó thành nhiều giá trị, không có giá trị nào cả hoặc một lỗi. Và như akarnokd đã viết trong câu trả lời của mình (và nhớ bạn thông minh hơn tôi nhiều, có lẽ nói chung, nhưng ít nhất là khi nói đến RxJava) bạn không nên ném ngoại lệ từ map()
của mình. Vì vậy, thay vào đó bạn có thể sử dụng flatMap()
và
return Observable.just(value);
khi mọi việc suôn sẻ, nhưng
return Observable.error(exception);
khi một cái gì đó thất bại.
Xem câu trả lời của mình cho một đoạn hoàn chỉnh: https://stackoverflow.com/a/30330772/1402641
Điều này không gọi 'subscriber.onError()' vv. Tất cả các ví dụ tôi đã thấy đã định tuyến lỗi theo cách đó. Điều đó có quan trọng không? –
Lưu ý rằng các hàm tạo của 'OnErrorThrowable' là' private' và bạn cần sử dụng 'OnErrorThrowable.from (e)' để thay thế. –
Tôi vừa cập nhật. OnErrorThrowable.from (e) không giữ giá trị, vì vậy tôi sử dụng OnErrorThrowable.addValueAsLastCause (e, file) thay vào đó, nên giữ giá trị. – dwursteisen