Search code examples
javascriptxmlwinapiwindows-8windows-runtime

Windows 8 Javascript app activation/launch deferral


So currently in a windows 8 WinJS app I'm coding, I am trying to get the loading of an xml file to take place in the app startup sequence, while the splash screen is still showing, as this xmldoc element is needed for when the home page loads, and loading of the home page will fail without it.

This is my initiation sequence in default.js:

(function () {
    "use strict";

    var activation = Windows.ApplicationModel.Activation;
    var app = WinJS.Application;
    var nav = WinJS.Navigation;
    var sched = WinJS.Utilities.Scheduler;
    var ui = WinJS.UI;

    app.addEventListener("activated", function (args) {
        if (args.detail.kind === activation.ActivationKind.launch) {
            if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {
                // TODO: This application has been newly launched. Initialize
                // your application here.
                console.log("Newly Launched!");

                var localSettings = Windows.Storage.ApplicationData.current.localSettings;
                WinJS.Namespace.define("MyGlobals", { localSettings: localSettings });

                // APP RUN TYPE CHECK AND SEQUENCE (FIRST RUN / NOT FIRST RUN):
                if (MyGlobals.localSettings.values['firstRunCompleted']) {
                    console.log("NOT FIRST RUN!");
                    // CACHE VERSION CHECK. IF APP HAS BEEN UPDATED, INITIATE NEWLY ADDED CACHE VALUES HERE:
                } else {
                    console.log("FIRST RUN!")
                    MyGlobals.localSettings.values['firstRunCompleted'] = true;
                };


                //loadXML(); have tried many things with this. doesn't work.

                

            } else {
                // TODO: This application has been reactivated from suspension.
                // Restore application state here.
                var currentVolume = app.sessionState.currentVolume;
                if (currentVolume) {
                    console.log("RESTORE FROM SUSPENSION");
                    console.log(currentVolume);
                };
            }

            nav.history = app.sessionState.history || {};
            nav.history.current.initialPlaceholder = true;

            // Optimize the load of the application and while the splash screen is shown, execute high priority scheduled work.
            ui.disableAnimations();
            var p = ui.processAll().then(function () {
                return nav.navigate(nav.location || Application.navigator.home, nav.state);
            }).then(function () {
                return sched.requestDrain(sched.Priority.aboveNormal + 1);
            }).then(function () {
                ui.enableAnimations();
            });

            args.setPromise(p);
            args.setPromise(WinJS.UI.processAll().then(function completed() {

                loadSavedColour();
                 
                // Populate Settings pane and tie commands to Settings flyouts.
                WinJS.Application.onsettings = function (e) {
                    e.detail.applicationcommands = {
                        "helpDiv": { href: "html/Help.html", title: WinJS.Resources.getString("settings_help").value },
                        "aboutDiv": { href: "html/About.html", title: WinJS.Resources.getString("settings_about").value },
                        "settingsDiv": { href: "html/Settings.html", title: WinJS.Resources.getString("settings_settings").value },
                    };
                    WinJS.UI.SettingsFlyout.populateSettings(e);
                }
                 

As you can see where I have the commented line of "loadXML()", that is where I need the loadXML() function to take place. Here is my loadXML() function:

function loadXML() {
        Windows.ApplicationModel.Package.current.installedLocation.getFolderAsync("foldername").then(function (externalDtdFolder) {
            externalDtdFolder.getFileAsync(MyGlobals.localSettings.values['currentBook']).done(function (file) {
                Windows.Data.Xml.Dom.XmlDocument.loadFromFileAsync(file).then(function (doc) {
                    WinJS.Namespace.define("MyGlobals", {
                        xmlDoc: doc,
                    });
                })
            })
        });
    };

(loadXML is a working function and works in other scenarios)

However, the issue is that before the loadXML function finishes, the app splash screen goes away, and the next home.html home page loads, which starts the accompanying home.js, which has a function that requires the MyGlobals.xmlDoc object that loadXML should have made. This immediately crashes the app, as MyGlobals.xmlDoc is undefined/null. I used to have this app working by running loadXML in home.js for the home.html page directly, but in that scenario the XML document is reloaded every time navigation is made to the page, wasting time and resources. As such, I'm trying to move the xmldocument loading into the app startup/initialization. Thanks a lot!


Solution

  • loadXML has async functionality and you need to handle that.

    You shouldn't expect that the loadFromFileAsync (or any of the other async functions) have completed before it returns to the caller. If your code doesn't wait, you'll find that the MyGlobals.xmlDoc value won't be set when you need it.

    I've renamed it below to be more accurate as to its behavior. The big change is that it returns a Promise that can be used by the caller to properly wait for the Xml doc to be loaded. This Promise could be used with other Promises to wait on multiple conditions if you'd like (or in the case, other async work).

    function loadXMLAsync() {
        return new WinJS.Promise(function (complete, error, progress) {
            var localSettings = MyGlobals.localSettings.values;
            var installedLocation = Windows.ApplicationModel.Package.current.installedLocation;
            installedLocation.getFolderAsync("foldername").then(function (externalDtdFolder) {
                externalDtdFolder.getFileAsync(values['currentBook']).done(function (file) {
                    Windows.Data.Xml.Dom.XmlDocument.loadFromFileAsync(file).then(function (doc) {
                        complete(doc);
                    });
                });
            });
        });
    };
    

    Then, in use:

    loadXmlAsync().then(function(doc) {
        WinJS.Namespace.define("MyGlobals", {
            xmlDoc: doc,
        });
        // and any other code that should wait until this has completed
    });
    

    The code above does not handle errors.