This tutorial shows you how to use materialize()
and dematerialize()
operators in RxDart.
Normally, an Observable will invoke the onData
method of its observers for zero or multiple times. After that, it will invoke either onDone
or onError
. That means there are three kinds of event and you may need to have different handlers for each kind of event. By using Materialize
, it becomes possible to have a general handler for all kinds of event. Materialize
works by projecting a Stream
of values into a stream of Notification
objects.
Notification
has the following properties:
Name | Type | Description |
---|---|---|
kind |
Kind |
Kind of the event. (Kind.OnData, Kind.OnDone , or Kind.OnError ) |
value |
T |
- |
error |
dynamic |
- |
stackTrace |
StackTrace |
- |
It's also possible to do the opposite thing: dematerializing Notification objects. The operators for materialize
and dematerialize
are available in RxDart. For usage examples, see the below examples.
Materialize Example
For converting onData
, onDone
, and onError
events into Notification
objects, Dart provides materialize()
operator.
import 'package:rxdart/rxdart.dart';
class MyException implements Exception {
String _message;
MyException([String message = 'Invalid value']) {
this._message = message;
}
@override
String toString() {
return _message;
}
}
void main(List<String> arguments) {
Observable.range(1, 4)
.map((value) => value < 4 ? value : throw Observable.error(new MyException()))
.materialize()
.listen(print);
}
Output:
Notification{kind: Kind.OnData, value: 1, error: null, stackTrace: null}
Notification{kind: Kind.OnData, value: 2, error: null, stackTrace: null}
Notification{kind: Kind.OnData, value: 3, error: null, stackTrace: null}
Notification{kind: Kind.OnError, value: null, error: Instance of 'Observable<dynamic>', stackTrace: #0 main.<anonymous closure> (file:///home/ivan/try-dart/src/rxdart-materialize.dart:36:43)
#1 _MapStream._handleData (dart:async/stream_pipe.dart:229:21)
#2 _ForwardingStreamSubscription._handleData (dart:async/stream_pipe.dart:166:13)
#3 _RootZone.runUnaryGuarded (dart:async/zone.dart:1316:10)
#4 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:338:11)
#5 _IterablePendingEvents.handleNext (dart:async/stream_impl.dart:539:18)
#6 _PendingEvents.schedule.<anonymous closure> (dart:async/stream_impl.dart:669:7)
#7 _microtaskLoop (dart:async/schedule_microtask.dart:43:21)
#8 _startMicrotaskLoop (dart:async/schedule_microtask.dart:52:5)
#9 _runPendingImmediateCallback (dart:isolate-patch/isolate_patch.dart:118:13)
#10 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:175:5)
}
Notification{kind: Kind.OnDone, value: null, error: null, stackTrace: null}
As you can see, the output are Notification
objects that have properties as mentioned on the above table.
Dematerialize Example
In case you need to dematerialize Notification
objects into onData
, onDone
, and onError
events, you can use dematerialize()
operator.
Observable<Notification<int>> o = Observable.range(1, 4)
.map((value) => value < 4 ? value : throw Observable.error(new MyException()))
.materialize();
o.dematerialize()
.listen(print);
Output:
1
2
3
Unhandled exception:
Instance of 'Observable<dynamic>'
#0 main.<anonymous closure> (file:///home/ivan/try-dart/src/rxdart-materialize.dart:44:43)
#1 _MapStream._handleData (dart:async/stream_pipe.dart:229:21)
#2 _ForwardingStreamSubscription._handleData (dart:async/stream_pipe.dart:166:13)
#3 _RootZone.runUnaryGuarded (dart:async/zone.dart:1316:10)
#4 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:338:11)
#5 _IterablePendingEvents.handleNext (dart:async/stream_impl.dart:539:18)
#6 _PendingEvents.schedule.<anonymous closure> (dart:async/stream_impl.dart:669:7)
#7 _microtaskLoop (dart:async/schedule_microtask.dart:43:21)
#8 _startMicrotaskLoop (dart:async/schedule_microtask.dart:52:5)
#9 _runPendingImmediateCallback (dart:isolate-patch/isolate_patch.dart:118:13)
#10 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:175:5)