Is the output of `Push.getPushKey()` always the same? - codenameone

I have to store server-side the output of Push.getPushKey().
Is it always the same? Or is it better to make a REST request to update its value in the init()?
Can its value be null?
For example, is the following code in the init() a good approach? It waits for a not null PushKey, then it sends it and stops the timer.
Timer timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
if (Push.getPushKey() != null && authToken != null) {
Rest.post(Server.getRestServerURL() + "/updatePushKey")
.jsonContent()
.header("authToken", authToken)
.body(Push.getPushKey())
.fetchAsString((Response<String> response) -> {
if (isSuccessResponse(response)) {
Log.p("PushKey successfully sent to the server", Log.INFO);
}
});
timer.cancel();
}
}
}, 1000, 1000);
Thank you for your clarifications.

Don't use a timer. You need to store this when the registeredForPush callback is invoked. Yes, it can update and it can be null if registration failed.

Related

Filter a broadcasted property in Angular 9

I have a dbService that calls the database!
//DB service code -----------------------
private changedEvents = new BehaviorSubject<IEvent[]>(null);
broadCastEvents = this.changedEvents.asObservable();
getEvents() {
this.http.get<IEvent[]>(this.configUrl + 'Event/GetEvents').subscribe(
(data: IEvent[]) => {
this.changedEvents.next(data)
});
}
In my component on ngOnInit I starts listening to this
ngOnInit(): void {
this.dbService.broadCastEvents.subscribe(data => {
this.events = data;
})
// this.dbService.getEvents();
}
Now all of this working like a charm! But now I'm only interested in records where this.events.type == 2
I tried by a standard filtering like below!
ngOnInit(): void {
this.dbService.broadCastEvents.subscribe(data => {
this.events = data.filter(event => event.eventTypeRefId == 2);
})
// this.dbService.getEvents();
}
But it results in the following Error!? Any ideas how to this in a better way (that works :-))
core.js:6241 ERROR TypeError: Cannot read property 'filter' of null
at SafeSubscriber._next (start-training.component.ts:26)
at SafeSubscriber.__tryOrUnsub (Subscriber.js:183)
at SafeSubscriber.next (Subscriber.js:122)
at Subscriber._next (Subscriber.js:72)
at Subscriber.next (Subscriber.js:49)
at BehaviorSubject._subscribe (BehaviorSubject.js:14)
at BehaviorSubject._trySubscribe (Observable.js:42)
at BehaviorSubject._trySubscribe (Subject.js:81)
at BehaviorSubject.subscribe (Observable.js:28)
at Observable._subscribe (Observable.js:76)
ngOnInit(): void {
this.dbService.broadCastEvents.pipe(filter(event => event.eventTypeRefId == 2)).subscribe(data => {
this.events = data
})
// this.dbService.getEvents();
}
Reference:
https://rxjs-dev.firebaseapp.com/guide/operators
There are multiple ways for it. One way is to use array filter like you did. Other way would be to use RxJS filter pipe as shown by #enno.void. However both these methods might still throw an error when the notification is null. And since the default value of your BehaviorSubject is null, there is high probability of hitting the error again.
One workaround for it is to use ReplaySubject with buffer 1 instead. It's similar to BehaviorSubject in that it holds/buffer the last emitted value and emits it immediately upon subscription, except without the need for a default value. So the need for initial null value is mitigated.
Try the following
private changedEvents = new ReplaySubject<IEvent[]>(1);
broadCastEvents = this.changedEvents.asObservable();
...
Now the error might still occur if you were to push null or undefined to the observable. So in the filter condition you could check for the truthiness of the value as well.
ngOnInit(): void {
this.dbService.broadCastEvents.subscribe(data => {
this.events = data.filter(event => {
if (event) {
return event.eventTypeRefId == 2;
}
return false;
});
});
}

How to stop the timer in flutter?

I have created a timer in flutter and everything works fine. Now I can't figure out how to dismiss the timer after I started it.
The docs say that you can cancel it by calling void cancel() but I don't understand the implementation.
How am I supposed to call it?
And is it the right approach?
static const timeout = const Duration(seconds: 5);
static const ms = const Duration(milliseconds: 1);
startTimeout([int milliseconds]) {
var duration = milliseconds == null ? timeout : ms * milliseconds;
return new Timer(duration, handleTimeout);
}
void handleTimeout() { // callback function
Navigator.of(context).pushAndRemoveUntil(new MaterialPageRoute(
builder: (BuildContext context) => new ScorePage(quiz.score, quiz.length)),(Route route) => route == null);
return;
}
Just keep a reference to the time and cancel it when you don't need it anymore
var timer = startTimeout(100);
...
timer.cancel();

How to execute promises "sync" and not in async way

I calling getBubblesUserAccess that returns json objects that are orderd in a special way. This results i wanna run a foreach and get other messages but there i wanna return them in "order". I know that it will run these async but there must be a way that i can force it to "sequential" execution. (above code is my last attempt to add a defer...)
Example
pseudo code - get my groups
{
"id":"016cd1fc-89a3-4e4a-9e6e-a102df1b03d9",
"parent":"53750396-7d26-41f3-913d-1b93276b9e09",
"name":"XX",
"createdBy":"c9c63080-2c5b-4e8e-a093-2cfcd628a9d0",
"hasWriteAccess":true,
"hasCreateAccess":false,
"hasDeleteAccess":false,
"hasAdminAccess":false,
"settingsBubbleId":"00000000-0000-0000-0000-000000000000"
},
{
"id":"016cd1fc-89a3-4e4a-9e6e-a102df1b03d9",
"parent":"53750396-7d26-41f3-913d-1b93276b9e09",
"name":"XX",
"createdBy":"c9c63080-2c5b-4e8e-a093-2cfcd628a9d0",
"hasWriteAccess":true,
"hasCreateAccess":false,
"hasDeleteAccess":false,
"hasAdminAccess":false,
"settingsBubbleId":"00000000-0000-0000-0000-000000000000"
}
From this result i wanna iterate over those parent id strings and call another service that respond with this.
pseudo code
for each group above call another service with parent id and get result. This result will be added to a new JSON object.
"messages":[
{
"id":"f1d1aeda-d4e2-4563-85d5-d954c335b31c",
"text":"asd",
"sent":"2015-09-10T22:31:09.897+00:00",
"sender":"6b9e404b-ef37-4d07-9267-3e7b2579003b",
"senderName":"XXX XXXX"
},
{
"id":"a7ac0432-e945-440e-91ce-185170cbf3de",
"text":"asd",
"sent":"2015-09-10T22:28:24.383+00:00",
"sender":"c9c63080-2c5b-4e8e-a093-2cfcd628a9d0",
"senderName":"ZZZZZ ZZZZ"
},
My problem is that my second foreach are running async (as it should) and i want it to resolve back in same order as first json object...
My code::
var loadBubblesAccess = function () {
if (vm.running && angular.isDefined(vm.running)) { return; }
vm.running = true;
vm.bubblesWithMessages = null;
return BubbleFactory.getBubblesUserAccess().then(function (bubblesAccessTo) {
return bubblesAccessTo;
});
},
loadSubBubbles = function (bubblesAccessTo) {
/**
* Result from chain method with all bubbles user has access to.
*/
var promiseArray = [];
//var promiseArrayError = [];
var i = 0;
/**
* Creates a defer object so that we will not resolve before for each loop has been gone thru.. async problems.
*/
var deferred = $q.defer();
angular.forEach(bubblesAccessTo, function (bubble) {
$log.error(JSON.stringify(bubblesAccessTo));
/**
* Get 20 because default thats default and cache and e-tags are done to that number..
*/
BubbleFactory.getBubbleMessages(bubble.id, 0, 20, false).then(function (data) {
i++;
if (data.messages.length > 0) {
promiseArray.push({ bubbleSortOrder: i, bubbleId: bubble.parent, bubbleName: bubble.name, bubbleMessagesId: bubble.id, bubbleMessages: smartTrim(data.messages[0].text, 400, ' ', ' ...'), bubbleMessagesSent: data.messages[0].sent });
}
else {
// console.log("YYYY::: " + bubble.parent);
promiseArray.push({ bubbleSortOrder:i, bubbleId: bubble.parent, bubbleName: bubble.name, bubbleMessagesId: bubble.id, bubbleMessages: 'Inget meddelande än..', bubbleMessagesSent: '' });
}
});
/**
* Check if we have gone thru all bubbles - when finished we resolve defer object.
*/
if(i===bubblesAccessTo.length)
{
deferred.resolve(promiseArray);
}
});
//$log.debug.log(promiseArray);
vm.bubblesWithMessages = promiseArray;
promiseArray.length = 0;
vm.running = false;
};
loadBubblesAccess().then(loadSubBubbles);
The $q service in AngularJS is described as "lightweight" because it only implements the functions 90% of people need. That keeps its code size small - at the expense of not being able to address requests like yours very easily.
If you have the option, try an alternative such as bluebird. Bluebird provides a reduce() function that can execute an array of promises serially, and return their results in the order they were requested. It makes this task straightforward because your result array will match your data array and you can match up the results very easily.
If you do NOT have that option, there is a standard (if not-exactly-simple) technique with promises where you build an array of the elements you want to promise, then call the processing function (that returns a Promise) on the first value (popped from the array). In the .finally() handler, call the processing function recursively with the next value until it is empty (or an error occurs).
Pseudo-code for this:
var valuesToProcess = [1, 2, 3],
results = [];
function processValue(val) {
myProcessingFunction(val).then(function(result) {
results.push(result);
}).catch(function(e) {
console.log('FAIL!', e);
}).finally(function() {
if (valuesToProcess.length > 0) {
processValue(valuesToProcess.shift());
} else {
// All done - do something with results here
}
});
}
// Note: No error checking done, assumes we have work to do...
processValue(valuesToProcess.shift());
You'll need to adapt this to your use-case but it's a simple technique that guarantees serial operation and result-handling.

Promises in loop

I have the following problem in Angular JS. I have this loop:
angular.forEach(objects, function(object)
{
UpdateFactory.updateObjectInDatabase(version, object).then(function(newVersion)
{
version = newVersion;
alert("Update successful! Version number increased.);
});
});
But my problem is:
I want only to call the Factory method, if previous call is finished. Otherwise I get status code 409, because of the wrong version.
I would be pleased if someone could help me!
Best regards.
You can solve this with a recursive function that calls itself when previous request is done:
function update(objects, current) {
UpdateFactory.updateObjectInDatabase(version, objects[current]).then(function (newVersion) {
version = newVersion;
if (objects[++current]) {
update(objects, current);
}
});
}
// Start with first object
update(objects, 0);
Note: this assumes objects is an array of objects
Try this
var keys = Object.keys(objects)
var i = 0;
update(function() {
console.log("should be called when the operation end");
})
function update(cb) {
cb = (angular.isFunction(cb) ? cb : angular.noop);
if(i <= keys.length-1 ) {
i++; //increment the counter
UpdateFactory.updateObjectInDatabase(version, objects[keys[i]])
.then(function(newVersion) {
version = newVersion;
alert("Update successful! Version number increased.");
update(cb)
}, function(){
console.log("a promise return a reject");
cb();
});
} else {
cb() //Finish the operation
}
}
Only get the keys of the object and call the function when the promise ends, make a recursive call and stop when the keys ends

Retrieve only one item with MVVM light in Silverlight

To grab some content from a WCF Data Service into my View Model is straight forward:
public const string RequestsPropertyName = "Requests";
private DataServiceCollection<Request> _requests = null;
public DataServiceCollection<Request> Requests
{
get { return _requests; }
set
{
if (_requests == value) { return; }
var oldValue = _requests;
_requests = value;
RaisePropertyChanged(RequestsPropertyName, oldValue, value, true);
}
}
and then
Requests.LoadAsync(query);
But what if I have a property which is not a collection?
public const string RequestDetailsPropertyName = "RequestDetails";
private Request _requestDetails = null;
public Request RequestDetails
{
get { return _requestDetails; }
and so on.
Where do I get the 'LoadAsync(query)' method from?
Thank you,
Ueli
This is a pretty simple thing to do. You just need to use the DomainContext in your application. This is where you create your query from, then apply the result to your property.
Here is an example of what this might look like in your code:
void LoadRequest(int requstID)
{
var query = workContext.GetRequestByIDQuery(requestID);
workContext.Load(query, lo =>
{
DispatcherHelper.CheckBeginInvokeOnUI(() =>
{
if (lo.HasError)
throw lo.Error;
else
RequestDetails = lo.Entities.Single();
});
}, null);
}
In this example, the workContext object is the DomainContext. The query is an specific version on the server - you can also just contruct the query client side with:
.Where(r => r.RequestID == requestID)
After the async call, it thows any errors that occurred from the async call, and then returns the only entity returned. If you get more than 1 entity, you might use .First() instead.
If this is not enough to get you going, let me know and I can explain further.

Resources