I want to get a current user location to update nearby stores based on latitude/longitude inside the url.
but I can't figure out how to interact data between two different class.
I want to make it work something like 'AppConfig.latitude = _position.latitude;'. I tried with several methods including inherited widget that I found on stackoverflow and youtube, but still don't work. It's definitely that I'm missing something.
when I use a bloc, I have no clue how to update data inside 'class AppConfig' with bloc. Can it be done simply using SetState? I spent the whole day yesterday Googling for this problem. please guide me to right approach
class _CurrentLocationState extends State<CurrentLocation> {
Position _position;
Future<void> _initPlatformState() async {
Position position;
try {
final Geolocator geolocator = Geolocator()
...
setState(() {
_position = position;
// print(${_position.latitude})
// 35.9341...
// print(${_position.longitude})
// -117.0912...
<*I want to make it work something like this*>
AppConfig.latitude = _position.latitude;
AppConfig.longitude = _position.longitude;
<*this is how I tried with bloc*>
latLongBloc.getUserLocation(LatLng(position.latitude, position.longitude));
});
<* latitude/longitude need to be updated with a current user location *>
abstract class AppConfig {
static const double latitude = 0;
static const double longitude = 0;
static const List<String> storeName = ['starbucks'];
}
<* I need to use AppConfig.latitude for url in Repository class*>
class Repository {
...
Future<List<Business>> getBusinesses() async {
String webAddress =
"https://api.yelp.com/v3/businesses/search?latitude=${AppConfig.latitude}&longitude=${AppConfig.longitude}&term=${AppConfig.storeName}";
...
}
this is my bloc.dart file
class LatLongBloc {
StreamController _getUserLocationStreamController = StreamController<LatLng>();
Stream get getUserLocationStream => _getUserLocationStreamController.stream;
dispose(){
_getUserLocationStreamController.close();
}
getUserLocation(LatLng userLatLong) {
_getUserLocationStreamController.sink.add(userLatLong);
}
}
final latLongBloc = LatLongBloc();
You want to share state between classes/widgets, right? There are also other state management patterns like ScopedModel or Redux. Each pattern has its pros and cons, but you don't have to use BLoC if you don't understand it.
I would recommend to use ScopedModel because it's quite easy to understand in my opinion. Your data/state is in a central place and can be accessed by using ScopedModel. If you don't like to use this approach then try Redux or other patterns :)
Hope it helped you :D
Yours Glup3
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()...)
Is there a way that we could save a map object into shared preferences so that we can fetch the data from shared preferences rather than listening to the database all the time.
actually i want to reduce the amount of data downloaded from firebase. so i am thinking of a solution to have a listener for shared prefs and read the data from shared prefs.
But i dont see a way of achieving this in flutter or dart.
Please can someone help me to achieve this if there is a workaround.
Many Thanks,
Mahi
If you convert it to a string, you can store it
import 'dart:convert';
...
var s = json.encode(myMap);
// or var s = jsonEncode(myMap);
json.decode(...)/jsonDecode(...) makes a map from a string when you load it.
Might be easier with this package:
https://pub.dartlang.org/packages/pref_dessert
Look at the example:
import 'package:pref_dessert/pref_dessert.dart';
/// Person class that you want to serialize:
class Person {
String name;
int age;
Person(this.name, this.age);
}
/// PersonDesSer which extends DesSer<T> and implements two methods which serialize this objects using CSV format:
class PersonDesSer extends DesSer<Person>{
#override
Person deserialize(String s) {
var split = s.split(",");
return new Person(split[0], int.parse(split[1]));
}
#override
String serialize(Person t) {
return "${t.name},${t.age}";
}
}
void main() {
var repo = new FuturePreferencesRepository<Person>(new PersonDesSer());
repo.save(new Person("Foo", 42));
repo.save(new Person("Bar", 1));
var list = repo.findAll();
}
Package is still under development so it might change, but any improvements and ideas are welcomed! :)
In dart's Shared Preferences there is no way to store Map directly but you can easily trick this by, converting Map to String then save it as usual, and when you need it to retrieve the String and then convert it back to Map. So simple!
Convert your map into String using json.encode() and then save it,
When you need your map use json.decode() to get back your map from the string.
import 'dart:convert';
import 'package:shared_preferences/shared_preferences.dart';
final yourStr = sharedPreferences.getString("yourkey");
var map = json.decode(yourStr);
sharedPreferences.setString("yourkey", json.encode("value"));
For those who don't like to convert String to JSON or vice versa, personally recommend localstorage, this is the easiest way I had ever found to store any data<T> in Flutter.
import 'package:localstorage/localstorage.dart';
final LocalStorage store = new LocalStorage('myapp');
...
setLocalStorage() async {
await store.ready; // Make sure store is ready
store.setItem('myMap', myMapData);
}
...
Hope this helps!
I like the await for construct in Dart.
How can I implement something similar with a regular for loop?
Something like
// beware! fictional code.
var element = stream.next();
for(; stream.isEndReached(); element = stream.next()) {
// use element here
}
// or probably it will be like this, right?
var element = await stream.next();
for(; await stream.isEndReached(); element = await stream.next()) {
// use element here
}
But I can't figure out what functions to use instead of next() and isEndReached() here. If you could give me a full example that acts exactly like async for, that would be great.
Edit: Here is the actual reason that I asked for this: I want to do something like this:
if (!stream.isEndReached()) {
var a = await stream.next();
// use a
}
if (!stream.isEndReached()) {
var b = await stream.next();
// use b
}
// have an arbitrary number of these
I need to consume items one by one like this. This is why I'm asking what my made up .next() and .isEndReached() methods map to which actual methods in the stream class.
The async package contains a StreamQueue class that might do what you want.
See also this great article http://news.dartlang.org/2016/04/unboxing-packages-async-part-3.html
StreamQueue provides a pull-based API for streams.
A code snipped from the article mentioned above
void main() async {
var queue = new StreamQueue(new Stream.fromIterable([1, 2, 3]));
var first = queue.next;
var second = queue.next;
var third = queue.next;
print(await Future.wait([first, second, third])); // => [1, 2, 3]
}
update
WebStorm (uses a feature of the dartanalyzer) doesn't provide quick fixes for imports when nothing was yet imported from that package. It doesn't read packages if they are not refered to in your source code. As mentioned in my answer StreamQueue is from the async package. import 'package:async/async.dart'; is usually enough (it's a convention to name the main entrypoint file (async.dart) of a package the same as the package) and all exported identifiers become available in your library. Otherwise you can search the source of your project and WebStorm will also search dependencies and show what library contains the StreamQueue class. Then you can import this file.
I am surprised that dart does not have a built in object-to-json and json-to-object mapper.
I read that we have to hand code the mapping ourselves, which is not pleasant.
Anyways, although I have not thoroughly tested it for my use case, I found dart-exportable to be very helpful for half of my requirement.
Any suggested package for json to object decoding?
Your best option is to use the Smoke library.
It's a subset of the Mirrors functionality but has both a Mirrors-based and a Codegen-based implementation. It's written by the PolymerDart team, so it's as close to "Official" as we're going to get.
While developing, it'll use the Mirrors-based encoding/decoding; but for publishing you can create a small transformer that will generate code.
Seth Ladd created a code sample here, which I extended slightly to support child-objects:
abstract class Serializable {
static fromJson(Type t, Map json) {
var typeMirror = reflectType(t);
T obj = typeMirror.newInstance(new Symbol(""), const[]).reflectee;
json.forEach((k, v) {
if (v is Map) {
var d = smoke.getDeclaration(t, smoke.nameToSymbol(k));
smoke.write(obj, smoke.nameToSymbol(k), Serializable.fromJson(d.type, v));
} else {
smoke.write(obj, smoke.nameToSymbol(k), v);
}
});
return obj;
}
Map toJson() {
var options = new smoke.QueryOptions(includeProperties: false);
var res = smoke.query(runtimeType, options);
var map = {};
res.forEach((r) => map[smoke.symbolToName(r.name)] = smoke.read(this, r.name));
return map;
}
}
Currently, there is no support to get generic type information (eg. to support List) in Smoke; however I've raised a case about this here:
https://code.google.com/p/dart/issues/detail?id=20584
Until this issue is implemented, a "good" implementation of what you want is not really feasible; but I'm hopeful it'll be implemented soon; because doing something as basic as JSON serialisation kinda hinges on it!
I haven't had the time to complete it yet but dartson is currently working using mirrors. However a better solution would be using a transformer when compiling to JavaScript. https://pub.dartlang.org/packages/dartson
Have been seeing the term "Expando" used recently with Dart. Sounds interesting. The API did not provide much of a clue to me.
An example or two could be most helpful!
(Not sure if this is related, but I am most anxious for a way to add methods (getters) and/or variables to a class. Hoping this might be a key to solving this problem. (hint: I am using the Nosuchmethod method now and want to be able to return the value of the unfound method.))
Thanks in advance,
_swarmii
Just to clarify the difference between expando and maps: as reported in the groups, expando has weak references.
This means that a key can be garbage collected even if it's still present in the expando (as long as there are no other references to it).
For all other intents and purposes it's a map.
Expandos allow you to associate objects to other objects. One very useful example of this is an HTML DOM element, which cannot itself be sub-classed. Let's make a top-level expando to add some functionality to an element - in this case a Function signature given in the typedef statement:
typedef CustomFunction(int foo, String bar);
Expando<CustomFunction> domFunctionExpando = new Expando<CustomFunction>();
Now to use it:
main(){
// Assumes dart:html is imported
final myElement = new DivElement();
// Use the expando on our DOM element.
domFunctionExpando[myElement] = someFunc;
// Now that we've "attached" the function to our object,
// we can call it like so:
domFunctionExpando[myElement](42, 'expandos are cool');
}
void someFunc(int foo, String bar){
print('Hello. $foo $bar');
}
I played with it a little bit. Here's what I've got.
import 'dart:html';
const String cHidden = 'hidden';
class ExpandoElement {
static final Expando<ExpandoElement> expando =
new Expando<ExpandoElement>("ExpandoElement.expando");
final Element element;
const ExpandoElement._expand(this.element);
static Element expand(Element element) {
if (expando[element] == null)
expando[element] = new ExpandoElement._expand(element);
return element;
}
// bool get hidden => element.hidden; // commented out to test noSuchMethod()
void set hidden(bool hidden) {
if (element.hidden = hidden)
element.classes.add(cHidden);
else
element.classes.remove(cHidden);
}
noSuchMethod(InvocationMirror invocation) => invocation.invokeOn(element);
}
final Expando<ExpandoElement> x = ExpandoElement.expando;
Element xquery(String selector) => ExpandoElement.expand(query(selector));
final Element input = xquery('#input');
void main() {
input.classes.remove(cHidden);
assert(!input.classes.contains(cHidden));
input.hidden = true;
assert(x[input].hidden); // Dart Editor warning here, but it's still true
assert(!input.classes.contains(cHidden)); // no effect
input.hidden = false;
assert(!x[input].hidden); // same warning, but we'll get input.hidden via noSuchMethod()
assert(!input.classes.contains(cHidden));
x[input].hidden = true;
assert(input.hidden); // set by the setter of ExpandoElement.hidden
assert(input.classes.contains(cHidden)); // added by the setter
assert(x[input].hidden);
assert(x[input].classes.contains(cHidden)); // this is input.classes
x[input].hidden = false;
assert(!input.hidden); // set by the setter
assert(!input.classes.contains(cHidden)); // removed by the setter
assert(!x[input].hidden);
assert(!x[input].classes.contains(cHidden));
// confused?
assert(input is Element);
assert(x[input] is! Element); // is not
assert(x[input] is ExpandoElement);
assert(x is Expando<ExpandoElement>);
}