How can I prevent twice call of observe() method in onViewCreated()? - android-fragments

I have Fragment where in onViewCreated() requesting data ,
So every time if I return to that fragment it checks if the mutableLiveData is empty or not and if it is empty it requests from server and I am observing that data in onViewCreated()
But if I navigate to another tab and then return to the same fragment observe() calls twice
I don’t want to move requesting method in onCreate() as if the request fails and if I navigate to another tab and return to that again I want to rerequest the data from server.
My question is how can I prevent call of observe() twice ?
I added removeObservers() in onDestroyView() but it doesn’t help

Android recently introduced the viewLifecycleOwner in fragments. By using it your observe method, this will prevent it from being called twice. Do not use activity or fragment object, use the fragments viewLifecycleOwner object instead.
No need to removeObservers().
example code:
viewmodel.livedata.observe(viewLifecycleOwner, Observer {
// your code here
})

Related

Is there a way to cancel or override a jsonrpc call?

I'm using Polkadot.js in my project, and I have a function where user click to filter assets by categories. The issue is if the user click very fast, two rpc calls will be dispatched, instead of the later call overriding the first call, this will result in getting duplicate results.
Is there any way I can either cancel the first inflight rpc call, or let the second call overrides the first one? They share the same method name and the later one will have a higher id.
Any suggestions or help is much appreciated!

Why does Firebase observeEventType return a snapshot everytime in viewWillAppear?

I have a query that is observed on viewWillAppear on View Controller A
let query = FIRDatabase.database().reference().child("tags").
queryOrdered(byChild: "users/uid").queryEqual(toValue: userId)
In the same view controller, in viewDidDisappear I remove this observer.
So let's say I push into another view controller from View Controller A.
When I come back to View Controller A, the observer returns a snapshot, even though my data on the backend hasn't changed.
I only want a snapshot returning if there's been some actual change to my database. How do I solve this problem? Thanks.
One answer is to simply let the observer do it's job and update your data in the background.
So if the user is on controllerA the observer updates a datasource (an array) so then the UI is updated from that array.
When the user switches to controllerB, the observer can still update the array, but don't update the UI in controllerA since there's no need to.
When the user switches back to A you'll have current data available so just reload the tableView (assuming iOS here) from the array.
This solution reduces the 'polling' nature and let's Firebase do the heavy lifting to notify your app when it needs to. You're just reloading the tableViews from an array when that controller becomes active.
Edit
The idea here is to add the observer once - perhaps when the view loads the first time only (viewDidLoad) or maybe in your app delegate. Once you add the observer it will update your dataSource arrays when data changes so when you move from view to view the only action needed will be to reload the tableView from the updated array.
There are times when you may want to remove an observer but it doesn't sound like you need to do that from your question. So - attach the observers once and let them update the dataSource arrays as the data changes. Reload your tableViews when switching views.
You have put the query in viewWillAppear, which means every time you come to viewController A, this query will be executed irrespective of you have removed the observer or not.
Try putting the same query in viewDidLoad which means, the query will be called once and don't remove the observer anywhere. Now the query would be called only when data gets changed in firebase.

Meteor - how can I empty out the collection of 10,000 objects I subscribed to after I no longer need it?

I have a template in which a user should be able to click on a button to bring up a modal and in the modal choose a handful of items out of a list of about 10,000 items which are displayed there to search or scroll through.
Since this collection is so big, I don't want to keep it around in memory when I don't absolutely need it.
So I would like to subscribe to this collection only when the modal is being viewed and I would like to ensure that I am unsubscribed if the modal is not being viewed.
Is there a way to explicitly unsubscribe from a collection?
There are a couple of ways you can do this:
Use the subscription handle
subscribe returns a handle you can call stop on. For example:
var handle = Meteor.subscribe('stuff');
handle.stop();
Use an autorun
Because an autorun will automatically start and stop subscriptions when its reactive dependencies change, this will work:
Tracker.autorun(function () {
if (Session.get('showingModal'))
Meteor.subscribe('stuff');
});
Side note - it may make more sense to use a method call for searching such a large data set rather than publishing the entire thing to the client. For example you can set a session variable whenever the user's query changes, then use an autorun to update the result set based on the method's return value.
https://docs.meteor.com/#/full/meteor_subscribe
Quoting the docs :
Meteor.subscribe returns a subscription handle, which is an object
with the following methods:
stop() Cancel the subscription. This will typically result in the
server directing the client to remove the subscription's data from the
client's cache.
So basically what you need to do is storing the subscription handle in a variable and call the stop method when you don't need those published documents anymore.
Note that if you're using iron:router (and you probably should), this is taken care of automatically for you on each route change, which is convenient but has the side effect of provoking a lot of sometimes unnecessary calls to Meteor.publish calls which are non trivial for the server and bandwidth... to address this matter you can use meteorhacks:subs-manager but it's another topic anyway.

In Meteor, how do I show newly inserted data as greyed out until it's been confirmed by the server?

Say my application has a list of items of some kind, and users can insert new items in the list.
What Meteor normally does is: when a user inserts an item in the list, it appears in their browser immediately, without waiting for server confirmation.
What I want is: when an item is in this state (submitted but not yet acknowledged by the server), it appears at its correct position in the list, but greyed out.
Is there a way to make Meteor do this?
Sure. Make a method that does the insertion. When the method runs, have it check to see if it is running in simulation, and if so, set a 'temporary' or 'unconfirmed' flag on the inserted item. Use that to decide whether to render the item as greyed out.
Assuming you're using MongoDB:
// Put this in a file that will be loaded on both the client and server
Meteor.methods({
add_item: function (name) {
Items.insert({name: name,
confirmed: !this.isSimulation});
}
});
Calling the method:
Meteor.call("add_item", "my item name");
That's all you need to do. The reason this works is that once the server has finished saving the item, the local (simulated) changes on the client will be backed out and replaced with whatever actually happened on the server (which won't include the 'unconfirmed' flag.)
The above is the simplest way to do it, but it will result in all of the
records in your database having a 'confirmed' attrbiute of true. To avoid this, only set the confirmed attribute if it's false.
Refer to this part of documentation for more information about isSimulation and Meteor.methods
This is what I did added an observer on the server side,
I created a variable called notify false from the client side itself
once the server receives the udpate it will make notify true and the client will be updated on the same.
Collection.find({"notify":false}).observe({
"added" : function(first){
collection.update({"_id":first._id},{$set : {"notify":true}});
}
});

Flex's FileReference.save() can only be called in a user event handler -- how can I get around this?

I need to call FileReference.save() after a web service call has completed, but this method has a restriction: "In Flash Player, you can only call this method successfully in response to a user event (for example, in an event handler for a mouse click or keypress event). Otherwise, calling this method results in Flash Player throwing an Error exception." (from the documentation here)
This restriction is a bit vague. Does it mean that I can only call the FileReference.save() method from within an event handler function that is registered as a listener for certain types of user events? If so then exactly which user events are valid? (Perhaps there's an event that will never be dispatched by user interaction with my application and I could register an event handler function for that event type and make the save() call from within that function?)
My difficulty is that I can't safely call the FileReference.save() method until my web service returns with the data that will be used as the argument of the FileReference.save() method call, so the event that triggers the FileReference.save() call is actually a ResultEvent rather than a user event, and I'm leery of dispatching a new (faux) user event type in order to be able to trigger the FileReference.save() call unless it's definitely a user event that would never be dispatched as a result of actual user interaction with my application.
In a nutshell what I'm doing now is this: I have a function that is registered as a handler for a button click. In this function I make my web service call to fetch data from the server. I also have a result handler function which gets invoked when the web service call completes, and it's in here that I want to call the FileReference.save() method since it's at this point that I know that the data is ready to be saved to a file. But the aforementioned restriction is blocking me from doing this -- I get an error:
Error #2176: Certain actions, such as those that display a pop-up window,
may only be invoked upon user interaction, for example by a mouse click
or button press.
I've tried many things to get around this such as creating a second mouse click event handler function with the FileReference.save() call within and calling it after a timeout interval (to give the web service time to complete), but I keep running into the same error -- maybe that approach doesn't work since the second function isn't registered as an event listener for the event type used as its argument.
I'm new to Flex development so perhaps I'm just not thinking about this in the right way. If anyone can suggest another approach I'd really appreciate it. Thanks in advance for your comments or suggestions.
--James
Adobe does this as a sort of security measure to ensure users are the ones messing with files rather than potentially harmful code. My understanding is that they enforce this by only allowing handlers of (click?) events that originate from UI components to execute the FileReference methods, so generating your own events programmatically will not work, although I have not tried to verify this. Unfortunately the best resolution I've found is to re-work the UI a bit to conform to this constraint. In your particular situation, you could make this a two click process with a button that says something like "Prepare Download", which changes to "Download File" after the web service is complete. This is less than ideal from a user perspective, but I don't think there's much else that can be done unless you can somehow complete your web service call prior to displaying the button that triggers the FileReference.save() call.
After struggling for that for well, a couple hours I found a workaround: you can use both mouseDown AND mouseUp events instead of just click.
For instance:
s:Button
mouseDown="prepare_PDF()"
mouseUp="save_PDF()"
Works fine for me!
Happy coding!
--Thomas
As a workaround I used the ExternalInterface class. I created a javascript function with this code
function downloadFile (url) {
window.open(url);
}
An in AS3 I call
var url = 'www.example.com/downloadfile.php?file_id=xxx';
ExternalInterface.call('downloadAttachmentFile', url);
So with that I transfer the file handling to JS/HTML.
This is a comment on Thomas' answer (I don't have enough XP to comment yet): The mousedown and mouseup workaround works nicely. Just a note that if you make any changes in prepare_PDF() that need 'undoing' in save_PDF(), then its a good idea to call that code on the mouseout event as well, since there might be a case that the user mousedown's on the button, but then moves the mouse away from the button.
This was particularly relevant for my case, in which we increase the size of a watermark on an image when the user clicks the download button (that triggers the .save() call). I reduce the size of the watermark down to normal on the mousedown and mouseout events.
I had this same issue, I chose to use flash.net methods. Call flash.net.navigateToURL(url); from an actionscript or navigateToURL(url); from mxml.
What i do to solve this is to show an alert message with an anonymous function so i don't have to create a button.
Alert.show("Do you wish to download the file?", "Confirm", Alert.OK | Alert.CANCEL, this, function (eventObj:CloseEvent):void {
if (eventObj.detail == Alert.OK) {
fileReference.save(zipOut.byteArray, dateFormater_titulo.format(new Date ()) + ".zip");
}//if
}/*function*/, null, Alert.OK);

Resources