I've seen a lot of questions here related to the OnNavigatedTo method, but none of them seem to answer the basic question of, "At what point should I load data?" The documentation on MSDN doesn't explicitly answer this question, as far as I can tell.
If I need to load a list of data from the local database, which method is the most appropriate to use? Should I use the OnNavigatedTo method, or the Loaded event?
What I've been using so far is this pattern, which seems to work well:
protected override void OnNavigatedTo(NavigationEventArgs e) {
base.OnNavigatedTo(e);
if (NavigationMode.New == e.NavigationMode) {
var data = LoadData();
this.DataContext = data;
}
}
What this means is that for a new instance of a page, load the data synchronously. This also means that the page will not be rendered until the data has finished loading and the profiler complains that I'm using too much UI thread time.
An alternate approach is this pattern:
protected override async void OnNavigatedTo(NavigationEventArgs e) {
base.OnNavigatedTo(e);
if (NavigationMode.New == e.NavigationMode) {
var data = await LoadData();
this.DataContext = data;
}
}
But with this pattern, it seems to me that navigation, and therefore page rendering may occur before I've loaded the data and set the DataContext, meaning unnecessary re-paints and what-not.
I usualy bind to a ViewModel directly in XAML. Then in OnNavigatedTo I trigger the view model to fetch its data async.
This allows me to show basic values from start (page title etc.). Then when I start fetching the data I can also activate a progressbar directly in the ViewModel and then remove it once the data is fetched.
I recommend you load your data asynchronously. OnNavigatedTo is one place where you can start the loading. If you're talking about a page that the user is almost certainly going to navigate to, then you may be able to start loading earlier.
I have a series of blog posts that look at how async has some friction with traditional OOP. There are a couple of posts that look at data binding in particular, e.g., asynchronous construction (the section on asynchronous initialization) and asynchronous properties (the section on data binding).
Just a few hours ago I announced the first stable release for my AsyncEx library, which includes the NotifyTaskCompletion types that you can use to kick off an asynchronous loading operation and have your view respond automatically (via data binding) when it completes.
But back to the core problem: you do have to show something while the data is loading. I recommend you do not consider this "unnecessary", but rather accept it as an opportunity to provide a better user experience. Think about what you want your app to look like on a slower phone or if there is an error loading the data. Any time there's I/O, design the "Loading..." and "Error" states as well as the "Loaded" state.
Related
I want to create a controller based JavaFX GUI consisting of multiple controllers.
The task I can't accomplish is to pass parameters from one Scene to another AND back.
Or in other words:
The MainController loads SubController's fxml, passes an object to SubController, switches the scene. There shall not be two open windows.
After it's work is done, the SubController shall then switch the scene back to the MainController and pass some object back.
This is where I fail.
This question is very similar to this one but still unanswered. Passing Parameters JavaFX FXML
It was also mentioned in the comments:
"This work when you pass parameter from first controller to second but how to pass parameter from second to first controller,i mean after first.fxml was loaded.
– Xlint Xms Sep 18 '17 at 23:15"
I used the first approach in the top answer of that thread.
Does anyone have a clue how to achieve this without external libs?
There are numerous ways to do this.
Here is one solution, which passes a Consumer to another controller. The other controller can invoke the consumer to accept the result once it has completed its work. The sample is based on the example code from an answer to the question that you linked.
public Stage showCustomerDialog(Customer customer) {
FXMLLoader loader = new FXMLLoader(
getClass().getResource(
"customerDialog.fxml"
)
);
Stage stage = new Stage(StageStyle.DECORATED);
stage.setScene(
new Scene(
(Pane) loader.load()
)
);
Consumer<CustomerInteractionResult> onComplete = result -> {
// update main screen based upon result.
};
CustomerDialogController controller =
loader.<CustomerDialogController>getController();
controller.initData(customer, onComplete);
stage.show();
return stage;
}
...
class CustomerDialogController() {
#FXML private Label customerName;
private Consumer<CustomerInteractionResult> onComplete
void initialize() {}
void initData(Customer customer, Consumer<CustomerInteractionResult> onComplete) {
customerName.setText(customer.getName());
this.onComplete = onComplete;
}
#FXML
void onSomeInteractionLikeCloseDialog(ActionEvent event) {
onComplete.accept(new CustomerInteractionResult(someDataGatheredByDialog));
}
}
Another way to do this is to add a result property to the controller of the dialog screen and interested invokers could listen to or retrieve the result property. A result property is how the in-built JavaFX dialogs work, so you would be essentially imitating some of that functionality.
If you have a lot of this passing back and forth stuff going on, a shared dependency injection model based on something like Gluon Ignite, might assist you.
I've used AfterBurner.fx for dependency injection, which is very slick and powerful as long as you follow the conventions. It's not necessarily an external lib if you just copy the 3 classes into your structure. Although you do need the javax Inject jar, so I guess it is an eternal reference.
Alternately, if you have a central "screen" from which most of your application branches out you could use property binding probably within a singleton pattern. There are some good articles on using singleton in JavaFX, like this one. I did that for a small application that works really great, but defining all of those bindings can get out of hand if there are a lot of properties.
To pass data back, the best approach is probably to fire custom Events, which the parent controller subscribes to with Node::addEventHandler. See How to emit and handle custom events? for context.
In complex cases when the two controllers have no reference to each other, a Event Bus as #jewelsea mentioned is the superior option.
For overall architecture, this Reddit comment provides some good detail: https://www.reddit.com/r/java/comments/7c4vhv/are_there_any_canonical_javafx_design_patterns/dpnsedh/
In mvvmcross v3 ViewModel
public class TimerViewModel : MvxViewModel
{
System.Timers.Timer timer;
public TimerViewModel()
{
timer = new System.Timers.Timer(500f);
timer.Elapsed += HandleTimerElapsed;
timer.Start();
}
void HandleTimerElapsed (object sender, ElapsedEventArgs e)
{
Debug.Log( "Time Elapsed" );
}
}
As MvxViewModel doesn't implement IDisposable, where should I put the following code ?
timer.Stop();
timer.Elapsed += HandleTimerElapsed;
I find that mvvmcross code have some MvxWeakEventSubscription, is it used to solve my problem ?
There's no easy universal way to know when to dispose the ViewModel - especially once you start mixing and matching ViewModel presentation styles to include navigations, tabs, splitviews, flyouts, fragments, lists, etc. and as you include more and more platforms
As a result of this, a couple of ways I have shut things like timers down in the past are:
1. Sometimes I have used a specialised interface on the ViewModel and I ensure this is called appropriately on each client.
For example, I have done some starting/stopping of 'page' level Views using:
OnPause/OnResume in Android
OnNavigatedTo/OnNavigatingFrom in Windows
ViewDidAppear/ViewWillDisappear in iOS
I have thought about adding this as a generalised pattern to do this (it is logged in https://github.com/slodge/MvvmCross/issues/74) - but so far I've not added this to v3 as I think it would lead to too much misunderstanding among users - it's better to let them to do this in the very few situations where it's needed.
Update: I have blogged about this and published a sample - see http://slodge.blogspot.co.uk/2013/11/n42-is-my-viewmodel-visible-can-i-kill.html
2. Sometimes I've just used Event Aggregation through the MvvmCross Messenger - and I've used it's inherent WeakReference-based messaging to make sure the ViewModel can be garbage collected when the view has finished with it.
An example of this is in the InternetMinute sample - which has a single 'Tick generation service' which ViewModels can connect to via messaging for updates - see:
the service - https://github.com/slodge/MvvmCross-Tutorials/tree/master/InternetMinute/InternetMinute.Core/Services/Tick
a ViewModel that consumes the service - via https://github.com/slodge/MvvmCross-Tutorials/blob/master/InternetMinute/InternetMinute.Core/ViewModels/HomeViewModel.cs
You might consider this slightly inefficient - as the Tick messages will be generated even if the ViewModel isn't present - but it's only a small inefficiency.
3. I've considered using more final events - things like OnNavigatingFrom(BACK) and 'onDestroy' and some 'final' detection on the UINavigationController delegates ... but I've not had a reason to do this 'for real' on any project yet.
I have this program, that needs to load a text file, which it can do, but since everything is multi-threaded on AS3, it continues with the program even though its not loaded. Like, if I was to make a function that loads the text, and then have it return the loaded text, it will always return "undefined". I have to add an event listener for when it's done, but the way I have to handle the returning of the text is awkward. Is there any way to make the program just wait, or do nothing until it's loaded?
It sounds like what you're looking for is for the data to load synchronously so that you can just make the loading call and have it return right away, like so:
# (this actually is not actionscript)
fileDataContents = open("file.txt", "r");
then have the fileDataContents immediately available to use.
By design this is not how flash works.
Loading external data in flash is not multithreaded, but rather asynchronous. One very good reason why synchronous loading is not done is that it causes blocking/locking of the program during the operation potentially resulting in a poor user experience.
Take for example, if this is loading a file over the web: what if the user's internet connection had just cut out/hiccupped or had been moved/deleted/modified suddenly on the server? Or what if the file is moderately sized but the user was on dial-up?
This is out of your control in most cases and the resulting behaviour may be that it causes flash to "forever" freeze in the user's browser window as it tries to load, possibly taking down the whole browser with it, ultimately ending in a poor user experience. By blocking/locking the program in that loop you would have no way to recover or respond to the user appropriately.
No, you can't.
Listening for the COMPLETE event like you have now is the correct way to wait and continue the application flow once done. I can't see how this would become awkward - I suggest updating your question to include information about what's making you uncomfortable about the event system so that I can help you from there.
Perhaps you're just not structuring your code in a way that works well with the event system. Here is how you can set up a very clean, straightforward way of loading some data and starting up the application once done.
Here's the document class, which can be used purely as a channel to load your text data which will be forwarded on to a fresh instance of the actual Application class:
public class Main extends Sprite
{
private var _application:Application;
private var _loader:URLLoader;
public function Main()
{
var fileUrl:URLRequest = new URLRequest("file.txt");
_loader = new URLLoader(fileUrl);
_loader.addEventListener(Event.COMPLETE, _textLoaded);
}
private function _textLoaded(e:Event):void
{
_loader.removeEventListener(Event.COMPLETE, _textLoaded);
// Load the main Application with the required text data.
_application = new Application( _loader.data );
}
}
And then your Application, which you can consider your central class.:
public class Application
{
public function Application(textData:String)
{
// Here we have access to the required text, and we can
// begin preparing the main Application.
trace(textData);
}
}
Let's say that I have a bunch of objects (thumbnails in a matrix for example) and I need to load some data files for all of those over the network (HTTP). So each thumbnail has the thumbnail image itself and an xml file for instance.
There's a number of things that can go wrong from IO errors to bad URLs to badly formatted XML and so on. The question is what is the best / most elegant / most robust way of organizing all of this. What I usually end up doing is having a load manager that tells the
child objects to start loading and then monitors the loading. The child objects have listeners for IO errors and HTTP status events. When all children have loaded everything (with some possible failures) something is done (the thumbnails are shown or whatever).
I was thinking that there has to be a better way of doing this, something that would allow me to maybe use throw clauses when errors occur. Throwing something from the listener isn't going to do much good of course. So what to do. Have a local flag(s) in the child objects and abort if something fails or what?
I am using AS3 but the question should be pretty much the same for other languages, at least for object oriented ones.
Just to be clear I'm not looking for any program code, just general ideas on a design pattern. I also realise that because of the asynchronous load I'm tied in to event handling at least in the child objects.
i use a "queue" package which is able to deal with all sorts of asyncronous operations. the nice thing is you can nest these operations (composite pattern) and create quite complex stuff easily. if events occur you can catch them either at the root as they "bubble up the queue tree) or directly where they originate, depending on the listeners you add.
interface Qable extends IEventDispatcher {
function start()
function stop()
}
interface Q extends Qable {
function add(item:Qable):Q
function remove(item:Qable):Q
...
}
var q1: Q = new Q
q1.add(new Qable(...))
q1.add(new Qable(...))
var q : Q = new Q
q.addEventListener(Event.COMPLETE, onComplete)
q.addEventListener(Event.ERROR, onError)
q.add(new Qable(...))
q.add(new Qable(...)).addEventListener(Event.Error, onItemXError)
q.add(m1)
q.start()
I have a large application that needs to ensure that various items are loaded (at different times, not just at startup) before calling other routines that depend on said loaded items. What i find problematic is how my architecture ends up looking to support this: it is either littered with callbacks (and nested callbacks!), or pre populated with dozens of neat little
private function SaveUser_complete(params:ReturnType):void
{
continueOnWithTheRoutineIWasIn();
}
and so forth. Right now the codebase is only perhaps 2500 lines, but it is going to grow to probably around 10k. I just can't see any other way around this, but it seems so wrong (and laborious). Also, i've looked into pureMVC, Cairngorm, and these methods seem equally tedious,except with another layer of abstraction. Any suggestions?
Well asynchronous operations always have this affect on code bases, unfortunately there's not really a lot you can do. If your loading operations form some sort of 'Service' then it would be best to make a IService interface, along with the appropriate MVC Style architecture and use data tokens. Briefly:
//In your command or whatever
var service:IService = model.getService();
var asyncToken:Token = service.someAsyncOperation(commandParams);
//some messaging is used here, 'sendMessage' would be 'sendNotification' in PureMVC
var autoCallBack:Function = function(event:TokenEvent):void
{
sendMessage(workOutMessageNameHere(commandParams), event.token.getResult());
//tidy up listeners and dispose token here
}
asyncToken.addEventListener(TokenEvent.RESULT, autoCallBack, false, 0, true);
Where I have written the words 'workOutMessageNameHere()' I assume is the part you want to automate, you could either have some sort of huge switch, or a map of commandParams (urls or whatever) to message names, either way best get this info from a model (in the same command):
private function workOutMessageNameHere(commandParams):String
{
var model:CallbackModel = frameworkMethodOfRetrivingModels();
return model.getMessageNameForAsyncCommand(commandParams);
}
This should hopefully just leave you with calling the command 'callService' or however you are triggering it, you can configure the callbackMap / switch in code or possibly via parsed XML.
Hope this gets you started, and as I've just realized, is relevant?
EDIT:
Hi, just had another read through of the problem you are trying to solve, and I think you are describing a series of finite states, i.e. a state machine.
It seems as if roughly your sequences are FunctionState -> LoadingState -> ResultState. This might be a better general approach to managing loads of little async 'chains'.
Agreeing with enzuguri. You'll need lots of callbacks no matter what, but if you can define a single interface for all of them and shove the code into controller classes or a service manager and have it all in one place, it won't become overwhelming.
I know what you are going through. Unfortunately I have never seen a good solution. Basically asynchronous code just kind of ends up this way.
One solution algorithm:
static var resourcesNeededAreLoaded:Boolean = false;
static var shouldDoItOnLoad:Boolean = false;
function doSomething()
{
if(resourcesNeededAreLoaded)
{
actuallyDoIt();
}
else
{
shouldDoItOnLoad = true;
loadNeededResource();
}
}
function loadNeededResource()
{
startLoadOfResource(callBackWhenResourceLoaded);
}
function callBackWhenResourceLoaded()
{
resourcesNeededAreLoaded = true;
if(shouldDoItOnLoad)
{
doSomething();
}
}
This kind of pattern allows you to do lazy loading, but you can also force a load when necessary. This general pattern can be abstracted and it tends to work alright. Note: an important part is calling doSomething() from the load callback and not actuallyDoIt() for reasons which will be obvious if you don't want your code to become out-of-sync.
How you abstract the above pattern depends on your specific use case. You could have a single class that manages all resource loading and acquisition and uses a map to manage what is loaded and what isn't and allows the caller to set a callback if the resource isn't available. e.g.
public class ResourceManager
{
private var isResourceLoaded:Object = {};
private var callbackOnLoad:Object = {};
private var resources:Object = {};
public function getResource(resourceId:String, callBack:Function):void
{
if(isResourceLoaded[resourceId])
{
callback(resources[resourceId]);
}
else
{
callbackOnLoad[resourceId] = callBack;
loadResource(resourceId);
}
}
// ... snip the rest since you can work it out ...
}
I would probably use events and not callbacks but that is up to you. Sometimes a central class managing all resources isn't possible in which case you might want to pass a loading proxy to an object that is capable of managing the algorithm.
public class NeedsToLoad
{
public var asyncLoader:AsyncLoaderClass;
public function doSomething():void
{
asyncLoader.execute(resourceId, actuallyDoIt);
}
public function actuallyDoIt ():void { }
}
public class AsyncLoaderClass
{
/* vars like original algorithm */
public function execute(resourceId:String, callback:Function):void
{
if(isResourceLoaded)
{
callback();
}
else
{
loadResource(resourceId);
}
}
/* implements the rest of the original algorithm */
}
Again, it isn't hard to change the above from working with callbacks to events (which I would prefer in practise but it is harder to write short example code for that).
It is important to see how the above two abstract approaches merely encapsulate the original algorithm. That way you can tailor an approach that suites your needs.
The main determinants in your final abstraction will depend on:
Who knows the state of resources ... the calling context or the service abstraction?
Do you need a central place to acquire resources from ... and the hassle of making this central place available all throughout your program (ugh ... Singletons)
How complicated really is the loading necessities of your program? (e.g. it is possible to write this abstraction in such a way that a function will not be executed until a list of resources are available).
In one of my project, I build custom loader which was basically wrapper class. I was sending it Array of elements to load and wait for either complete or failed event(further I modified it and added priority also). So I didn't have to add so many handlers for all resources.
You just need to monitor which all resources has been downloaded and when all resources complete, dispatch a custom event-resourceDownloaded or else resourcesFailed.
You can also put a flag with every resource saying it is necessary or compulsory or not, If not compulsory, don't throw failed event on failing of that resource and continue monitoring other resources!
Now with priority, you can have bunch of file which you want to display first, display and continue loading other resources in background.
You can do this same and believe me you'll enjoy using it!!
You can check the Masapi framework to see if it fulfills your needs.
You can also investigate the source code to learn how they approached the problem.
http://code.google.com/p/masapi/
It's well written and maintained. I used it successfully in a desktop RSS client I developed with Air.
It worked very well assuming you pay attention to the overhead while loading too many resources in parallel.