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!
Related
I have an activity indicator on xaml page. Initially its IsVisible property is false. I have a button on page. When user click on button it calls a web service to get data. I change the value of IsVisible property to true before calling the service so that activity indicator starts to display on page and after successful calling of service I change its value to again false so that it doesn't show any more on page.
But it is not working. I know the actual problem. When we call the web service the UI thread gets block and it doesn't show the activity indicator.
How I can enable the UI thread when web service gets called so that activity indicator can show on page until we get the data?
Try making your webservice call into an async and await it.
Depending on how you've structured things you may have to use a TaskCompletionSource as the following example demonstrates.
In this example when the button is clicked, the button is made invisible, and the ActivityIndicator is set to IsRunning=True to show it.
It then executes your long running task / webservice in the function ExecuteSomeLongTask using a TaskCompletionSource.
The reason for this is that in our button click code, we have the final lines:-
objActivityIndicator1.IsRunning = false;
objButton1.IsVisible = true;
That stop the ActivityIndicator from running and showing, and also set the button back to a visible state.
If we did not use a TaskCompletionSource these lines would execute immediately after calling the ExecuteSomeLongTask if it was a normal async method / function, and would result in the ActivityIndicator not running and the button still being visible.
Example:-
Grid objGrid = new Grid()
{
};
ActivityIndicator objActivityIndicator1 = new ActivityIndicator();
objGrid.Children.Add(objActivityIndicator1);
Button objButton1 = new Button();
objButton1.Text = "Execute webservice call.";
objButton1.Clicked += (async (o2, e2) =>
{
objButton1.IsVisible = false;
objActivityIndicator1.IsRunning = true;
//
bool blnResult = await ExecuteSomeLongTask();
//
objActivityIndicator1.IsRunning = false;
objButton1.IsVisible = true;
});
objGrid.Children.Add(objButton1);
return objGrid;
Supporting function:-
private Task<bool> ExecuteSomeLongTask()
{
TaskCompletionSource<bool> objTaskCompletionSource1 = new TaskCompletionSource<bool>();
//
Xamarin.Forms.Device.StartTimer(new TimeSpan(0, 0, 5), new Func<bool>(() =>
{
objTaskCompletionSource1.SetResult(true);
//
return false;
}));
//
return objTaskCompletionSource1.Task;
}
You need to do your work in an asynchronous way. Or in other words: Use Asnyc & Await to ensure, that you UI works well during the call.
You can find more informations in the Xamarin Docs.
async and await are new C# language features that work in conjunction
with the Task Parallel Library to make it easy to write threaded code
to perform long-running tasks without blocking the main thread of your
application.
If you need further asistance, please update your question and post your code or what you have tried so far.
I have an image which will be uploaded twice by flash. Besides, I'll do some resizing & compression stuff. So I have to load the data and create a BitmapData object.
_fileRef.addEventListener(Event.Complete, onLoadComplete);
_fileRef.load();
The problem is the complete event is never fired which could be checked from log message in console. What are the possibilities that such an event failed to be triggered?
my real code is shown as below:
private function prepareImage():void
{
_compressionFactor = 82;
if(as3_jpeg_wrapper==null)
{
as3_jpeg_wrapper = clibinit.init();
}
_fileRef.addEventListener(Event.COMPLETE, onImageComplete);
_fileRef.load();
}
private var tempLoader:Loader;
private var tempData:ByteArray;
private function onImageComplete(event:Event):void
{
Utils.log("loading data completed");
tempData = event.currentTarget.data;
_fileRef.removeEventListener(Event.COMPLETE,onImageComplete);
tempLoader = new Loader;
tempLoader.contentLoaderInfo.addEventListener(Event.COMPLETE,onImageLoaded);
tempLoader.loadBytes(tempData);
}
The fact is that the log message "loading data completed" is never printed. I've traced the whole process, flash stucked here. The function prepareImage is called via:
Utils.log("We'll resize & compress the picture to be uploaded");
prepareImage();
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.
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.
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.