I'm working on a Windows Store app (C++). The app loads data from database using a webservice and I want that data to be shown on the page.
Why can I not call functions w.r.t an instance of a class created inside the enclosing function? Here's the LoadState event of my app's first page...
void ItemsPage::LoadState(Object^ navigationParameter, IMap<String^, Object^>^ pageState)
{
(void) pageState;
StorySource^ storysource = ref new StorySource();
task<wstring> (GetFromDB(cancellationTokenSource.get_token()))
.then([this, storysource](task<wstring> response){
try
{
auto resp = response.get();
storysource->Init(resp);
DefaultViewModel->Insert("Items", storysource->AllGroups);
}
catch(COMException^ ex)
{ ... }
});
}
I can't execute any function inside the .then() block. I need to somehow chain the completion of GetFromDB() to StorySource::Init() and this to DefaultViewModel->Insert().
I am very new to asynchronous programming. Please explain me what I am doing wrong and what could be the solution to my problem. Thanks in advance.
Related
I am trying to understand how to write a WWW call in Unity. According to the description here http://docs.unity3d.com/ScriptReference/WWW.html I can inspect the isDone property, but in the example on the same page, it makes no attempt to inspect isDone.
The question I have is, if I make a WWW call and it takes several seconds to reply, doesn't the game freeze?
I would like to think the right code is this, but is it?
StartCoroutine(WaitForResponse(myWWWObject));
private IEnumerator WaitForResponse(WWW aRequest ) {
while ( ! aRequest.isDone )
yield return aRequest;
}
Does the game freeze until aRequest is done? Or is it truly asynchronous?
You need to understand Coroutines - a fundamental feature of Unity that allows you to write long-duration code functions (eg: longer then a frame) that will not freeze your game.
http://docs.unity3d.com/Manual/Coroutines.html
In C# you can spot a coroutine function because it has a return type of IEnumerator. And you can spot the locations in the code where the function will suspend and continue from again by the C# keyword yield.
Each MonoBehaviour class can manage coroutines, and if you tell it to start one with StartCoroutine(), then MonoBehaviour will call the coroutine every frame (sometimes more then once) until the Coroutine reaches the end.
For WWW class (which supports co-routines), all you need is to call this:
WWW www = new WWW(url);
yield return www;
You create a WWW class with the URL to retrievve, and the yield will basically be called each frame automatically by the MonoDevelop coroutine manager until www object says it has completed (successfully or failure).
Your game will not freeze at all during this time.
In the linked documentation page for WWW, the following method is a coroutine method:
IEnumerator Start() {
WWW www = new WWW(url);
yield return www;
Renderer renderer = GetComponent<Renderer>();
renderer.material.mainTexture = www.texture;
}
The yield statement is used to pause execution and return control to Unity and then to resume execution in the next game frame. For example yield return null; will cause execution to resume in the next frame. Additionally, you can extend that behaviour by using one of the classes that derive from YieldInstruction class, for example WaitForSeconds.
Consider yield return new WaitForSeconds(1f); - this will resume execution after 1 second of game time has passed. The WWW class works in similar way. You can use an instance of that class to yield execution, returning only after the download has been completed, no need to manually poll the isDone property.
Keep in mind that you can only yield in Coroutines, I advise you read up on them. If you want to do a WWW request not in a Coroutine then you have to poll the isDone manually and proceed when completed.
To answer last question: Will the game freeze when creating an instance of the WWW class? - No. The class works asynchronously. You can use it in normal Update/Start etc. functions and inside Coroutines with yield.
if I make a WWW call and it takes several seconds to reply, doesn't the game freeze?
Not, Game Will not be freez try this code and you will see that log "after corou" will show immediately even the picture is downloading.
public class WWWDemo : MonoBehaviour {
bool b = true;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update()
{
if (b) {
StartCoroutine(ExampleCoroutine());
Debug.LogWarning("after corou");
}
}
IEnumerator ExampleCoroutine()
{
b = false;
Debug.Log("Time : " + DateTime.Now);
string url = "http://images.earthcam.com/ec_metros/ourcams/fridays.jpg";
WWW www = new WWW(url);
yield return www;
Debug.Log("Time : " + DateTime.Now);
Renderer render = gameObject.GetComponent<Renderer>();
render.material.mainTexture = www.texture;
Debug.Log("Time : " + DateTime.Now);
}
}
but the execution of next line will definitely stop after yield return www statement it will wait unitl the picture download while the rest events of Unity will execute async.
Consider below example as well separately. Start Event executes ones it will wait but update will run continuously.
IEnumerator Start() {
Debug.Log("Time : " + DateTime.Now);
string url = "http://images.earthcam.com/ec_metros/ourcams/fridays.jpg";
WWW www = new WWW(url);
yield return www;
Debug.Log("Time : " + DateTime.Now);
Renderer render = gameObject.GetComponent<Renderer>();
render.material.mainTexture = www.texture;
Debug.Log("Time : " + DateTime.Now);
}
void Update()
{
Debug.Log("update is running while start is waiting for downloading");
}
I googled but didn't find a post for Flex mobile..
All I want for now is display an user agreement popup from TabbedViewNavigatorApplication when the user uses the app for the first time
var agreementView: UserAgreement = new UserAgreement();
PopUpManager.addPopUp(agreementView, this,true);
PopUpManager.centerPopUp(agreementView);
but maybe more later.
Please help..
What i did in my desktop air app;
I guess this will work at a mobile app also.
Make sure you have write access;
open yourproject-app.mxml scroll down to the end of the document. In the section, uncomment the following permission:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Now you can create files like for example an sqlite database.
At the applicationcomplete call the function checkFirstRun:
// functions to check if the application is run for the first time (also after updates)
// so important structural changes can be made here.
public var file:File;
public var currentVersion:Number;
private function checkFirstRun():void
{
//get the current application version.
currentVersion=getApplicationVersion();
//get versionfile
file = File.applicationStorageDirectory;
file= file.resolvePath("Preferences/version.txt");
if(file.exists)
{
checkVersion();
}
else
{
firstRun(); // create the version file.
}
}
public function getApplicationVersion():Number
{
var appXML:XML = NativeApplication.nativeApplication.applicationDescriptor;
var ns:Namespace = appXML.namespace();
var versionnumber:Number =Number(appXML.ns::versionNumber);
return versionnumber;
}
private function checkVersion():void
{
var stream:FileStream= new FileStream();
stream.open(file,FileMode.READ);
var prevVersion:String = stream.readUTFBytes(stream.bytesAvailable);
stream.close();
if(Number(prevVersion)<currentVersion)
{
// if the versionnumber inside the file is older than the current version we go and run important code.
// like alternating the structure of tables inside the sqlite database file.
runImportantCode();
//after running the important code, we set the version to the currentversion.
saveFile(currentVersion);
}
}
private function firstRun():void
{
// at the first time, we set the file version to 0, so the important code will be executed.
var firstVersion:Number=0;
saveFile(firstVersion);
// we also run the checkversion so important code is run right after installing an update
//(and the version file doesn't exist before the update).
checkFirstRun();
}
private function saveFile(currentVersion:Number):void
{
var stream:FileStream=new FileStream();
stream.open(file,FileMode.WRITE);
stream.writeUTFBytes(String(currentVersion));
stream.close();
}
private function runImportantCode():void
{
// here goes important code.
// make sure you check if the important change previously has been made or not, because this code is run after each update.
}
Hope this helps.
Greets, J.
Some you need to store whether the user has agreed to the agreement or not. IF they haven't agreed, then show it.
One way to do this would be to store a value in a shared object. Another way to do this would be to use a remote service and store such data in a central repository. I assume you'll want the second; so you can do some form of tracking against the number of users using your app.
We are trying to load and resume workflows which have a delay. I have seen the Microsoft sample of Absolute Delay for this using store.WaitForEvents and LoadRunnableInstance to load the workflow. However here the workflow is already known.
In our case we want to have an event waiting for the store.WaitForEvents after every say 5 seconds to check if there is a runnable instance and if so only load and run that /those particular instances. Is there a way I could know which workflow instance is ready.
We are maintaing the workflow id and the xaml associated to it in our database, so if we could know the workflow instance id we could get the xaml mapped to it, create the workflow and then do a LOadRunnableInstance on it.
Any help would be greatly appreciated.
Microsoft sample (Absolute Delay)
public void Run(){
wfHostTypeName = XName.Get("Version" + Guid.NewGuid().ToString(),
typeof(WorkflowWithDelay).FullName);
this.instanceStore = SetupSqlpersistenceStore();
this.instanceHandle =
CreateInstanceStoreOwnerHandle(instanceStore, wfHostTypeName);
WorkflowApplication wfApp = CreateWorkflowApp();
wfApp.Run();
while (true)
{
this.waitHandler.WaitOne();
if (completed)
{
break;
}
WaitForRunnableInstance(this.instanceHandle);
wfApp = CreateWorkflowApp();
try
{
wfApp.LoadRunnableInstance();
waitHandler.Reset();
wfApp.Run();
}
catch (InstanceNotReadyException)
{
Console.WriteLine("Handled expected InstanceNotReadyException, retrying...");
}
}
Console.WriteLine("workflow completed.");
}
public void WaitForRunnableInstance(InstanceHandle handle)
{
var events=instanceStore.WaitForEvents(handle, TimeSpan.MaxValue);
bool foundRunnable = false;
foreach (var persistenceEvent in events)
{
if (persistenceEvent.Equals(HasRunnableWorkflowEvent.Value))
{
foundRunnable = true;
break;
}
}
if (!foundRunnable) {
Console.WriteLine("no runnable instance");
}
}
Thanks
Anamika
I had a similar problem with durable delay activities and WorkflowApplicationHost. Ended up creating my own 'Delay' activity that worked essentially the same way as the one out of the box, (takes an arg that describes when to resume the workflow, and then bookmarks itself). Instead of saving delay info in the SqlInstanceStore though, my Delay Activity created a record in a seperate db. (similar to the one you are using to track the Workflow Ids and Xaml). I then wrote a simple service that polled that DB for expired delays and initiated a resume of the necessary workflow.
Oh, and the Delay activity deleted it's record from that DB on bookmark resume.
HTH
I'd suggest having a separate SqlPersistenceStore for each workflow definition you're hosting.
I'm building a Flex app which requires me to download files.
I have the following code:
public function execute(event:CairngormEvent) : void
{
var evt:StemDownloadEvent = event as StemDownloadEvent;
var req:URLRequest = new URLRequest(evt.data.file_path);
var localRef:FileReference = new FileReference();
localRef.addEventListener(Event.OPEN, _open);
localRef.addEventListener(ProgressEvent.PROGRESS, _progress);
localRef.addEventListener(Event.COMPLETE, _complete);
localRef.addEventListener(Event.CANCEL, _cancel);
localRef.addEventListener(Event.SELECT, _select);
localRef.addEventListener(SecurityErrorEvent.SECURITY_ERROR, _securityError);
localRef.addEventListener(IOErrorEvent.IO_ERROR, _ioError);
try {
localRef.download(req);
} catch (e:Error) {
SoundRoom.logger.log(e);
}
}
As you can see, I hooked up every possible event listener as well.
When this executes, I get the browse window, and am able to select a location, and click save. After that, nothing happens.
I have each event handler hooked up to my logger, and not a single one is being called! Is there something missing here?
The problem seems to be with my command being destroyed before this could finish.
For a proof of concept, I set my localRef variable to be static instead of an instance variable, and everything went through successfully! I guess Cairngorm commands kill themselves asap!
I used Flash player 10, and Flex SDK 3.4. The code as followings:
// Following comes callbacks
function imageLoadOpenCallback(evt:Event):void
{
trace("in--open");
}
function imageLoadCompleteCallback(evt:Event):void
{
trace("in--load");
var fr:FileReference = evt.target as FileReference;
trace(fr.data);
}
function imageLoadErrorCallback(evt:IOErrorEvent):void
{
trace("in--ioerror");
}
function imageSelectCancelCallback(evt:Event):void
{
trace("in cancel");
}
function imageSelectCallback(evt:Event):void
{
trace("in -- select");
for (var i:int=0; i<frl.fileList.length; i++)
{
frl.fileList[i].addEventListener(Event.OPEN, imageLoadOpenCallback);
frl.fileList[i].addEventListener(Event.COMPLETE, imageLoadCompleteCallback);
frl.fileList[i].addEventListener(IOErrorEvent.IO_ERROR, imageLoadErrorCallback);
frl.fileList[i].load();
trace(frl.fileList[i]);
trace(frl.fileList[i].creationDate);
trace(frl.fileList[i].creator);
trace(frl.fileList[i].data);
trace(frl.fileList[i].name);
}
}
// Following comes UI handlers
function onAddPictures():void
{
var imageFilter:FileFilter = new FileFilter("Images", "*.jpg;*.png");
frl.addEventListener(Event.SELECT, imageSelectCallback);
frl.addEventListener(Event.CANCEL, imageSelectCancelCallback);
frl.browse([imageFilter]);
}
Only the imageSelectCancelCallback handler get called when I select some files in the dialog. But no load/open/io_error handler get called at all. I have Google some code example, in which it used FileReference instead of FileReferenceList. I don't know the reason, could you please help me?
In Air the fileReference objects in fileReferenceList do not fire the complete event when doing fileList[i].load(). In a Flex project it works fine. Adobe has not responded to bug reports on this appropriately.
Make sure in your compiler settings for flex, that you have at least 10.0.0 for "Use a specific version".
The main reason to use FileReferenceList instead of FileReference would be if you need to upload multiple files at once. If you only want to allow uploading one file at once, simply use FileReference.
Some clarification: imageSelectCallback(), and NOT imageSelectCancelCallback(), should get called when you select some files in the file browser AND click OK. imageSelectCancelCallback() is only called when you click Cancel.
Other than that, I never used the load() API, but I did use the upload(URLRequest) API. I am not sure what's your use case, but if you need to upload an image to a server, you should use the upload() method.
Speaking of upload events, I experienced some reliability issues when listening to Event.COMPLETE events, so I actually got better results listening to DataEvent.UPLOAD_COMPLETE_DATA.