I need to save the result of the following StreamSubscription passing a non-static member variable _uid. which is not allowed. What workarounds are possible to make this work?
StreamSubscription < LocationResult > subscription = Geolocation.locationUpdates(
accuracy: LocationAccuracy.best,
displacementFilter: 10.0, // in meters
inBackground: true, // by default, location updates will pause when app is inactive (in background). Set to `true` to continue updates in background.
)
.listen((result) {
if (result.isSuccessful) {
saveResult(result, _uid);
} else {
}
});
_uid is set during Widget build:
String _uid = UserModel.of(context).firebaseUser.uid;
I can't access _uid in saveResult() either since it's a static method.
Related
I'm trying to aggregate (per key) a streaming data source in Apache Beam (via Scio) using a stateful DoFn (using #ProcessElement with #StateId ValueState elements). I thought this would be most appropriate for the problem I'm trying to solve. The requirements are:
for a given key, records are aggregated (essentially summed) across all time - I don't care about previously computed aggregates, just the most recent
keys may be evicted from the state (state.clear()) based on certain conditions that I control
Every 5 minutes, regardless if any new keys were seen, all keys that haven't been evicted from the state should be outputted
Given that this is a streaming pipeline and will be running indefinitely, using a combinePerKey over a global window with accumulating fired panes seems like it will continue to increase its memory footprint and the amount of data it needs to run over time, so I'd like to avoid it. Additionally, when testing this out, (maybe as expected) it simply appends the newly computed aggregates to the output along with the historical input, rather than using the latest value for each key.
My thought was that using a StatefulDoFn would simply allow me to output all of the global state up until now(), but it seems this isn't a trivial solution. I've seen hintings at using timers to artificially execute callbacks for this, as well as potentially using a slowly growing side input map (How to solve Duplicate values exception when I create PCollectionView<Map<String,String>>) and somehow flushing this, but this would essentially require iterating over all values in the map rather than joining on it.
I feel like I might be overlooking something simple to get this working. I'm relatively new to many concepts of windowing and timers in Beam, looking for any advice on how to solve this. Thanks!
You are right that Stateful DoFn should help you here. This is a basic sketch of what you can do. Note that this only outputs the sum without the key. It may not be exactly what you want, but it should help you move forward.
class CombiningEmittingFn extends DoFn<KV<Integer, Integer>, Integer> {
#TimerId("emitter")
private final TimerSpec emitterSpec = TimerSpecs.timer(TimeDomain.PROCESSING_TIME);
#StateId("done")
private final StateSpec<ValueState<Boolean>> doneState = StateSpecs.value();
#StateId("agg")
private final StateSpec<CombiningState<Integer, int[], Integer>>
aggSpec = StateSpecs.combining(
Sum.ofIntegers().getAccumulatorCoder(null, VarIntCoder.of()), Sum.ofIntegers());
#ProcessElement
public void processElement(ProcessContext c,
#StateId("agg") CombiningState<Integer, int[], Integer> aggState,
#StateId("done") ValueState<Boolean> doneState,
#TimerId("emitter") Timer emitterTimer) throws Exception {
if (SOME CONDITION) {
countValueState.clear();
doneState.write(true);
} else {
countValueState.addAccum(c.element().getValue());
emitterTimer.align(Duration.standardMinutes(5)).setRelative();
}
}
}
#OnTimer("emitter")
public void onEmit(
OnTimerContext context,
#StateId("agg") CombiningState<Integer, int[], Integer> aggState,
#StateId("done") ValueState<Boolean> doneState,
#TimerId("emitter") Timer emitterTimer) {
Boolean isDone = doneState.read();
if (isDone != null && isDone) {
return;
} else {
context.output(aggState.getAccum());
// Set the timer to emit again
emitterTimer.align(Duration.standardMinutes(5)).setRelative();
}
}
}
}
Happy to iterate with you on something that'll work.
#Pablo was indeed correct that a StatefulDoFn and timers are useful in this scenario. Here is the with code I was able to get working.
Stateful Do Fn
// DomainState is a custom case class I'm using
type DoFnT = DoFn[KV[String, DomainState], KV[String, DomainState]]
class StatefulDoFn extends DoFnT {
#StateId("key")
private val keySpec = StateSpecs.value[String]()
#StateId("domainState")
private val domainStateSpec = StateSpecs.value[DomainState]()
#TimerId("loopingTimer")
private val loopingTimer: TimerSpec = TimerSpecs.timer(TimeDomain.EVENT_TIME)
#ProcessElement
def process(
context: DoFnT#ProcessContext,
#StateId("key") stateKey: ValueState[String],
#StateId("domainState") stateValue: ValueState[DomainState],
#TimerId("loopingTimer") loopingTimer: Timer): Unit = {
... logic to create key/value from potentially null values
if (keepState(value)) {
loopingTimer.align(Duration.standardMinutes(5)).setRelative()
stateKey.write(key)
stateValue.write(value)
if (flushState(value)) {
context.output(KV.of(key, value))
}
} else {
stateValue.clear()
}
}
#OnTimer("loopingTimer")
def onLoopingTimer(
context: DoFnT#OnTimerContext,
#StateId("key") stateKey: ValueState[String],
#StateId("domainState") stateValue: ValueState[DomainState],
#TimerId("loopingTimer") loopingTimer: Timer): Unit = {
... logic to create key/value checking for nulls
if (keepState(value)) {
loopingTimer.align(Duration.standardMinutes(5)).setRelative()
if (flushState(value)) {
context.output(KV.of(key, value))
}
}
}
}
With pipeline
sc
.pubsubSubscription(...)
.keyBy(...)
.withGlobalWindow()
.applyPerKeyDoFn(new StatefulDoFn())
.withFixedWindows(
duration = Duration.standardMinutes(5),
options = WindowOptions(
accumulationMode = DISCARDING_FIRED_PANES,
trigger = AfterWatermark.pastEndOfWindow(),
allowedLateness = Duration.ZERO,
// Only take the latest per key during a window
timestampCombiner = TimestampCombiner.END_OF_WINDOW
))
.reduceByKey(mostRecentEvent())
.saveAsCustomOutput(TextIO.write()...)
In Dart, I have a class like this that protects _x behind getters/setters which allows me to control changes to _x:
//in a.dart
class A {
int _x;
int get x => _x;
set x(int value) {
bool validation_ok=true;
//do some validation/processing
if (validation_ok) {
_x = value;
//perform side effects that should happen every time _x changes e.g. save to SharedPreferences
print('Validated $value and side effects performed');
}
}
}
//in amain.dart
import 'a.dart';
void main() {
A a = A();
a.x = 5; //if validation successful stores 5 to _x and performs side effects
print(a.x); //prints 'Validated 5 and side effects performed' and then '5'
}
But what can I do if instead of an int, I want to protect a List or an object?
//in b.dart
class B {
List<int> _y;
List<int> get y => _y;
set y(List<int> value) {
bool validation_ok=true;
//do some validation/processing
if (validation_ok) {
_y = value;
//perform side effects that should happen every time _y changes e.g. save to SharedPreferences
print('Validated $value and side effects performed');
}
}
}
//in bmain.dart
import 'b.dart';
void main() {
B b = B();
b.y = [5]; //if validation successful stores [5] to _y and performs side effects
print(b.y); //prints 'Validated [5] and side effects performed' and '[5]'
b.y.add(6); //now _y is [5,6] but no validation was done on 6 and no side effects performed
print(b.y); //prints '[5,6]' only
}
Notice that in bmain.dart the line b.y.add(6) adds to the private list without going through the setter. How can I ensure no such access is permitted and any changes to the private list or object are controlled?
You cannot expose a mutable object and be certain that it's not changed by someone else.
That leaves your options as:
Not exposing the object at all.
Exposing a view of the object which does not allow modification.
The former is not as bad as it sounds. If you give your container class members which accesses the members of the protected object, then you don't have to expose the object itself. (It might even be a good idea, q.v. "the law of Demeter").
The latter would mean wrapping the real object in a view adapter which throws if you want to make changes. For a List, you can use an UnmodifiableListView. For other classes, you might need to write one yourself.
This solution is obviously only skin deep. Code with access to the unmodifiable list cannot change which objects are elements of the list, but if those objects are themselves mutable, then they can be changed as well.
Usually protecting the list itself is what you need.
I've implemented the stream transformer. Please note that it is only an exercise (in order to learn Dart). This transformer converts integers into strings. I give the code below, and you can also find it on GitHub.
// Conceptually, a transformer is simply a function from Stream to Stream that
// is encapsulated into a class.
//
// A transformer is made of:
// - A stream controller. The controller provides the "output" stream that will
// receive the transformed values.
// - A "bind()" method. This method is called by the "input" stream "transform"
// method (inputStream.transform(<the stream transformer>).
import 'dart:async';
/// This class defines the implementation of a class that emulates a function
/// that converts a data with a given type (S) into a data with another type (T).
abstract class TypeCaster<S, T> {
T call(S value);
}
/// This class emulates a converter from integers to strings.
class Caster extends TypeCaster<int, String> {
String call(int value) {
return "<${value.toString()}>";
}
}
// StreamTransformer<S, T> is an abstract class. The functions listed below must
// be implemented:
// - Stream<T> bind(Stream<S> stream)
// - StreamTransformer<RS, RT> cast<RS, RT>()
class CasterTransformer<S, T> implements StreamTransformer<S, T> {
StreamController<T> _controller;
bool _cancelOnError;
TypeCaster<S, T> _caster;
// Original (or input) stream.
Stream<S> _stream;
// The stream subscription returned by the call to the function "listen", of
// the original (input) stream (_stream.listen(...)).
StreamSubscription<S> _subscription;
/// Constructor that creates a unicast stream.
/// [caster] An instance of "type caster".
CasterTransformer(TypeCaster<S, T> caster, {
bool sync: false,
bool cancelOnError: true
}) {
_controller = new StreamController<T>(
onListen: _onListen,
onCancel: _onCancel,
onPause: () => _subscription.pause(),
onResume: () => _subscription.resume(),
sync: sync
);
_cancelOnError = cancelOnError;
_caster = caster;
}
/// Constructor that creates a broadcast stream.
/// [caster] An instance of "type caster".
CasterTransformer.broadcast(TypeCaster<S, T> caster, {
bool sync: false,
bool cancelOnError: true
}) {
_cancelOnError = cancelOnError;
_controller = new StreamController<T>.broadcast(
onListen: _onListen,
onCancel: _onCancel,
sync: sync
);
_caster = caster;
}
/// Handler executed whenever a listener subscribes to the controller's stream.
/// Note: when the transformer is applied to the original stream, through call
/// to the method "transform", the method "bind()" is called behind the
/// scenes. The method "bind()" returns the controller stream.
/// When a listener is applied to the controller stream, then this function
/// (that is "_onListen()") will be executed. This function will set the
/// handler ("_onData") that will be executed each time a value appears
/// in the original stream. This handler takes the incoming value, casts
/// it, and inject it to the (controller) output stream.
/// Note: this method is called only once. On the other hand, the method "_onData"
/// is called as many times as there are values to transform.
void _onListen() {
_subscription = _stream.listen(
_onData,
onError: _controller.addError,
onDone: _controller.close,
cancelOnError: _cancelOnError
);
}
/// Handler executed whenever the subscription to the controller's stream is cancelled.
void _onCancel() {
_subscription.cancel();
_subscription = null;
}
/// Handler executed whenever data comes from the original (input) stream.
/// Please note that the transformation takes place here.
/// Note: this method is called as many times as there are values to transform.
void _onData(S data) {
_controller.add(_caster(data));
}
/// This method is called once, when the stream transformer is assigned to the
/// original (input) stream. It returns the stream provided by the controller.
/// Note: here, you can see that the process transforms a value of type
/// S into a value of type T. Thus, it is necessary to provide a function
/// that performs the conversion from type S to type T.
/// Note: the returned stream may accept only one, or more than one, listener.
/// This depends on the method called to instantiate the transformer.
/// * CasterTransformer() => only one listener.
/// * CasterTransformer.broadcast() => one or more listener.
Stream<T> bind(Stream<S> stream) {
_stream = stream;
return _controller.stream;
}
// TODO: what should this method do ? Find the answer.
StreamTransformer<RS, RT> cast<RS, RT>() {
return StreamTransformer<RS, RT>((Stream<RS> stream, bool b) {
// What should we do here ?
});
}
}
main() {
// ---------------------------------------------------------------------------
// TEST: unicast controller.
// ---------------------------------------------------------------------------
// Create a controller that will be used to inject integers into the "input"
// stream.
StreamController<int> controller_unicast = new StreamController<int>();
// Get the stream "to control".
Stream<int> integer_stream_unicast = controller_unicast.stream;
// Apply a transformer on the "input" stream.
// The method "transform" calls the method "bind", which returns the stream that
// receives the transformed values.
Stream<String> string_stream_unicast = integer_stream_unicast.transform(CasterTransformer<int, String>(new Caster()));
string_stream_unicast.listen((data) {
print('String => $data');
});
// Inject integers into the "input" stream.
controller_unicast.add(1);
controller_unicast.add(2);
controller_unicast.add(3);
// ---------------------------------------------------------------------------
// TEST: broadcast controller.
// ---------------------------------------------------------------------------
StreamController<int> controller_broadcast = new StreamController<int>.broadcast();
Stream<int> integer_stream_broadcast = controller_broadcast.stream;
Stream<String> string_stream_broadcast = integer_stream_broadcast.transform(CasterTransformer<int, String>.broadcast(new Caster()));
string_stream_broadcast.listen((data) {
print('Listener 1: String => $data');
});
string_stream_broadcast.listen((data) {
print('Listener 2: String => $data');
});
controller_broadcast.add(1);
controller_broadcast.add(2);
controller_broadcast.add(3);
}
The class CasterTransformer<S, T> extends the abstract class StreamTransformer<S, T>.
Thus, it implements the method StreamTransformer<RS, RT> cast<RS, RT>().
On the documentation, it is said that :
The resulting transformer will check at run-time that all data events of the stream it transforms are actually instances of S, and it will check that all data events produced by this transformer are actually instances of RT.
See: https://api.dartlang.org/stable/2.1.0/dart-async/StreamTransformer/cast.html
First, I think that there is a typo in this documentation : it should say "...it transforms are actually instances of RS" (instead of S).
However, this seems obscure to me.
Why do we need a stream transformer to check values types ? The purpose of a transformer is to transform, isn't it ? If the purpose of a component is to check, so why don't we call it a checker ?
And, also, why would we need to check that the transformer (we implement) produces the required data ? If it doesn't, then we face a bug that should be fixed.
Can someone explain the purpose of the method Cast() ?
The cast method is there to help typing the operation.
If you have a StreamTransformer<num, int>, it transforms numbers to integers (say, by calling .toInt() on them and then adding 42, because that is obviously useful!).
If you want to use that transformer in some place that expects a StreamTransformer<int, num>, then you can't. Since num is not a sub-type of int, the transformer is not assignable to that type.
But you know, because you understand how a stream transformer actually works, that the first type argument is only used for inputs. Something that accepts any num should safely be useable where it's only given ints.
So, to convince the type system that you know what you are doing, you write:
StreamTransformer<int, num> transform = myTranformer.cast<int, num>();
Now, the tranformer takes any integer (RS), checks that it's a num (S), passes it to myTransformer which calls toInt() and adds 42, then the resulting int (T) is passed back and transformer checks that it is a num (RT) and emits that.
Everything works and the type system is happy.
You can use cast to do things that will never work at run-time, because all it does is to add extra run-time checks that convinces the static type system that things will either succeed or throw at those checks.
The easiest way to get an implementation of StreamTransformer.cast is to use th e StreamTransformer.castFrom static method:
StreamTransformer<RS, RT> cast<RS, RT>() => StreamTransformer.castFrom(this);
That will use the system's default cast wrapper on your own transformer.
How can remove all variables value from one place when I logout from the application? Like for NSUserDefaults we use below code:
/*===CLEAR ALL NSUSERDEFAULTS====*/
let appDomain = NSBundle.mainBundle().bundleIdentifier!
NSUserDefaults.standardUserDefaults().removePersistentDomainForName(appDomain)
create a class which consist of all the properties of the loggedin user(that you want to clear at the time of logout)
and best way is to create shared instance using dispatch once and than when you need to reset the properties just reset the dispatch onceToken
here is the sample code in objective C
static dispatch_once_t onceToken;
+ (id)sharedInstance
{
dispatch_once(&onceToken, ^{
instance = [[self alloc] init];
});
return instance;
}
+ (void)clearMemberInfo
{
// [[NSNotificationCenter defaultCenter] removeObserver:self];
//instance = nil;
onceToken = 0;
}
From a design point, create a class that handles all settings - e.g. I have XUPreferences in my projects and store all settings there in one place (generally a class that has various variables that delegate their values to NSUserDefaults). Aside from not having various defaults key floating around the namespace, you have a nice overview of everything the app is setting.
On this class, you can have a func clearAllPreferences() method, which may (various options):
you can try using the resetStandardUserDefaults() class method on NSUserDefaults
enumerate all the defaults keys you have and call the removeObjectForKey: method on NSUserDefaults
if you prefix your keys (e.g. I prefix all my defaults keys with XU), you can do this automatically by going through the keys in NSUserDefaults.standardUserDefaults().dictionaryRepresentation() and matching those against your prefix.
use suites - see the designated initializer - pass in extra suite name, and then you can call func removeSuiteNamed() on NSUserDefaults - which is probably the best way, since it allows you to distinguish between session-related and non-session-related settings and wipe just the session-related ones.
EDIT:
/// Key in defaults for myOption
private let XUMyOptionDefaultsKey = "XUMyOption"
public class XUPreferences {
/// Shared instance
public static var sharedPreferences = XUPreferences()
/// Your option, purely based on the values in NSUserDefaults.
public var myOption: Bool {
get {
return NSUserDefaults.standardUserDefaults().boolForKey(XUMyOptionDefaultsKey)
}
set {
NSUserDefaults.standardUserDefaults().setBool(newValue, forKey: XUMyOptionDefaultsKey)
}
}
/// Clears preferences.
public func clearPreferences1() {
let defaults = NSUserDefaults.standardUserDefaults()
for (key, _) in defaults.dictionaryRepresentation() {
// All keys are prefixed with XU
if key.hasPrefix("XU") {
defaults.removeObjectForKey(key)
}
}
}
/// Clears preferences another way
public func clearPreferences2() {
let defaults = NSUserDefaults.standardUserDefaults()
for key in [ XUMyOptionDefaultsKey /**, all keys for your options go here. */ ] {
defaults.removeObjectForKey(key)
}
}
}
// Usage:
// x is now false (most likely)
var x = XUPreferences.sharedPreferences.myOption
// Change the option to true
XUPreferences.sharedPreferences.myOption = true
XUPreferences.sharedPreferences.clearPreferences1()
// False again, since we've cleared the preferences.
x = XUPreferences.sharedPreferences.myOption
I have the following code:
public static int smsCount = 0 ;
public void startListener()
{
SendListener smsListener;
smsListener = new SendListener() {
public boolean sendMessage(Message message) {
++smsCount;
return true;
}
};
SMS.addSendListener(smsListener);
}
When I use a debugger I see that the value of smsCount is increasing. However, for some reason, it returns zero when I try to access it from outside the class. Is there anything wrong with this code ? sendMessage is called whenever an SMS is sent.
To expand on John B's comment, and to be more specific are you accessing it from a different runtime (application) context? Each runtime context has its own global (and therefore) static namespace. To ensure an object is a global singleton you should use the RuntimeStore.