IntroductionWelcome| 00:00 | Hi, my name is David Gassner and I'd like to welcome
you to this video series, AIR for Flex Developers.
| | 00:06 | This is a followup to a previous lynda.com video series,
AIR Essential Training, in which I described how to build and
| | 00:13 | deploy basic AIR applications
| | 00:15 | using either Flex, Flash or Dreamweaver and AJAX.
| | 00:20 | In this series, I offer a deep dive into the details of
building more powerful desktop applications with the Adobe
| | 00:26 | Integrated Runtime, with an exclusive focus on building
applications with Flex Builder 3 and the Flex 3 framework.
| | 00:34 | I hope you enjoy this training,
| | 00:36 | and that it helps you build better, more powerful, cross
operating system desktop applications using Flex 3 and AIR 1.0.
| | Collapse this transcript |
| Prerequisites| 00:00 | In this video I describe some of the
prerequisites for working with this video series.
| | 00:05 | This video series, AIR for Flex Developers,
was primarily designed for developers
| | 00:09 | with some experience already in working with Flex and AIR.
| | 00:13 | It's not a beginning course. It's designed as a
follow up to the AIR Essential Training course
| | 00:18 | that was previously delivered at lynda.com.
| | 00:21 | For all of you who are brand new to Flex, you
will be able to get a lot out of this course.
| | 00:25 | You'll get a lot more if you have some
background working with Flex and AIR already.
| | 00:30 | Some of the skills that can help you get more out of the
course include knowing how to build basic applications
| | 00:35 | in Adobe Flex and how to deliver those
over the Adobe Integrated Runtime.
| | 00:40 | How to use the ActionScript 3 programming language.
| | 00:43 | How to parse XML using E4X, an aspect of ActionScript 3 that
allows to easily parse and extract data from XML structures
| | 00:52 | and some of the most fundamental things about
the Adobe Integrated Runtime, including getting
| | 00:56 | and installing the Runtime and delivering new applications
using such features as the seamless installation batch.
| | 01:03 | If some of these skills are new to you, there
are plenty of resources to help you get started.
| | 01:08 | First of all for Flex itself, take a look
| | 01:11 | at the Flex 3 Essential Training video
series that I previously did for lynda.com.
| | 01:16 | In that series you learned how
to build basic Flex applications,
| | 01:19 | how to lay out those applications visually using containers
and controls, how to work with the Event Architecture
| | 01:25 | of the Flex framework and how to
communicate with application servers
| | 01:29 | such as the PHP Application Server that's used in this
video series using a Flex component named HTTP Service.
| | 01:37 | If you'd like a refresher on the ActionScript
language, take a look at ActionScript 3
| | 01:42 | in Flex Builder Essential Training
by Joey Lott also on lynda.com.
| | 01:47 | There you'll get refresh on programming
fundamentals and on object oriented programming
| | 01:52 | as it's implemented in the ActionScript language.
| | 01:55 | Finally for AIR itself, take a
look at AIR Essential Training.
| | 01:59 | In that video series I showed developers how to build
| | 02:02 | into play basic AIR applications using
either FLEX, Flash or Dreamweaver and AJAX.
| | 02:08 | This video series focuses on a deep
dive into the details of working
| | 02:12 | with AIR including very detailed programming techniques
to work with the local file system, the local database
| | 02:18 | and so on, but it assumes that you
understand the fundamentals of AIR first,
| | 02:23 | how to get and install the Runtime and
how to deliver your applications using
| | 02:27 | such techniques as creating seamless installation.
| | 02:31 | These and other features are all covered in the Essential
Training So go ahead and jump in and at any point
| | 02:37 | when you feel like you might need some help you can go back
to these other preliminary titles, Flex 3 Essential Training,
| | 02:43 | ActionScript 3 and AIR Essential Training
to get the background that you need.
| | Collapse this transcript |
| Installing WAMP on Windows| 00:00 | In this video I'm going to describe how to
install WAMP, the Integrated Server bundle
| | 00:05 | for Windows that includes Apache, MySQL and PHP.
| | 00:10 | I'll be using services hosted by WAMP throughout
many of the exercises in this video series.
| | 00:15 | If you are working on Mac OS X, you instead want to
use a MAMP, the Mac equivalent of this server bundle.
| | 00:22 | Look for the separate video on
downloading and installing that product.
| | 00:26 | To download a copy of WAMP, go to WAMP's website
which you'll find at this URL www.en.wampserver.com.
| | 00:37 | The WAMP server bundle is completely free and includes
everything you need for hosting simple services
| | 00:43 | for your AIR applications, you
can download the latest release.
| | 00:47 | I'm using the latest version as of the
time of this recording, WampServer 2.0c.
| | 00:52 | I have already downloaded the Installer on to my desktop.
| | 00:56 | So now to get started, I will start the Installer, I'll step
through the various prompts including the notice not to try
| | 01:03 | to upgrade from WAMP 1.x, I'll click Yes to
continue the installation, click Next and then read
| | 01:11 | through the License Agreement, if you agree to the
License Agreement continue on, click Next again
| | 01:17 | and then select the installation folder location.
| | 01:20 | The default location for the WAMP Server is C:WAMP, that
will also create a WWW sub folder under the WAMP root
| | 01:29 | that will serve as your Web documents directory, click Next,
at this screen indicate whether you want a Quick Launch icon
| | 01:37 | or a Desktop icon, you really don't need
these icons for WAMP because once you start
| | 01:42 | up the WAMP server you will have an
easy access icon in the system tray
| | 01:46 | that appears automatically, I'll
click Next and click Install.
| | 01:51 | Once the files are copied over, you'll be prompted to
select which browser you want to use when you navigate
| | 01:56 | to various WAMP Administrative Tools, if Firefox has
been detected on your system as it has been on mine,
| | 02:04 | you'll be prompted to use it as
the default browser with WAMP.
| | 02:07 | If you don't have Firefox, you'll see a different version
of this screen prompting you to select a default browser,
| | 02:13 | I'll say Yes, I want to use Firefox
for my Administrative Tools in WAMP
| | 02:18 | and then the installation process will complete.
| | 02:21 | You are prompted along the way to select an SMTP server
and then to your email address, I'll enter my email address
| | 02:30 | and that just means that any links that are
produced by the WAMP server to send email
| | 02:35 | to the system administrator will
go through that email address.
| | 02:38 | I'll click Next and then on the final screen
I'm prompted to launch the WAMP Server.
| | 02:43 | I'm not going to launch it right away
because I'd also like to show you how
| | 02:47 | to start it up after it's already been installed.
| | 02:49 | I will click Finish and then I'll go to the Windows
menu, if you are working on Windows Vista as I am,
| | 02:56 | type in WAMP and look for the item labeled Start
WAMP Server, I'll click to start the server.
| | 03:02 | In the system tray on the lower right corner you'll
see an icon appear, I'll go down and click the icon
| | 03:09 | and the menu pops up showing the all the
administrative tools for the WAMP Server.
| | 03:13 | The WAMP Server includes not just the server
itself but also Apache, PHP and MySQL.
| | 03:20 | So, for example if I wanted to administer any of these
services individually I could go to the MySQL menu choice
| | 03:27 | to be able to start, stop and otherwise manage that
service, I could go to PHP and select various settings there
| | 03:34 | or once again I can start and stop the
Apache Server from this menu choice.
| | 03:38 | Under the Quick Admin section there are menu choices to
Start All Services, Stop All Services and Restart All.
| | 03:45 | To use the WAMP Server right away I'll select
Put Online and that means that I'd like to start
| | 03:51 | up the server and be able to use it immediately.
| | 03:53 | In the low right hand corner the icon in this
system tray will temporarily change color
| | 03:58 | and then the pointer will move all the way over to
the right indicating the server is ready for use.
| | 04:04 | Then I'll go back to the icon, click it again and select
Localhost and that will take me to the WAMP Home Page.
| | 04:11 | This is how you know your WAMP Server is working correctly.
| | 04:15 | I'll close that browser window, go back to the icon
again and this time I'm going to select phpMyAdmin.
| | 04:24 | This is how I'll start up the web
based management console for MySQL.
| | 04:29 | This same application phpMyAdmin is hosted
both by WAMP on Windows and by MAMP on Mac.
| | 04:36 | In a later video I'll describe how to use this
interface to import the database that you'll use
| | 04:42 | in the AIR application examples throughout the video series.
| | Collapse this transcript |
| Installing MAMP on Mac OS X| 00:00 | In this video I'm going to describe how to install
MAMP, the Integrated Server bundle that includes Apache,
| | 00:06 | MySQL and PHP for Mac OS X. To download and install
MAMP, go to the MAMP website www.mamp.info/en/index.php.
| | 00:21 | Scroll down towards the bottom of the home
page and click the Download Now button,
| | 00:26 | there are two versions of MAMP, MAMP and MAMP Pro.
| | 00:30 | MAMP is a free version of the server bundle which includes
Apache, MySQL and PHP and MAMP Pro is a licensed version
| | 00:38 | which requires a fee, we are going to use the simpler MAMP,
the one that's free because it has all the tools we need
| | 00:44 | to run the exercises in this video series, but
there is only a single installer for both versions,
| | 00:50 | download the DMG installer package and then once the MAMP
DMG file has been downloaded to your system unpack it.
| | 00:58 | Then open up the MAMP and MAMP Pro virtual disk.
| | 01:02 | The installation of MAMP is very simple, simply
drag the MAMP folder into the Applications folder,
| | 01:10 | it'll take a few seconds for everything to copy over,
there is a little over 300 megabytes of content there,
| | 01:16 | but then once the copying is complete, you 'll
be ready to launch MAMP for the first time.
| | 01:21 | Close the Installer window and then navigate to your
Applications folder and locate the new MAMP folder.
| | 01:31 | Within the MAMP folder you'll find a MAMP application.
| | 01:35 | Start it up, you may see this security
prompt and click Open,
| | 01:40 | when MAMP starts up as an application you'll see two
things happen, first you'll see a browser window open
| | 01:46 | to localhost:8888, the Apache web server that's a part
of the MAMP installation starts up on this custom port
| | 01:55 | and you'll be able to navigate around to the
various tools that lead to administer the servers.
| | 02:00 | Before you visit those administrative tools
though, you'll want to go to the MAMP application
| | 02:04 | and change the ports for both Apache and MySQL.
| | 02:08 | Click on the MAMP icon in your Dock, then click
the Preferences button in the MAMP application,
| | 02:15 | click on Ports at the top of the Window and then
click Set to Default Apache and MySQL ports.
| | 02:22 | This will cause the Apache and MySQL servers to run on
the same ports as they are in Windows which will allow you
| | 02:28 | to run the code in exactly the same way
as a Windows user might do, then click OK.
| | 02:33 | You'll see that the servers restart automatically
and you maybe prompted for a password.
| | 02:41 | If so, enter your Mac administrative password.
| | 02:45 | It's also a good idea that the built-in web
server that comes with Mac OS X is turned off.
| | 02:51 | To do that goto System Preferences, from there goto Sharing
and check to make sure that Web Sharing is unchecked,
| | 02:59 | if you had Web Sharing checked that would meant
that the version of Apache that's included
| | 03:04 | with Mac OS X is also running and
you might run into a port conflict.
| | 03:09 | You should now be able to navigate around
and see all the different tools of MAMP.
| | 03:13 | In order to make sure that the MAMP servers keep
running just keep the MAMP application open,
| | 03:18 | if you close the application that shuts down the servers.
| | 03:22 | I'll just minimize the MAMP application to
the Dock, the tool that you'll be using here
| | 03:26 | and there throughout the video series is phpMyAdmin,
| | 03:29 | a web based administrative tool that
lets you manage your MySQL server.
| | 03:34 | Close the browser and close any other windows, we turn
to the MAMP application and then click Open Startpage.
| | 03:43 | This time you'll see that the page opens on a localhost
with no port number because we updated the port numbers
| | 03:48 | in the MAMP installation, then goto phpMyAdmin and from
there you'll be able to follow steps in later videos
| | 03:56 | where you will import a database
table into your MySQL database.
| | 04:00 | One other thing that's important to know about using
MAMP, your Apache document root folder that is the folder
| | 04:06 | that contains all of the root document is
in the htdocs folder under the MAMP folder.
| | 04:12 | In the later video you'll be instructed to copy
some existing PHP code into your document root,
| | 04:18 | at that point if you are working on the Mac
you'll copy the files into this htdocs folder,
| | 04:23 | I'll mention that in the later video at that time too,
but it's a good thing to know at this point as well.
| | Collapse this transcript |
| Installing the sample database on MySQL| 00:00 | In this video, I'm going to describe how to import the
database table into the MySQL database that I'll be using
| | 00:07 | in many of the exercises throughout this video series.
| | 00:10 | In the previous exercises I showed you how to install
either WAMP or MAMP, so that you already have MySQL
| | 00:17 | and PHP installed and running on your system.
| | 00:20 | Now I'm going to go to an application called phpMyAdmin.
| | 00:25 | To get started goto your Server Administrator.
| | 00:28 | If you are working on Windows, click on the
icon in the system tray and if you are working
| | 00:32 | on Mac you can go to the MAMP application.
| | 00:35 | Locate the phpMyAdmin menu choice or
item and start up the application,
| | 00:41 | it should appear at this URL http://localhost/phpmyadmin/.
| | 00:46 | The next task is to create a new database, click into
the text field under the label Create new database
| | 00:53 | and type in the name of the database
contacts and then click Create.
| | 00:58 | If prompted with a security warning click
Continue, that will result in creating the database.
| | 01:05 | Now the next step is to import the database table.
| | 01:09 | Click the Import button, then click the Browse button,
navigate to the location of your exercise files.
| | 01:17 | If for instance, your exercise files are on your desktop,
go there and then click into the exercises folder,
| | 01:25 | from the exercises root directory, click into Assets,
from there into Server and from there into MySQL,
| | 01:33 | you'll find two files there named contacts.sql
and readme.txt, select the file contacts.sql,
| | 01:42 | on Windows just click Open, that will add the path of the
contacts.sql file to the text field in the import screen,
| | 01:50 | then click the Go button in the lower right hand corner.
| | 01:53 | It takes just a few seconds to execute the import operation.
| | 01:57 | Once the import operation is complete, go to
the structure link under the Server Listing
| | 02:03 | and from there you'll find the person table
that was created by the import script.
| | 02:08 | Click the first button which allows you
to browse the data and that will show you
| | 02:12 | that in fact you have successfully
imported the data from the database,
| | 02:16 | this database table named person
includes a 1000 records of data.
| | 02:22 | I'll be using this data in many of the exercises and
demonstrations in AIR applications, both retrieving the data
| | 02:28 | from the server and then in the section
that describes how to persist data
| | 02:32 | to the local system using the embedded SQL live
database, I'll show how to retrieve the data
| | 02:37 | from the server and then save it locally.
| | 02:40 | If you can see this data on the screen, you
are ready for the next step of the installation
| | 02:45 | which is to setup the actual exercise files.
| | Collapse this transcript |
| Using the example files| 00:00 | Just a quick word about the exercise files we'll be using.
| | 00:03 | If you're a premium member of the lynda.com Online Training
Library or if you are watching this tutorial on a DVD,
| | 00:10 | you have access to the exercise files used throughout this title.
| | 00:13 | In the Exercise File folder, I have collected some assets
for you to use during our tour of AIR for Flex developers.
| | 00:20 | They include everything you will need
to create the applications in this title.
| | 00:23 | Two videos following this one show you how to set up the
exercise files first for the Mac and then for Windows.
| | 00:30 | If you're a monthly or annual subscriber to lynda.com,
you don't have access to the exercise files
| | 00:36 | but you can easily follow along and create your own code as we go.
| | 00:40 | Let's get started.
| | Collapse this transcript |
| Setting up the example files on Mac OS X| 00:00 | In this video I'm going to describe how to install the
exercise files on Mac OS X. The steps are very similar
| | 00:07 | to those on Windows, but there are some
variations so it's worth a separate video.
| | 00:12 | First, assuming that you have the DVD version of
the video series or you have a premium membership
| | 00:17 | to the Online Training Library, you can download and
extract the exercise files anywhere on your system.
| | 00:23 | I have placed the exercise files in a
folder called Exercises on my desktop.
| | 00:27 | The first step is to move some files from the
Exercises folder into your MAMP document root.
| | 00:34 | Go to the Exercises folder, open it up and go down
to the Assets folder, from there to the Server folder
| | 00:42 | and from there to php, you will find a folder there
named AIRFlex, copy that folder to the clipboard
| | 00:49 | and then using finder, navigate to the MAMP
document root, I will go to the Applications folder,
| | 00:57 | to the MAMP folder and from there into the htdocs folder.
| | 01:03 | The htdocs folder is your document root when
you are working with Apache through MAMP.
| | 01:08 | Now paste the contents of the AIRFlex folder into the
htdocs folder, before you can test these files you need
| | 01:15 | to make a certain change in the configuration,
drill down into the AIRFlex folder within htdocs
| | 01:21 | and from there locate the file contactsconn.php, this is a
php file that defines how you will be connecting to MySQL.
| | 01:29 | Open this file in any text editor, for speed I will use
Text Edit, there is a difference between the configuration
| | 01:37 | of MySQL on Windows using WAMP and Mac using MAMP.
| | 01:42 | On Windows, MySQL is installed with a blank password,
on MAMP it's installed with a password of root.
| | 01:49 | So, in this file move to the line that starts
$password_conn and between the quotes put
| | 01:55 | in the word root, then Save and Close the file.
| | 02:00 | Then close whatever text editor you
are using, close any finder windows
| | 02:05 | and now make sure that you have your MAMP server started.
| | 02:09 | I have placed my MAMP server application
on the dock, so I can get to it easily.
| | 02:13 | I will click to start up MAMP and then
I will enter my administrative password.
| | 02:18 | Now, to test the php files that were
installed, go to the browser web address
| | 02:23 | and enter
http://localhost/AIRFlex/Person.php?method=FindAll,
| | 02:36 | it's important to note that this entire URL is
case-sensitive, type it exactly as you see on the screen.
| | 02:42 | With AIRFlex capitalized as you see it Person.php with
an initial uppercase character and the word FindAll
| | 02:49 | with an uppercase F and A, you should see after a
few moments the data returned from the MySQL server
| | 02:56 | as an xml packet, this is how you will be working with
the PHP server and My SQL using your AIR application.
| | 03:03 | So, if that's over so far, you are
ready to move on to Flex Builder.
| | 03:07 | Close the browser window, remember
to keep MAMP running at all time,
| | 03:11 | so just minimize that to the dock
and then go to Flex Builder.
| | 03:15 | Within Flex Builder, change your workspace to point
to the Exercises folder, from the Menu select File,
| | 03:23 | Switch Workspace, Other and then click Browse, then
navigate to the location of your Exercises folder,
| | 03:31 | I have placed my Exercise folder
in the desktop under Exercises,
| | 03:35 | I will choose that, I will click OK, to switch work spaces.
| | 03:40 | Whenever you switch workspaces, Flex Builder closes and then
reopens to release any locks on any open files or folders.
| | 03:48 | Now to test the ability to use an AIR application, that uses
data from a PHP server and MySQL, import an existing project
| | 03:57 | from the exercises area, go to the Flex Builder
Menu and select File, Import, Flex Project,
| | 04:06 | click to browse for an archive file, locate your
exercises area and find the file FlexAIRTest.zip,
| | 04:14 | this is a flex archive file, that you can
import into either Windows or Mac, click to open
| | 04:21 | and then click Finish, that will open up the project.
| | 04:25 | Next go to the Test Application, open the project
in the Flex Navigator view, open the source folder
| | 04:31 | and double click to open FlexAIRTest.mxml.
| | 04:36 | This application makes a simple call to a PHP
page and retrieves the same data that you saw
| | 04:41 | on the browser and then displays it in a data grid.
| | 04:44 | Go to the Menu and select Run, run FlexAIRTest,
you can also click the Run button on the toolbar
| | 04:51 | or press the appropriate keyboard shortcut.
| | 04:55 | When the application opens up, you will see that it has a
Get Data button and a Data Grid, click the Get Data button
| | 05:01 | and after a few moments the data
should appear in the data grid.
| | 05:04 | You will see that there are thousand rows that are
being displayed in the data grid and you will be able
| | 05:09 | to scroll up and down freely through the data.
| | 05:12 | So, if all that's working you are
ready to launch into the video series.
| | Collapse this transcript |
| Setting up the example files on Windows| 00:00 | In this video I will show you how
to setup some of the exercise files,
| | 00:04 | so that your AIR applications can
communicate with the PHP based services
| | 00:08 | that in turn retrieve and send data to the MySQL database.
| | 00:12 | If you have the exercise files, open up the Exercise
Files folder now and then go down to the Assets folder,
| | 00:20 | from there to Server and from there to php, in this
folder you will find a single sub folder named AIRFlex,
| | 00:28 | this folder in turn contains php based resources
that will communicate with your MySQL database.
| | 00:34 | I will go back to the php folder and then
copy the AIRFlex folder, to the clipboard.
| | 00:40 | Now, navigate to your document root within your
WAMP or MAMP server, if you are working on Windows,
| | 00:46 | the location of the document root is c:wampwww.
| | 00:50 | Now paste the AIRFlex folder into the document
root, your php files are now ready to use.
| | 00:59 | To test the files, go to a browser, make sure that your
WAMP or MAMP server is started up and then navigate
| | 01:07 | to this web address
http://localhost/AIRFlex/Person.php?method=FindAll.
| | 01:18 | All parts of this URL are case sensitive and
you must type it in exactly as you see it here.
| | 01:23 | If the service is working, you should see that an XML
structure is returned, representing one thousand rows
| | 01:30 | of data, it may take a few moments to
download to the browser, so be patient,
| | 01:34 | scroll down to the end of the XML file and you
should see down at the bottom a metadata section,
| | 01:40 | showing the total rows of one thousand, if that much
is working you are now ready to open Flex Builder,
| | 01:46 | set up your workspace and import a
project for testing an AIR application.
| | 01:52 | Close the browser and close all other
windows and then start up Flex Builder.
| | 01:57 | Flex Builder should open up to the
default Flex Development Perspective.
| | 02:02 | Next, I'm going to change the workspace.
| | 02:05 | If you went through Flex 2 or Flex
3 Essential Training video series,
| | 02:09 | you heard me describe the nature of a workspace.
| | 02:11 | As a system folder, the services are sort of table of
contents, each workspace can contain more than one project
| | 02:18 | and each project can contain one or more applications.
| | 02:21 | Go to the Flex Builder Menu and select File, Switch
Workspace, Other, then navigate to the location
| | 02:29 | of your exercise files, I will click the browse
button and then on Windows, I will go to the desktop
| | 02:37 | and then from there I will go to the Exercises folder for
this video series and click OK, you should modify your path
| | 02:43 | to wherever you installed the Exercise Files, whether
you are working on Windows or the Mac, then click OK.
| | 02:50 | You should see that Flex Builder closes and then
reopens again, once Flex Builder has reopened,
| | 02:56 | import a Flex project from the exercises area, go
to the Menu and select File Import, Flex Project,
| | 03:05 | you are going to import an archived file, a Flex project
archive file is a new architecture that was introduced
| | 03:11 | with Flex Builder 3, that allows you to export and then
import projects that are portable between operating systems.
| | 03:19 | Click the Browse button and then in the Exercises folder,
| | 03:23 | locate the file FlexAIRTest.zip,
click Open and then click Finish.
| | 03:30 | That will result in importing the flex project
and once the project is finished importing,
| | 03:35 | you will be ready to run a test to see whether
your AIR applications can talk to your PHP server.
| | 03:41 | Go to the Flex Navigator View and open up the
project, drill down to the source root SRC
| | 03:47 | and then double click to open FlexAIRTest.mxml.
| | 03:52 | Notice that there are two files, the mxml file which
is the main application file and FlexAIRTest-app.xml,
| | 03:59 | which is the application descriptive
file that contains information
| | 04:03 | about how your AIR application should be packaged and run.
| | 04:06 | Now, run the application, go to the Menu and select Run, Run
FlexAIRTest or you can click the Run button on the toolbar
| | 04:15 | or press the appropriate keyboard shortcut.
| | 04:19 | Once the application is opened up on the screen, click
the Get Data button, you should see a clock cursor appear
| | 04:26 | and then after a few moments you
should see your data show up.
| | 04:29 | In the Status Bar of the application at
the bottom, you should see the message,
| | 04:33 | There are 1000 records in the person table
and you should be able to scroll up and down
| | 04:37 | and see all the data that was returned from the server.
| | 04:41 | The source code for this application is fairly straight
forward, it includes the use of an Http Service component
| | 04:47 | and an array collection to hold the data in memory.
| | 04:50 | If this code is unfamiliar to you, go back to the Flex 3
Essential Training title and it will describe not only how
| | 04:57 | to use the PHP service that I'm using in this application,
| | 05:01 | but also how to create the service using
Flex Builder's new application wizards
| | 05:05 | for various application server platforms.
| | 05:08 | So, if you have installed the application and you
have successfully run it and you have seen data,
| | 05:13 | you are ready to start your training in this video series.
| | Collapse this transcript |
|
|
1. AIR and Flex: A Quick ReviewCreating a Flex project for AIR| 00:00 | As described in a previous video about
the prerequisites for this video series,
| | 00:05 | you might have already watched the AIR
1.0 Essential Training video series,
| | 00:09 | in which I described the most basic skills
for building AIR applications in Flex Builder.
| | 00:14 | For those who are jumping right into this video
series though, I'm going to do a quick review of how
| | 00:19 | to build a Flex Builder project for AIR
applications and then how to package
| | 00:23 | and install those applications on your desktop.
| | 00:25 | To get started in Flex builder create a new
project, from the menu select File, New,
| | 00:33 | Flex Project, set the project name to Chapter01.
| | 00:37 | As with all Flex Projects, a project name consist
of letters, numbers and underscores and starts
| | 00:43 | with an alphabetical character, special
characters and spaces aren't allowed.
| | 00:48 | Click the Browse button to select the folder.
| | 00:51 | In the Exercises folder area, go
down to the Chapter1 subfolder
| | 00:55 | and from their choose the Begin folder and click OK.
| | 00:59 | Make sure your Application Type is set to
Desktop Application, Runs in Adobe AIR,
| | 01:05 | set the Application Server Type to None and click Next.
| | 01:09 | The output folder is the location where your
debugged version of the application will be built,
| | 01:13 | accept the default value of bin-debug and click Next again.
| | 01:17 | The main application file is your
source code for the application.
| | 01:21 | Change the name of the application file to HelloWorld.mxml.
| | 01:27 | The application idea is described in the previous video
series essential training, should consist of the name
| | 01:33 | of the application, plus a prefix including
the reverse domain name of your organization
| | 01:39 | and any other identifying information
you might want to include in dot (.)
| | 01:43 | format. For instance, for this application I will use the
application id com.lynda- that's the reverse domain name
| | 01:50 | of lynda.com. com.lynda.FlexAIR.HelloWorld, I will
click Finish to create the project and the application.
| | 02:01 | When the application opens, if it opens in Source, you
click on the Design button to go into Design View,
| | 02:08 | then go down to the Components View in the lower left
hand corner of Flex Builder and drag in a label object.
| | 02:14 | Because the application is initially
created with absolute layout,
| | 02:18 | the label object will drop in the
place wherever you place it.
| | 02:21 | Now with the label selected go over to the Flex
Properties View and scroll down to the Text Section.
| | 02:29 | Set the Label Size to 18 pixels, you can
use the slider as I did or your can click
| | 02:36 | and type the value into the text entry area.
| | 02:39 | Now, scroll down to the bottom of the Flex
Properties View and with the Label Control selected,
| | 02:45 | use Constraints based layout to place the
label in the direct center of the application.
| | 02:50 | Click the horizontal center anchor and then set it's
value to 0 and then click the vertical center anchor
| | 02:57 | and make sure it's value is set to 0 as well.
| | 03:03 | Save your changes and then run the application.
| | 03:07 | To run an application from within Flex Builder, you can
click the Run button, you can go to the Menu and select Run,
| | 03:14 | run HelloWorld or you can press
the appropriate keyboard shortcut.
| | 03:18 | When the application runs it should open up
in a separate window as a native application.
| | 03:24 | In the next video, I will review how to package
and install your application on the desktop.
| | Collapse this transcript |
| Exporting an AIR installation package| 00:00 | In this video,
| | 00:01 | I'm going to review how to create an installer package
| | 00:04 | for an AIR application.
| | 00:06 | Once again, these were steps that I have
described in the Essential Training video series,
| | 00:10 | that are worth going over again for those
who are jumping right into this video series.
| | 00:14 | You can follow these steps with any AIR application
in Flex Builder. I'll be using the HelloWorld application
| | 00:20 | I created in the previous video.
| | 00:23 | From the Flex Builder menu select File,
| | 00:26 | Export,
| | 00:28 | Release Build.
| | 00:29 | In the Export Release Build dialog box,
select the Project and an Application
| | 00:34 | and then indicate what AIR file you are creating.
| | 00:37 | I'll accept the default setting of HelloWorld.air.
| | 00:40 | A file with the .air extension again
| | 00:42 | is an installer package that can be used on either Windows,
Mac or in the future any other platform that supports the
| | 00:49 | Adobe Integrated Runtime.
| | 00:51 | Click Next
| | 00:53 | and now you will need to select a digital certificate.
| | 00:56 | As described in the Essential Training video series, the
digital certificate is required to verify your identity to
| | 01:02 | anybody who wants to install your application.
| | 01:05 | If you don't already have a digital certificate that's from
one of the authorized digital certificate vendors, Thawte or
| | 01:10 | Verisign, you can create a self-signed certificate here.
A self-signed certificate is only used during testing and
| | 01:18 | development because when you install the
application it will report your identity as unknown.
| | 01:24 | To create a new self-signed certificate,
| | 01:27 | click the Create button,
| | 01:28 | enter yours or your organization's name. I'll enter Lynda.com
| | 01:33 | and then type in a password twice.
| | 01:39 | Browse to select a location where you
want to create the certificate file.
| | 01:43 | I'll place it in my top level Exercises folder, so I can
use it in all the exercises throughout this video series.
| | 01:49 | And then give it a name. I'll call it myCertificate
| | 01:53 | and it will have a file extension of .p12.
| | 01:56 | Click Save
| | 01:57 | and that'll take you back to the
digital certificate creation screen
| | 02:02 | and click OK to create the certificate file.
| | 02:05 | Next, enter the password.
| | 02:07 | You may find that the password is entered
automatically for you, but if it isn't just type it in.
| | 02:13 | And you can check this option, Remember password for this session,
| | 02:17 | and that will cause the password to always be there whenever you
use this certificate again during the current Flex Builder session.
| | 02:23 | Click Next,
| | 02:26 | and on the following screen, you'll indicate
which files should be packaged in the installer.
| | 02:31 | You must include the application descriptor file,
| | 02:34 | which in this application is called HelloWorld-app.xml
| | 02:38 | and the compiled application HelloWorld.swf. Click Finish,
| | 02:43 | and that should result in creating the HelloWorld.air file.
| | 02:47 | Now before you follow the next step to actually
install your application on the desktop system,
| | 02:52 | you'll need to make sure you have
installed the Adobe Integrated Runtime.
| | 02:55 | If you don't already have the runtime,
you can download it from the Adobe website.
| | 03:00 | On the Adobe homepage there is a link labeled Get ADOBE AIR.
| | 03:05 | Click that link and you should go to a screen that's
appropriate for your operating system, Windows or Mac.
| | 03:12 | Once you've downloaded and install the runtime, which I've
already done previously, you're ready to install your application.
| | 03:19 | Go back to the Flex Navigator view
| | 03:21 | and locate the HelloWorld.air file that we just created.
| | 03:26 | And then open the AIR file, which you can
do by double clicking on either Mac or Windows.
| | 03:31 | At the initial screen, noticed that the publisher is reported
as Unknown. Once again, this is because you are using a
| | 03:37 | self-signed digital certificate.
| | 03:39 | If you had one from the Certificate Authorities
your actual organization name would be reported here.
| | 03:45 | Click the Install button,
| | 03:47 | verify your Installation Preferences
and the location of your application.
| | 03:52 | On Windows, the Installation Location will be the Program Files folder
under the C drive and on Mac it will be in the Applications folder.
| | 04:00 | Click Continue to install the application
| | 04:03 | and then the application should
open immediately on your system.
| | 04:07 | Close the application
| | 04:09 | and then try opening the application again.
| | 04:12 | If you're working on Windows you can
open the application from the Start Menu.
| | 04:16 | On Windows Vista, which I'm operating on, I'll type in HelloWorld
| | 04:21 | and I'll find the HelloWorld application there
| | 04:24 | and I'll be able to run the application immediately.
| | 04:27 | If you're working on Windows XP,
| | 04:28 | you'll find the application listed under All Programs on the Start
Menu and if you are working on the Mac, you will want to go to
| | 04:34 | your Application folder and double click or
simply run the HelloWorld application from there.
| | 04:40 | To uninstall the application, you can either follow
the standard operations on your operating system.
| | 04:46 | For instance, on Windows Vista you could go through the
Remove Programs dialog or on the Mac you could simply drag the
| | 04:52 | application into the trash
| | 04:54 | or you can double click on the AIR file to run it again.
| | 04:58 | The Adobe Integrated Runtime will detect that the application
is already installed and it will give you the option to Uninstall.
| | 05:05 | And now the application is gone from my desktop but I have the
application installer ready to go anytime I need to install it again.
| | Collapse this transcript |
| Using the descriptor file| 00:00 | In this video, I'm going to review the
use of the Application Descriptor File,
| | 00:04 | which determines much of the behavior of
both the application and the installer.
| | 00:09 | When you create a brand new mxml
application in Flex Builder,
| | 00:13 | a new Application Descriptor File was created for you.
| | 00:17 | The name of the file will match the name of the application
| | 00:20 | and will have the suffix of -app
and a file extension of .xml.
| | 00:25 | Here is the HelloWorld-app.xml file that's determining the
behavior of both the installer and the application itself.
| | 00:32 | I am going to maximize the editor so I can show you as
much of this code as I can, but if you are following along
| | 00:38 | in the exercises you can go ahead and open
this file yourself to see all of the text.
| | 00:42 | The first important element I want to describe is the
xmlns attribute of the application element at the root.
| | 00:49 | As I have described in the Essential Training video,
this is a critical bit of information to the AIR Packager
| | 00:56 | that tells it what version of the
runtime this application is designed for.
| | 01:00 | The namespace that's indicated here that ends with
1.0 means that this application works on AIR 1.0.
| | 01:06 | If you see something that ends with a .0, .m
and then a number, that would be an application
| | 01:12 | that was go for previous data version of AIR.
| | 01:15 | For current AIR applications, you want to ensure
that you have a 1.0 at the end and nothing after it.
| | 01:21 | Next, a little further down is the id element.
| | 01:25 | The id element will contain the
fully qualified id that you entered
| | 01:29 | in the Flex Builder interface when
you first created the application.
| | 01:33 | If you want to change the id you can and the purpose
of it is simply to uniquely identify the application.
| | 01:40 | The Filename is used to determine the
name of the file for the application.
| | 01:44 | For instance, HelloWorld means you are
creating a file called HelloWorld.air.
| | 01:49 | The Name element is a value that shown
during the application installation process
| | 01:54 | and the version number can be used to provide information
to you during automatic updates to the application.
| | 02:01 | There are some additional descriptive elements
down here which can either choose to enter or not.
| | 02:06 | The Description if you enter it
will show up on the second screen
| | 02:09 | of the installer and the Copyright again, is optional.
| | 02:13 | The initial window elements actually control behavior
of the application rather than the installer.
| | 02:18 | In the Essential Training video, I have
described the use of the title element.
| | 02:22 | You can set the title element either from this Application
Descriptor File or from your main application file code.
| | 02:29 | For example, if I were to establish the title element here,
I would remove the comment tokens from the title element
| | 02:35 | and then type in the title of the
application here Hello World.
| | 02:44 | I will then save and run the application and notice on the
title bar of the application window, it shows the title.
| | 02:50 | Now I will undo those changes, save the
changes to the descriptor file and then go
| | 02:58 | to the mxml main application file to the source code.
| | 03:01 | I will go to the WindowedApplication element and I'm going
to move some code around here so it's a little bit easier
| | 03:07 | to see on the screen and then I will
add a title element here and this time
| | 03:12 | to make sure I'm seeing the new version I
will use a different string Hello Again.
| | 03:16 | I will save the changes, run the application and
once again the application shows up and you will see
| | 03:23 | that the title element is shown on the Title bar.
| | 03:26 | So there are many properties that
initial window which can be set either
| | 03:30 | in the application code or in the
application descriptor file.
| | 03:34 | I will come back to the Application
Descriptor File in Flex Builder.
| | 03:38 | The next three elements System Chrome, Transparent
| | 03:41 | and Visible are typically set through
the Application Descriptor File.
| | 03:45 | I have described in the Essential Training Video Series,
how to use these elements in some other properties
| | 03:51 | to create transparent applications, that is
applications that are like widgets that appear
| | 03:56 | on the screen without any rectangular background.
| | 03:59 | The next three values, minimizable, maximizable and
resizable can be used to control what the users allowed
| | 04:06 | to do with the initial window, whether
they can minimize, maximize or resize it.
| | 04:11 | By default, this application can be resized at runtime.
| | 04:14 | I will run the application and show you
that the user is able to resize as needed.
| | 04:22 | They are able to minimize, they are able
to restore and they are able to maximize.
| | 04:29 | Now, I will close the application and
return to the Application Descriptor File.
| | 04:35 | For all three of these elements, I'm
going to remove their comment tokens
| | 04:40 | and then put in the word false in between the tags.
| | 04:43 | I will do that for the minimizable, the
maximizable and the resizable elements.
| | 04:58 | I will save the changes and run the application again and
this time the application will put up with a fixed size.
| | 05:05 | Noticed that any system chrome or controls
that would normally allow you to minimize
| | 05:10 | or maximize the window are gone and if I move the cursor
| | 05:13 | down to the lower right corner, I
will find that I can't resize it.
| | 05:17 | So again, these are values that are
controlled in the application descriptor.
| | 05:22 | The height and width of the window can be controlled either
| | 05:24 | from the Application Descriptor
file or from the application itself.
| | 05:29 | Here is a very important tip.
| | 05:30 | When you are building an application in
Flex Builder, make sure that if you set one
| | 05:35 | of dimensions then you actually set both.
| | 05:38 | There are circumstances where if you set
a height for instance but not a width,
| | 05:42 | the application will open Mac OS X and not show any content.
| | 05:46 | So I'm going to set this application with an initial
height of 300 pixels and an initial width of 400 pixels
| | 05:55 | and I will save and run the application and now I have
exerted very tight control over the size of the application.
| | 06:02 | I can close the application, change the values.
| | 06:06 | I will change to a height of 100 and a width of 150
and run the application again and now I will see
| | 06:14 | that the application opens up in
a much smaller initial window.
| | 06:18 | I will close the application and then set
the dimensions back to their initial settings
| | 06:22 | with the width of 400 and a height of 300.
| | 06:26 | Other elements that can be set through the Application
Descriptor file, include the X and Y properties,
| | 06:31 | that is the initial window's initial position when it first
opens up on the screen and a minimum size and maximum size.
| | 06:38 | So for instance, if you set minSize and maxSize
elements and then we have resizable set to true,
| | 06:44 | then the user will be able to resize but
only bring it down to a minimum size beyond
| | 06:49 | which you don't want to minimize anymore.
| | 06:52 | There are many other attributes in this file
that you can set, many of which I have described
| | 06:56 | in the Essential Training video series and some of
which I will come back to later on in this video series,
| | 07:02 | but for those who went through the initial video
series this will have been a good review of the purpose
| | 07:07 | of the application descriptor file and how
it controls both the application packaging
| | 07:12 | and the applications behavior at runtime.
| | Collapse this transcript |
|
|
2. Using the ClipboardUnderstanding the Clipboard architecture| 00:00 | In this chapter, I'm going to describe
the use of the Clipboard
| | 00:03 | to move data back and forth between applications in AIR.
| | 00:06 | The clipboard is an architecture that allows
copying and pasting between different applications.
| | 00:12 | For example, if you are using the Microsoft Office suite and
you want to move data between say Excel and Microsoft Word,
| | 00:19 | you would copy content from Excel
and then paste it into Word.
| | 00:23 | In a manner very similar to these sorts of
applications, AIR application allow you to place data
| | 00:28 | in the clipboard programmatically using ActionScript code
and then retrieve the data using other ActionScript code.
| | 00:34 | I will be using a standard action
script class called the Clipboard.
| | 00:38 | Users already have the ability to copy and paste simple
text values between applications when they are working
| | 00:45 | in their desktop application deployed on AIR.
| | 00:47 | For example, if your application has a data entry form
and you have some content say a text or a word file,
| | 00:54 | the user can move data between the applications using
standard user adjusters such as Ctrl+C or Command+C
| | 01:01 | on the Mac and Ctrl+V or Command+V on the Mac.
| | 01:05 | The clipboard allows programmatic
support of these features though.
| | 01:09 | The AIR clipboard class allows you to
place data into the clipboard and get data
| | 01:14 | out while your AIR application is executing.
| | 01:17 | It allows you to move data not just within an
AIR application but also allows you to move data
| | 01:23 | between AIR applications, from an AIR application to
a non-AIR application and back in the other direction
| | 01:29 | from a non-AIR application to an AIR application.
| | 01:32 | There are limitations to this ability.
| | 01:34 | First of all, you only have control over
what happens inside the AIR application.
| | 01:39 | You naturally can't control directly what happens in a
target or a source application that's not built-in AIR,
| | 01:45 | but within those restrictions the clipboard class allows you
to move data quite easily from one application to another.
| | 01:51 | The concept of a clipboard is wrapped
around the idea of formats.
| | 01:55 | When you place data into a clipboard,
you indicate what format it's in.
| | 02:00 | Formats are identified by names
which as expressed as Strings.
| | 02:04 | There are five built-in formats in the AIR environment.
| | 02:08 | They are listed here.
| | 02:09 | When you place data in the clipboard you can does made that
it's simple text, that it's a bitmap representing a graphic,
| | 02:16 | that it's a URL, a file list which would be a
list of file objects or HTML formatted test.
| | 02:23 | You also have the ability to create
your own custom format names.
| | 02:27 | For instance, if you wanted to move complex data from
one application to another and had it both the copying
| | 02:33 | of the data in the source application
and the retrieve of the data
| | 02:37 | in the destination application using ActionScript code,
you would designate your own custom format name because none
| | 02:44 | of the standard formats would match the type of
data that you are moving between applications.
| | 02:49 | The System Clipboard is represented in the world of AIR by
a static generalClipboard property of the clipboard class.
| | 02:57 | When you call any of the methods of the clipboard class,
you call them as members of the general clipboard object.
| | 03:04 | For example, the clipboard class has getData method, which
receives a format name as it's only argument is called
| | 03:11 | as a member of the generalClipboard static property.
| | 03:14 | For example, the getData method, which receives a
formatname as an argument and returns data associated
| | 03:21 | with that format name is always called as a
member of the generalClipboard static property
| | 03:26 | of the Clipboard class and not
of the clipboard class itself.
| | 03:29 | There can only be one clipboard at any time,
| | 03:33 | so the generalClipboard property
represents what we called a Singleton,
| | 03:36 | an object of which that can only be wanted at a given time.
| | 03:41 | Here are the key members of the
clipboard class that you will use.
| | 03:44 | First the methods, setData, adds data to the
clipbord, getData retrieves data from the clipboard,
| | 03:52 | clearData removes all data from the clipboard and should
be called prior to adding new data to the clipboard
| | 03:58 | and the hasFormat method allows you to
determine, whether data is currently stored
| | 04:03 | in the clipboard associated with a particular format name.
| | 04:07 | The generalClipboard static property which is I have
previously described, references the only instance
| | 04:13 | of the clipboard object and the formats
property, an array which represents all
| | 04:18 | of the formats currently stored in the clipboard.
| | 04:21 | So those are the pieces of the puzzle.
| | 04:23 | In the following videos in this chapter, I will show you
some examples of how to move data between the clipboard
| | 04:28 | of the operating system and the clipboard of
an AIR application and back again and then how
| | 04:34 | to move complex data between AIR applications.
| | Collapse this transcript |
| Copying data to the system Clipboard| 00:00 | In this video, I'm going to describe how to copy data
to the system clipboard so that it can be accessed
| | 00:06 | by other applications running in the operating system.
| | 00:09 | For all the demonstrations in this chapter, I
will be using a Flex Project that you will find
| | 00:13 | in the Exercise files if you are following along.
| | 00:15 | To import the Flex Project, go to the Flex Builder
Menu and select File, Import, Flex Project.
| | 00:23 | Click the Browse button next to Archive
file and in the Chapter02 folder
| | 00:28 | within the Exercises area select
the Chapter02BeginProject.zip.
| | 00:34 | Open the project and click Finish to import it.
| | 00:38 | Now open the project in the Flex
Navigator view, open the source folder
| | 00:43 | and from there open a file named ClipboardDemo.mxml.
| | 00:47 | In this first demonstration, I'm going to be showing
you how to copy a simple string value to the clipboard
| | 00:53 | so that it can then be pasted into other applications.
| | 00:56 | The user of course could do this themselves by simply
using a keyboard or a mouse adjuster to copy text
| | 01:03 | but the clipboard class and ActionScript allows you
| | 01:05 | to explicitly copy data using your own ActionScript
commands and that's what I will be showing here.
| | 01:11 | The existing AIR application is very simple.
| | 01:13 | It has two text area controls and two buttons.
| | 01:17 | The first text area control is label Source, the second
Destination and there are Copy and Paste buttons.
| | 01:24 | The existing source code has two
functions named copyData and pasteData.
| | 01:28 | I will be simply filling in the
code to execute these functions.
| | 01:33 | In this first demonstration I'm going
to copy a string value to the clipboard.
| | 01:36 | If you are following along, place your
cursor inside the copyData function.
| | 01:41 | I will expand my editor to full
screen to see as much code as possible
| | 01:46 | and then I will start the process
of copying data to the clipboard.
| | 01:49 | I will be using a class called Clipboard.
| | 01:52 | This is a class that's in the AIR library
that does not have to be explicitly imported.
| | 01:57 | Putting the name of the class and
press a period and you will see
| | 02:00 | that there is a single static property named
generalClipboard which represents the system clipboard.
| | 02:06 | Put in the generalClipboard property and press
another period and then call the clear() method.
| | 02:11 | This method clears all data from
the clipboard, regardless of format.
| | 02:16 | Put in a semicolon to close the line
then start a new ActionScript statement.
| | 02:21 | In the next statement, once again use the Clipboard class as
generalClipboard property and then call the setData method.
| | 02:28 | The setData method has two required
arguments and one that's optional.
| | 02:32 | The first argument is the name of the format.
| | 02:35 | There are five built-in formats in the AIR library.
| | 02:38 | They are represented as constants in
the class called ClipboardFormats.
| | 02:43 | Put in the ClipboardFormats class and press a
period and you will see the five constants listed.
| | 02:49 | Select the Text Format.
| | 02:50 | This is the format that's used when you pass
simple text values into or out of the clipboard.
| | 02:56 | Put in a comma after the constant and then passing the
value from the text in text area control, textIn.text.
| | 03:05 | Close the parenthesis and close
the command with the semicolon.
| | 03:09 | That's it.
| | 03:11 | The copyData function is already being called
when the user clicks on the Copy button.
| | 03:16 | Save your changes and then I will restore the editor to
regular size so I can see the Flex Navigator view again.
| | 03:24 | I am going to close up the Source folder
and open a file called SimpleTextFile.txt.
| | 03:30 | I will be using this text file to show that once I have
copy data into the clipboard from the AIR application,
| | 03:35 | I can then paste it from any other application.
| | 03:38 | I will go back to ClipboardDemo and run the application.
| | 03:42 | Once the application is opened up, I will click into
the source text area folder and type a value in.
| | 03:51 | Now I will click the Copy button to
actually copy the data to the clipboard.
| | 03:55 | There is no indication to the user that this is worked
but the code in the background should have been executed.
| | 04:01 | Notice I can still use standard
copy and paste functionality.
| | 04:05 | Either within an AIR application here I have right
click on the text area control and selected Paste
| | 04:11 | or more to the point, I can go back to the SimpleTextFile
running in any text editor and I can also paste from here
| | 04:18 | and you will see that the data has moved from
the AIR application into the SimpleTextFile.
| | 04:24 | Just to make sure that there is no slide
of hand and the text is actually coming
| | 04:28 | from the application I will demonstrate again.
| | 04:30 | I will type in another line, I will once again
copy to the clipboard by clicking the button,
| | 04:40 | switch back to the text file and once again Paste and you
will see all of the text coming from the AIR application.
| | 04:48 | So this is the basic model for copying data into
the clipboard programmatically in ActionScript.
| | 04:54 | We use the generalClipboard property to represent
the singleton instance of the system clipboard.
| | 05:00 | Before copying any data into the clipboard you clear it
and then you call the setData method to pass the data in.
| | 05:08 | Now in the next video, I will show you how to get data out
of the clipboard programmatically using ActionScript code.
| | 05:13 | 2
| | Collapse this transcript |
| Retrieving data from the system Clipboard| 00:00 | In this video, I'm going to describe how
to use the ActionScript clipboard class
| | 00:04 | to retrieve data from the system clipboard.
| | 00:07 | I will be using the same application as
the previous video ClipboardDemo.mxml.
| | 00:12 | If you didn't watch that video previously, you will
need to go back to that video and follow the steps
| | 00:17 | to import the project and then
open the file ClipboardDemo.mxml.
| | 00:22 | If you are following along, place the cursor
inside the existing pasteData function just
| | 00:27 | as when adding data to the clipboard.
| | 00:29 | To retrieve data from the clipboard, you will use the
Clipboard class as generalClipboard static property.
| | 00:35 | To reference the single instance of the system
clipboard, place the cursor inside the pasteData function
| | 00:41 | and declare a variable named pastedString
and data type it as a string.
| | 00:49 | Then assigned the variable by calling the
Clipboard's generalClipboard properties getData method
| | 00:55 | like this, Clipboard.generalClipboard.getData.
| | 01:02 | There is one required argument,
the format name you are looking for
| | 01:05 | and then an optional argument named
transferMode that I will describe later.
| | 01:09 | For this example, I will use the simplest syntax just
passing in a format name, just as when setting data
| | 01:16 | in the clipboard we use the ClipboardFormats classes
constants to indicate what kind of data we are looking for.
| | 01:21 | I will select the Text Format constant just as before,
then I will close the method call with the parenthesis
| | 01:30 | and then explicitly cast the data
type of the return value as a string.
| | 01:34 | If you look in the API documentation for the getData
method, it indicates that it returns in object.
| | 01:40 | If you know that you are getting
back a string you have to say so.
| | 01:43 | Now I will take that returned data and assign it to the text
| | 01:47 | out to text areas text property like
this, textOut.text = pastedString.
| | 01:56 | I will save the changes and notice again that
the pasteData function is already being called
| | 02:01 | when the user clicks the button with a label of paste.
| | 02:04 | I will run the application.
| | 02:06 | Now I will come back to Flex Builder and returned to
the file SimpleTextFile.txt and I'm going to select
| | 02:14 | and copy the text that was already there, The
quick red fox jumped over the lazy brown dog.
| | 02:19 | I will copy it to the clipboard, I will return back to
the running AIR application and click the Paste button
| | 02:26 | and you will see the data show up in
the Destination text area control.
| | 02:30 | So that's the basic syntax for getting
data out of the clipboard regardless
| | 02:34 | of whether the data was placed
there using an AIR application
| | 02:38 | or some other application running in the operating system.
| | 02:41 | Use the getData method, you will pass in the name of the
format you are looking for, you will explicitly data type
| | 02:47 | to return value as the type you know it's going to be
returned, in this case we know it's going to be a string
| | 02:53 | because that's what the text format, format name is
telling us and then you do something with that data.
| | 02:59 | In the next video, I will show you
how to do the same sort of copy
| | 03:02 | and paste operation but this time using a complex object.
| | Collapse this transcript |
| Transferring complex objects with the Clipboard| 00:00 | In this video, I'm going to describe how to use the system
clipboard to move complex objects between AIR applications.
| | 00:07 | I will be using two different applications
named ObjectSource and ObjectDest
| | 00:12 | that are part of the Chapter02Begin Project.
| | 00:15 | If you are following along in the exercises,
open these two application in Flex Builder.
| | 00:20 | I will start off in ObjectSource.mxml.
| | 00:24 | I will open up the code to full screen
so we can see as much code as possible.
| | 00:28 | This application retrieves data from the PHP
interface that I described in earlier videos.
| | 00:34 | So in order to run this application, you
will need to make sure that your copy of MAMP
| | 00:38 | or WAMP is running as it is on my system.
| | 00:41 | I will run the application and show you the goal.
| | 00:45 | In this version of the application, the date is
retrieved from the server as the application opens up.
| | 00:50 | I want to be able to select a single row from
the Data grid and copy that row to the clipboard
| | 00:56 | and then in the Destination application I
would like to be able to paste that data
| | 01:02 | so that its data shows up in this data entry form in detail.
| | 01:07 | So here with the steps.
| | 01:08 | I will close both the applications and return to the code.
| | 01:12 | In the Source application, place the cursor
inside the existing copyToClipboard method.
| | 01:18 | Noticed that this method starts off empty.
| | 01:20 | Now I'm going to retrieve a reference to the
currently selected object from the DataGrid.
| | 01:26 | Noticed that the DataGrid has an id of personGrid.
| | 01:30 | I declare a variable named dataObj typed
as an object and then I will reference
| | 01:37 | that from DataGrid personGrid.selectedItem.
| | 01:42 | Now I'm going to clear the clipboard and then
copy this data object to the clipboard just
| | 01:47 | as with the earlier video where I cleared the data.
| | 01:50 | I'm going to use the Clipboard objects, generalClipboard
property and from there I will call the clear method.
| | 01:58 | Then I will call the Clipboard
generalClipboard.setData method.
| | 02:02 | So far this looks exactly the same as before,
but now we get to the name of the format.
| | 02:08 | If the object that you are copying from one application to
another has properties that are exclusively string values,
| | 02:15 | you can use Text Format as the format name, but if you
are moving other kinds of data like integers, numbers,
| | 02:22 | booleans and so on, you have to create
your own custom format name, otherwise,
| | 02:27 | you run into runtime errors when
you try to paste the data in later.
| | 02:31 | So I'm going to create a very simple
format name named customFormat.
| | 02:37 | In an actual application I would probably use a more
descriptive format name but I want to make it clear
| | 02:43 | that you can make up the name and call it whatever you want.
| | 02:46 | Then I will pass in the data object dataObj.
| | 02:49 | I will also make a call to Alert.show to give the user an
indication that The data has been copied to the clipboard.
| | 03:04 | I will save my changes, run the application to test it
and you will notice that when the application first opens
| | 03:10 | up the Copy to Clipboard button is disabled.
| | 03:14 | That's because its enabled properties bound to an expression
that only turns the button on when I select a row.
| | 03:20 | Now I will click the button and I will get the message
that the data has been copied to the clipboard.
| | 03:25 | Now I will go to the Destination application.
| | 03:29 | In the Destination application noticed that there is a
Bindable variable named aPerson, data typed as an object.
| | 03:36 | Once again, as in the previous examples I
will use the clipboard class's getData method.
| | 03:42 | I will assign the value of the existing variable
aPerson to clipboard.generalClipboard.getData
| | 03:51 | and then I will use the same customFormat
name that I used when I put the data
| | 03:57 | into the clipboard in the other application.
| | 03:59 | Because the variable aPerson is already declared
and is Bindable and because the textInput controls
| | 04:05 | within the form below are binding to the properties of that
object, when I paste the data in I should see the details
| | 04:13 | of that appear in the Destination application.
| | 04:15 | So now I will run both applications.
| | 04:19 | Noticed that when you are working in Flex Builder,
you can run two applications at a time as long
| | 04:25 | as they each have different identifiers or application ids.
| | 04:29 | So I will run the two applications and I
will place them side by side on the screen.
| | 04:37 | I will go to the Source Application, select a row of data,
I will choose Robert Lombardi and copy it to the clipboard.
| | 04:45 | I will get the message that the
data has been copied successfully.
| | 04:49 | Now I will go to the Destination Application
and paste and you will see the data up here.
| | 04:53 | I will be able to go back and forth
between the two applications.
| | 04:57 | Select another row and copy.
| | 04:59 | Go back to the Destination and paste and once again,
you will see the data moving between AIR applications.
| | 05:06 | You can copy and paste complex
objects very simply in this manner.
| | 05:09 | There is a limitation here.
| | 05:11 | In that if you use strongly typed value objects, you will
be able to successfully copy a strongly typed value object
| | 05:18 | into the clipboard but when you retrieve it at the other
side, it will be transferred into a standard objects.
| | 05:24 | There are ways around this.
| | 05:25 | There is an interface called IExternalizable which you can
implement in your value objects but that takes a good bit
| | 05:31 | of work but in many it's a lot simpler to just use the
standard ActionScript object as the format for complex data
| | 05:39 | that you move from one application
to another using the clipboard.
| | 05:43 | Now in the next video, I will show you how to do something
very similar but this time instead of passing one object
| | 05:48 | from source to destination application, I will use an array
collection and show you that you can pass complete sets
| | 05:55 | of data from one application to another using the clipboard.
| | Collapse this transcript |
| Transferring data collections with the Clipboard| 00:00 | In this video, I'm going to describe
how to pass complete data sets
| | 00:04 | from one AIR Application to another
using the system clipboard.
| | 00:08 | As in the previous videos, I'm going to use the standard
Clipboard class and it's setData and getData methods.
| | 00:14 | But this time instead of passing a simple object,
I'm going to use the ArrayCollection class
| | 00:19 | to hold the data that moves between the applications.
| | 00:23 | Before I show you the code, I'm
going to explain, why this works.
| | 00:27 | The ArrayCollection class implements
an interface named IExternalizable.
| | 00:32 | The rule for moving data between AIR applications using
the Clipboard is that the data object that you pass into
| | 00:38 | and get out of the Clipboard must implement this interface.
| | 00:42 | The interface is implemented not
just by the ArrayCollection,
| | 00:45 | but also by also by a class named ObjectProxy,
| | 00:48 | which wraps an object in the same way
that an ArrayCollection wraps an Array.
| | 00:52 | This interface requires two methods
named writeExternal and readExternal.
| | 00:56 | These methods allow you to customize, how the data is
stored, the format of the data and other important aspects
| | 01:03 | of how the data is represented while
it's stored in memory in the Clipboard.
| | 01:07 | You can actually write your own custom
classes that implement this interface.
| | 01:11 | The exact code for that is beyond
the scope of this tutorial.
| | 01:14 | But what I want to explain here is that the reason
we can pass an ArrayCollection between a source
| | 01:20 | and a Destination Application with the Clipboard
is because it does implement this interface.
| | 01:25 | I will close the Help screen and return back to the code.
| | 01:29 | I'm using the applications RecordSetSource and
RecordSetDest, that are in the Chapter 02 project.
| | 01:35 | The source application, the code for which is on my
screen right now, starts off as the same code I used
| | 01:41 | in the last video, that is I'm currently
allowing the user to choose one row of a DataGrid
| | 01:46 | and that I'm copying that data object to the Clipboard.
| | 01:49 | In this version of the Application I'm going
to allow the users to choose more than one row.
| | 01:54 | I'll go down to the DataGrid and I will add a property
called allow multiple selection and set its value to true.
| | 02:02 | The user will now be able to click
and select more than one row,
| | 02:06 | while they hold down to Ctrl key on
Windows or the Command key on Mac.
| | 02:12 | Now I'll go back up to the method copytoClipboard,
that's adding the data to the Clipboard.
| | 02:16 | In the old version of the code, I
was passing in a single data object.
| | 02:20 | I'm going to comment out that line of code, that's
getting the data out of the DataGrid and I'll replace it
| | 02:27 | with a statement, that gets the
data out as an ArrayCollection.
| | 02:30 | It will look like this.
| | 02:32 | I will declare a local variable name of
acData and data type it as an ArrayCollection.
| | 02:39 | I will initialize the ArrayCollection as a
new object using the ArrayCollection class's,
| | 02:45 | no arguments constructor method.
| | 02:47 | Notice that when you instantiate an ArrayCollection using
this syntax, you can pass in an array as it's source
| | 02:54 | and it just so happens that the DataGrid
has a property called SelectedItems,
| | 02:59 | which returns an Array of all of
the currently selected rows.
| | 03:03 | So, I will pass in personGrid.selectedItems and now
whatever rows the user has selected will be stored
| | 03:13 | in the ArrayCollection.
| | 03:15 | Now, I'll go to the line of code that's
calling the setData method of the Clipboard.
| | 03:19 | I'll change the name of format.
| | 03:21 | I already used Custom Format to represent a single object.
| | 03:25 | Now, I'm going to use something that's more descriptive.
| | 03:27 | I'll call it simply people and then I'll change
the name of the data object that I'm passing
| | 03:32 | in from dataObj the old single object
to acData, the new ArrayCollection.
| | 03:39 | That's all of the code I need to
change in the source application.
| | 03:42 | I'll save that and go over to the Destination Application.
| | 03:46 | The Destination Application RecordSetDEST.mxml already
has a bindable variable named acPerson declared
| | 03:54 | as an ArrayCollection and the identical
DataGrid that's the source application,
| | 03:59 | which is binding to the acPerson
ArrayCollection as its data provider.
| | 04:03 | This version of the Application is
not getting its data from the sever.
| | 04:07 | Instead, It will paste the data in from the Clipboard.
| | 04:10 | Go to the Paste from Clipboard
function which is currently empty.
| | 04:13 | Make a little bit of space between the
braces and assign the value of the bindable,
| | 04:18 | variable acPerson by calling the
Clipboard.generalClipboard.getData method.
| | 04:27 | We have to match the name of the
format that we are passing in.
| | 04:31 | I'll name it People and then as I did in an earlier video,
I'm going to explicitly cast the data as an ArrayCollection.
| | 04:39 | I know that the data is coming as an
ArrayCollection because that's why I put it
| | 04:43 | into the Clipboard in the source application.
| | 04:46 | That's all of the code I need to put into this application.
| | 04:49 | The ArrayCollection is already bindable and it's already
bound to the DataGrid as its data provider and the Paste
| | 04:56 | from Clipboard function is already been called when
the user clicks the Paste from Clipboard button.
| | 05:01 | I'll save the change and run the application.
| | 05:04 | I'll also go back to Flex Builder and run the source
Application and then I'll move the applications around,
| | 05:12 | so they are sitting side by side on the screen.
| | 05:17 | Now, I'll hold down the Ctrl key,
if you are working on Mac hold
| | 05:21 | down to Command key instead and then click on Multiple rows.
| | 05:25 | I'll then click Copy to Clipboard and I will get a
verification that the data has been correctly copied.
| | 05:33 | Now, come over to the Destination
Application and click Paste from Clipboard
| | 05:37 | and you will see the data appear
in the destination DataGrid.
| | 05:41 | In the current version of the Destination Application each
time I select new data in the Source Application and copy it
| | 05:48 | and then come back over to the destination
and paste, I'm replacing the existing data.
| | 05:53 | I could easily refactor the Destination
Application to add Data incrementally if I so chose.
| | 05:59 | There is one another thing I would like to
show you in the Destination Application.
| | 06:03 | It's a good idea in the Destination Application, before you
would retrieve data from the Clipboard to first make sure
| | 06:10 | that the correct format is stored in the Clipboard.
| | 06:14 | We can do this using a method of the
generalClipboard object named hasFormat.
| | 06:19 | I'm going to go back to the Paste from
Clipboard function and add a conditional clause.
| | 06:24 | If Clipboard.generalClipboard.hasFormat and then I
will pass in the name of the format I'm looking for
| | 06:35 | and then I will put it in a code
block and I will move the code
| | 06:42 | that retrieves the data from the
Clipboard into the code block.
| | 06:48 | I'll reformat the code a little bit for readability and
now I will only be retrieving data from the Clipboard
| | 06:55 | if in fact the data is given in the correct format.
| | 06:57 | There is also a property called formats which
returns an array which is in an ordered list of all
| | 07:03 | of the formats in which data is currently stored.
| | 07:06 | Remember that the Clipboard is able to
store multiple formats at the same time.
| | 07:10 | When you use the Clipboard to move data either
between AIR Applications or from the operating system
| | 07:15 | into an AIR application, it's always
a good idea to make sure
| | 07:18 | that the format is already there
before you try to retrieve the data.
| | 07:22 | I'll run the Application one more time just
to make sure that the code still works.
| | 07:27 | I'll try to paste from the Clipboard
and you will see that nothing happens.
| | 07:34 | Now come back to the Source Application and run it again.
| | 07:40 | I'll select multiple rows, copy it to the Clipboard,
| | 07:45 | go back to the Destination Application
and paste and there is the result.
| | Collapse this transcript |
| Transferring images in the Clipboard| 00:00 | In this video, I'm going to describe, how to use the
system clipboard to copy an Image in BitmapData format
| | 00:06 | to the clipboard, so that you can then retrieve or paste it
| | 00:10 | from within any graphic sensitive
application in the operating system.
| | 00:14 | I will be using an application in the
Chapter 02 project named TransferImage.mxml.
| | 00:20 | I have the application opened on the screen right now
and I will show that it's a very simple application
| | 00:26 | that has a single Image control displaying
a JPG file called yosemitefalls.jpg.
| | 00:32 | There is an existing copyToClipboard function
which clears the clipboard and alerts the user
| | 00:37 | that the Image has been copied, but I will need to
add code to actually move the data into the clipboard.
| | 00:43 | I will run the application so we can see what it
looks like before I do the coding and you will see
| | 00:48 | that it simply displays the image
and displays a Copy button.
| | 00:54 | In order to copy data to the clipboard in
Image format, you have to first turn the Image
| | 00:59 | into something called a BitmapData object.
| | 01:02 | The BitmapData object, is an actual ActionScript
class which you can instantiate very simply.
| | 01:08 | I will declare a variable named bd standing for BitmapData
| | 01:13 | and I will instantiate it with
the class's constructor method.
| | 01:17 | Notice that the constructor method accepts two
required properties the width and the height.
| | 01:23 | I will get those values dynamically
from the existing Image object.
| | 01:27 | I will pass in myImage.width and
myImage.height and that will ensure
| | 01:37 | that the BitmapData object's dimensions
match the dimensions of my Flex image object.
| | 01:43 | Next, I will pass the actual image into the BitmapData
object like this, I will call it the bd.draw() method,
| | 01:51 | you pass a source into the BitmapData object and
you can use an image object in this location.
| | 01:58 | So I have now taken the Image object, I have
constructed a BitmapData object of the correct dimensions
| | 02:04 | and I have drawn the BitmapData object
based on the contents of the Image object.
| | 02:09 | Now, I'm ready to pass the data into the clipboard.
| | 02:13 | I will add a statement that calls the
Clipboard.generalClipboard.setData method
| | 02:19 | and I will pass in a format.
| | 02:21 | I will use one of the built-in formats
from the ClipboardFormats class.
| | 02:28 | The name of this format is Bitmap Format and
it's a format that requires a particular type
| | 02:33 | of data specifically a BitmapData object and
then I will pass in the actual BitmapData object
| | 02:40 | in the second argument and close the method.
| | 02:44 | I will Save the change and the Run the
application, I once again see the Image displayed
| | 02:49 | and I will click the Copy button and get the message
that the Image has been copied to the clipboard.
| | 02:55 | Now I can use any Graphics application
that allows me to Paste from the clipboard.
| | 03:00 | I'm going to demonstrate this using Fireworks.
| | 03:04 | In Fireworks, you can create a brand new Image file and when
you do this, it will automatically pick up the dimensions
| | 03:09 | of any Image that's in the clipboard and
propose that as the new size of the image.
| | 03:15 | From the Menu I will select File, New and notice that the
Width and Height of 320 by 240 Pixels and the Resolution
| | 03:23 | of 72 Pixels/Inch, match the source file
that I just copied to the clipboard.
| | 03:28 | I will click OK and now I will right click and Paste
and you will see that the Image was transferred
| | 03:36 | from the AIR application into the system clipboard
and from there into my Graphics application.
| | 03:42 | Now if you don't have Fireworks, you should still
be able to do this with many graphics application.
| | 03:48 | For instance I will open up Paint, which is a standard
graphics application that comes with all copies of Windows
| | 03:54 | and I will Paste or press Ctrl+V and once again
you will see the Image pasted into the application.
| | 04:00 | So this a very simple way of getting Image data from an AIR
application out into the general operating system clipboard,
| | 04:08 | so that it can then be pasted into other graphics
applications without having to save the file to disk
| | 04:13 | and then exclusively retrieve it and then
copy and paste within the native application.
| | Collapse this transcript |
| Deferred rendering| 00:00 | In this video, I'm going to describe how to
use a feature of the ActionScript clipboard,
| | 00:05 | that allows you to defer the creation or
the rendering of data until the moment
| | 00:09 | when a Destination Application requests it.
| | 00:12 | I will be working in two applications I have used
previously, ObjectSource and ObjectDest and I'm going
| | 00:18 | to make some changes in the Source Application that
defer provision of data to the clipboard until the moment
| | 00:24 | when the Destination Application tries to retrieve it.
| | 00:27 | I will open up ObjectSource.mxml to full
screen, so we can see as much code as possible
| | 00:32 | and then I will go down to the code section.
| | 00:36 | Right now, when the user clicks the Copy button,
we are copying directly into the clipboard.
| | 00:41 | Whichever row of the DataGrid, you have
selected at the moment, they clicked the button,
| | 00:44 | will be the data that's retrieved
in the Destination Application.
| | 00:48 | To use the deferred creation capability, create a function
that returns the data you want to place in the clipboard.
| | 00:55 | I will simply call it getData and I will
data type the return value as an Object.
| | 01:02 | In the body of the function, I will return
the currently selected row from the DataGrid.
| | 01:13 | Now, I'm going to modify the copyToClipboard
function in a couple of ways.
| | 01:17 | I'm no longer going to retrieve the data from
the DataGrid, I'm going to clear the clipboard,
| | 01:23 | but then instead of directly passing
data into the clipboard,
| | 01:27 | I'm going to call a function called setDataHandler.
| | 01:31 | The setDataHandler function takes two required arguments,
the Format name which can stay the same and then a reference
| | 01:38 | to the function that should be called, when
the data is requested that will be getData.
| | 01:44 | Now when the user clicks the Copy button, it will
simply register the call back function getData
| | 01:50 | and then when the Destination Application
retrieves the data from the clipboard
| | 01:54 | that will cause this function to be called instantly.
| | 01:57 | I will save the changes and run the application
and then I will go back to Flex Builder
| | 02:04 | and run the Destination Application as
well and I will arrange the application,
| | 02:10 | so we can see both of them on the screen at the same time.
| | 02:14 | Now I will click into a row and click Copy to Clipboard and
I get a message that the data has been copied to clipboard.
| | 02:22 | But then I will select another row of data.
| | 02:24 | I will move the cursor to James Jaeger instead of Brad Lang,
then I will go to the Destination Application and Paste
| | 02:32 | and notice that I pasted the data
that's currently selected rather
| | 02:36 | than the data was selected at the
moment I clicked the button.
| | 02:39 | Notice something interesting about this feature,
if I go over back to the Source Application
| | 02:44 | and then I immediately try to Paste
again, I simply get the same data again.
| | 02:49 | You can only call the function once for each time the
setDataHandler method is called in the Source Application.
| | 02:56 | But if I click the button and then select an entirely
different row, then go to the Destination Application again
| | 03:04 | and Paste, I once again get the currently
selected data rather than the data
| | 03:09 | that was selected at the moment the button was clicked.
| | 03:11 | So this is called deferring of
creation or rendering of data.
| | 03:15 | Instead of pushing data directly into the
clipboard, you simply tell the clipboard object,
| | 03:21 | when the data is requested, this is
the function that should be called
| | 03:25 | to determine, what type of data and value is returned.
| | Collapse this transcript |
|
|
3. Creating Drag-and-Drop InterfacesUnderstanding drag-and-drop interfaces| 00:00 | In this chapter of the video series, I'm going to describe,
how to implement drag and drop operations that allow you
| | 00:06 | to move data between AIR applications and between
an AIR application and the hosting operating system.
| | 00:12 | If you are following along with the exercises,
you can work along in these exercises
| | 00:16 | by importing a project from your exercises folder.
| | 00:19 | Go to the Flex, go to Menu and select File,
Import, Flex Project, browse for an Archive File,
| | 00:29 | go to the Chapter03 folder in the Exercises area
| | 00:33 | and select Chapter03BeginProject.zip,
click Finish and Import the Project.
| | 00:42 | Then open the Project in the Flex Navigator view, go to
the Source folder and open the file FlexDragDrop.mxml.
| | 00:51 | In this video, I'm going to show a simple approach
to doing drag and drop within a Flex application,
| | 00:58 | using tools that are available whether you are building an
application for deployment over the web or to the desktop.
| | 01:04 | I will maximize the Editor to see as much code as
possible and show you that this application retrieves data
| | 01:10 | from a server and then displays it in a DataGrid.
| | 01:14 | There are two DataGrid controls
in this application side by side.
| | 01:17 | I will run the application to show what it looks like,
the data appears initially in the first DataGrid,
| | 01:24 | we want the user to be able to click and drag data
from the first DataGrid to the second DataGrid.
| | 01:29 | In Flex applications, you can implement
drag and drop very simply.
| | 01:35 | If your Drag and Drop Initiator and your
Drag and Drop Target are both list controls.
| | 01:41 | The DataGrid for instance is one of the
list controls that supports this feature.
| | 01:45 | If you want to be able to drag and drop data from a
list control, simply add a property called dragEnabled
| | 01:53 | and set it's value to true, then go to the
control that you want to use as the drop target
| | 02:00 | and add a dropEnabled property and
set it's value to true as well.
| | 02:05 | Save your changes and Run the application.
| | 02:13 | Once the data appears in the first DataGrid, you
should now be able to click on any row, drag it,
| | 02:18 | you will see a little image of the selected row up here
and when you move the cursor into the drop target DataGrid
| | 02:26 | and release the mouse button, the data
is copied from one DataGrid to the other.
| | 02:31 | I will demonstrate that again with the second
record and a third and I will also show you
| | 02:37 | that using this automated drag and drop feature,
you can actually place data in specific locations
| | 02:43 | by paying attention to the selector
bar that appears in the DataGrid.
| | 02:46 | If you want to be able to drag and drop
multiple items, simply go the Initiator DataGrid
| | 02:52 | and set it's allowMultipleSelection property to true, from
the application again and this time hold down the Ctrl
| | 03:00 | or Command key, depending on which operating system
you are working in and click and select multiple rows,
| | 03:06 | then release the Command or Ctrl key, click on one
of the selected items and drag and you will see
| | 03:12 | that you are actually moving multiple
rows into the Target DataGrid.
| | 03:17 | There is a more advanced and more powerful architecture
for creating drag and drop within a Flex application,
| | 03:22 | using a class called the DragManager, but
that's not the subject of this video series.
| | 03:27 | We are interested here in what you can do with drag
and drop in AIR application in terms of moving data
| | 03:33 | between multiple applications and also moving data back and
forth between an AIR application and the operating system.
| | 03:40 | So that will be the focus of the
rest of these videos in this chapter.
| | Collapse this transcript |
| Accepting native dropped data | 00:00 | In this video, I'm going to describe how to accept
a Native Drag and Drop operation, where the drag
| | 00:06 | and drop operation is initiated by some other
non-AIR application hosted by the operation system.
| | 00:12 | I will be working in the application NativeDragDrop.mxml,
that's a part of the Chapter03BeginProject.
| | 00:19 | If you are following along in the
Exercises, open that application now.
| | 00:23 | This is a simple application with two labels, one that
will be a static label with the text of Drop text anywhere!
| | 00:30 | and the other that's a targetLabel.
| | 00:33 | They both have a fontSize of 12, the second
label doesn't have an initial text value,
| | 00:38 | we will be filling in that value upon text being dragged and
dropped into the application from an external application.
| | 00:45 | To get started, go to the application's
root element, WindowedApplication
| | 00:50 | and add an event listener for an
event called nativeDragEnter.
| | 00:56 | When the mouse cursor enters the application during a Drag
and Drop operation initiated by any other application,
| | 01:03 | this event will tell you that a
Drag and Drop operation is pending,
| | 01:06 | you will react to that by passing the generated
event object to an event handler function.
| | 01:12 | We will call it dragEnterHandler
and we will pass the event object,
| | 01:19 | then go down to your Script section
and create that function.
| | 01:28 | The function receives an event object
typed as a class named NativeDragEvent
| | 01:35 | and as with all good event handler functions, returns void.
| | 01:39 | Within the dragEnterHandler function,
I'm first going to add a trace command
| | 01:43 | to tell me that the DragEnter event happened.
| | 01:47 | Within the Trace function I will put in a simple literal
string of Drag enter event and then I will test this
| | 01:56 | by saving and running the application
in Debug mode and then I will open
| | 02:01 | up another application that's capable
of dragging and dropping text values.
| | 02:05 | On Windows, you can use WordPad, on Mac you can use TextEdit
| | 02:09 | or any other text editor that's capable
of initiating a Drag and Drop operation.
| | 02:14 | Now I will select some text and drag it into the application
and then in the console in the background you will see
| | 02:21 | that every time the cursor moves over the AIR application,
the trace command is executed and this tells me
| | 02:28 | that in fact I'm successfully detecting,
when the DragEnter event occurs.
| | 02:33 | So, now I will close the application and return to the code.
| | 02:38 | In order to accept the event, you will
use a class named NativeDragManager.
| | 02:45 | The NativeDragManager class has
a method named acceptDragDrop,
| | 02:50 | you pass into it what we call the target object.
| | 02:54 | In a Flex application, you can usually refer to this meaning
the application itself and that tells the Flex application
| | 03:01 | that if the user releases the mouse
button, while the cursor is
| | 03:05 | over the application then will
accept the drag and drop event.
| | 03:09 | Now we need to handle that event.
| | 03:11 | When the user releases the mouse cursor, we will get an
event named nativeDragDrop and once again we will listen
| | 03:19 | for the event and handle it with an event handler
function, which I will call dragDropHandler.
| | 03:26 | I will once again go down to the
script section and create that function
| | 03:31 | and I will receive once again an
event object typed as nativeDragEvent.
| | 03:40 | Within the dragDropHandler, I will retrieve the data
| | 03:44 | from the clipboard object that's a
part of the drag and drop architecture.
| | 03:48 | I will assign the written value to the label
control that I already declared targetLabel.
| | 03:53 | So I will start off with
TargetLabel.txt=event.clipboard.getData,
| | 04:01 | this is exactly the same getData function that I showed how
to use in the previous chapter about using the clipboard.
| | 04:09 | I have pass in a format name to designate what
kind of data I want to retrieve and once again,
| | 04:15 | as with standard clipboard operations, I will use the
ClipboardFormat class and its Text_Format constant.
| | 04:23 | I also need to specifically type cast the value that's
returned from the getData method using as String.
| | 04:30 | As I described in the previous chapter about the
clipboard the getData method expects to return an object.
| | 04:37 | If you know you are receiving the data in the
form of some other class, you need to say so.
| | 04:41 | I will save my changes and run the application, then
once again I will go over to my initiator application,
| | 04:49 | I'm using WordPad and I will drag and
drop the text into the application.
| | 04:54 | Notice the cursor shape changes as soon as I
accept the operation and when I drop the data,
| | 05:00 | it's placed into the application and my code retrieves the
data from the clipboard and displays it in the targetLabel.
| | 05:07 | I can do this as many times as I like, I will
type in another phrase in the TextEditor,
| | 05:14 | select it and drag and drop it into the application.
| | 05:18 | So you will see that each time the initiator places
data into the clipboard and then I accept the Drag
| | 05:24 | and Drop operation and react to the
drop event I'm able to get the data out.
| | 05:29 | In the next video, I will show you how to do
something very similar using a special kind
| | 05:34 | of clipboard format called a File List.
| | Collapse this transcript |
| Dragging and dropping file references| 00:00 | In this video, I'm going to describe how to use the
drag and drop native interface to move file references
| | 00:06 | from the operating system into an AIR application.
| | 00:09 | I will be describing the use of references to
files much more thoroughly in a later chapter,
| | 00:13 | all about access to the local file system.
| | 00:16 | For now, what's important to understand is that
when the user initiates a drag and drop operation,
| | 00:21 | from an application, that's native and hosted in the
operating system and drags a file into your AIR application,
| | 00:29 | that's a Native Drag and Drop operation where
the format is something called File List.
| | 00:34 | To demonstrate this capability, I will be using
an application named DragFileReferences that's
| | 00:39 | in your Chapter03Begin folder.
| | 00:41 | If you are following along in the
exercises, open the file now.
| | 00:45 | You will see that this application is already
listening for the event nativeDragEnter
| | 00:50 | and nativeDragDrop that I demonstrated in a previous video.
| | 00:54 | There is a label with a text value of Photo Gallery
and a Tile container, which will layout objects in rows
| | 01:01 | and add as many rows as it needs to
display the contents that I will be adding.
| | 01:06 | I will run the applications so we can see the initial
interface and you will see that the tile is represented
| | 01:12 | by the rectangular white area with the black border.
| | 01:16 | When the user drags an image file into the application,
I'm going to display the image in the Tile container
| | 01:23 | by detecting the Drag and Drop operation and getting the
File Reference that was dragged into the application.
| | 01:30 | I will close the application and return to the code.
| | 01:32 | if you are following along with me, place
the cursor in the dragEnterHandler function,
| | 01:38 | notice that if it receives an event
object typed as the NativeDragEvent class.
| | 01:43 | The first step is to detect whether the
clipboard that's associated with the Drag
| | 01:48 | and Drop operation contains the File List format.
| | 01:51 | I will put in a conditional clause that's looks like this,
if event.clipboard.hasFormat then as in previous exercises,
| | 02:02 | I will use the ClipboardFormats class as
constants to indicate which format I'm looking for.
| | 02:09 | I'm looking for this format, File_List_Format.
| | 02:12 | I will close the conditional block with a couple of
ending parenthesis and put in the braces that will serve
| | 02:19 | as the code block for this conditional clause.
| | 02:22 | If the event object's clipboard has the appropriate format,
| | 02:26 | I will use the NativeDragManager class's acceptDragDrop
function and pass in reference to the application
| | 02:35 | to indicate that I will accept the Drag
Drop Operation targeting the application.
| | 02:39 | Now once the user drags the object into the application,
the cursor shape will change to indicate to the user,
| | 02:46 | that they are allowed to drop the object.
| | 02:49 | I will demonstrate that behavior.
| | 02:51 | I will run the application.
| | 02:54 | Now I'm going to move the application over to the side
and then resize Flex Builder, so it's only showing part
| | 03:00 | of the screen and bring back the Flex Navigator view.
| | 03:05 | Notice in this project there is an images
folder, which contains some graphic files.
| | 03:10 | The Flex Navigator view essentially exposes the behavior
of the Operating System's File Management System.
| | 03:17 | Window's Explorer and Windows or Finder on the Mac.
| | 03:20 | When I click and drag an object out of the
file list and move it into the AIR application,
| | 03:27 | as I move the cursor out of the File List and into the
AIR application, notice that the cursor graphic indicates
| | 03:33 | through the plus(+) icon, that I'm
now allowed to drop the object.
| | 03:38 | That's the result of calling the acceptDragDrop function.
| | 03:41 | I'm ready now to accept the drop action, I will
close the application and return to the code,
| | 03:48 | and show it in full screen, so that we
can see as much of the code as possible.
| | 03:52 | In the dragDropHandler function the first step
is to get the data out of the event object.
| | 03:59 | I'm going to declare a variable called arFiles typed
as an array and I will set the value of that Array
| | 04:06 | from this expression, event.clipboard.getData, then
I will pass in the format name I'm looking for,
| | 04:15 | as before I will use the constant
ClipboardFormats.FILE_LIST_FORMAT and then close that part
| | 04:20 | of the expression with a closing parenthesis and
explicitly data type the value that's returned as an Array.
| | 04:27 | The nature of the data that's stored in the clipboard
as File List is that it's an array of file objects.
| | 04:34 | Each file object in the Array has a property called
nativePath, which returns the location of the file
| | 04:40 | on the local disk, starting from the root folder.
| | 04:44 | To get that value out, I will create another variable called
fileLocation typed as a String and I will get that value
| | 04:53 | from arfiles, I will look for the first item because
I know I'm only dragging a single item for the moment
| | 05:00 | and then I will put in the property nativePath.
| | 05:04 | We will learn more about the nativePath property in the
later chapter about accessing the local file system.
| | 05:10 | Next I will create an image object, I will
declare a variable named img typed as an Image.
| | 05:18 | Notice that as I selected the Image
class from the list of available classes,
| | 05:22 | an import statement was automatically created by
Flex Builder at the top of the Script section.
| | 05:28 | Continuing that line of code, I will instantiate the
image object by calling it's no argument constructor
| | 05:35 | and I will set the Image object's source.
| | 05:38 | When you set the source of an Image
object using the local file system,
| | 05:42 | you should always prefix the actual
file location with a prefix of file:///.
| | 05:49 | If you forget this step, things will work fine on Windows,
| | 05:54 | but on the Mac the image will probably
not show up correctly.
| | 05:57 | So I'm going to set the source property of the Image object
with file:/// and then append the fileLocation property,
| | 06:06 | I could have written this syntax a lot more concisely,
combining these statements into single statements,
| | 06:12 | but I want you to see each step
of the process along the way.
| | 06:15 | I extract the array of files out of the event
object's clipboard using the getData method,
| | 06:20 | I will get the file location from the nativePath
property of the first file in the array,
| | 06:26 | I instantiate an Image object and I set its source.
| | 06:31 | Finally, I will add this image object to
the Tile that I have already declared,
| | 06:35 | using the syntax imageTile.addchild
and I will pass in the Image object.
| | 06:41 | I don't need to retain a reference to that Image
object, this is only for displaying the image once.
| | 06:46 | I don't for instance need to be able to
remove the Image object from the Tile,
| | 06:50 | later on in the current application, that's all of the code.
| | 06:54 | Now I will run the application, I will once again move
the application over to the right side of the screen,
| | 07:01 | restore the size of Flex Builder and
then look at the Flex Navigator view
| | 07:06 | and I will drag an image into the application.
| | 07:09 | This time when I drop the image,
the image is added to the Tile.
| | 07:13 | I can continue this operation as many times as I want to.
| | 07:17 | The nature of a Tile container, is
that each time I add a new image in,
| | 07:21 | it's going to create additional rows as needed.
| | 07:25 | Each of the cells within the Tile
has to be of exactly the same size.
| | 07:29 | There might be a little bit more work to do
to make this a little bit more attractive,
| | 07:33 | but you can see that the functionality is working correctly.
| | 07:36 | You can drag images from any application
that knows how to provide a File List.
| | 07:41 | Another application that knows how to provide
a File List is in fact Windows itself.
| | 07:46 | I will go to the Exercises folder that's on my local
system, I will go to the Assets folder, to images,
| | 07:54 | to thumbs and from there I can drag and drop directly from
the operating system, I will select this one, crawfish.jpg,
| | 08:02 | once again drag into the application and there is the image
and I can keep doing that with as many images as I like.
| | 08:10 | So that's a look at how to use Native Drag and Drop
to move File References from the operating system
| | 08:16 | or from applications that know how to
provide this kind of drag and drop capability
| | 08:20 | and to move those File References into an AIR application.
| | Collapse this transcript |
| Initiating native drag-and-drop| 00:00 | In this video, I'm going to describe how to initiate a Drag
and Drop operation from an AIR application that allows you
| | 00:06 | to transfer data from an AIR application
to another AIR application
| | 00:10 | or to any other application running in the operating system.
| | 00:14 | For this demonstration, I'll use an
application file named DragOut.mxml.
| | 00:19 | If you are following along with the exercise files, you
will find this file in the Chapter 03 Begin Project.
| | 00:25 | Open the file and then expand the Code to full screen.
| | 00:29 | In the beginning version of the application,
there is a simple Label and Image.
| | 00:33 | The image control is displaying a
graphic called yosemitefalls.jpg.
| | 00:37 | It's listing for the mouse down event, and when the
user clicks the mouse button while it's over the image,
| | 00:43 | it will call the startDragDrop
function, that's already been defined.
| | 00:47 | Place your cursor within the function.
| | 00:49 | The first step in transferring the Bitmap graphic to
another application, that can accept Bitmap data in a Drag
| | 00:55 | and Drop Operation is to transfer the image
controls data to a Bitmap data object.
| | 01:01 | I'll declare a new variable named
BD and data type it as BitmapData.
| | 01:08 | I'll initialize that using the
BitmapData classes constructor method,
| | 01:13 | and I'll pass in the two required values, the Width
and Height getting them from the image control myImage.
| | 01:25 | Next, I'll fill in the BitmapData by calling it
Draw Method, and I'll pass in the image control,
| | 01:32 | and that will transfer the image control's
BitmapData over to this new object.
| | 01:37 | In the previous chapter about the Clipboard, I only used
the Clipboard Classes, General Clipboard Static Property,
| | 01:44 | referring to the singleton instance of the system clipboard.
| | 01:47 | When you do a Drag and Drop operation, you don't use the
system clipboard, instead you create a single instance
| | 01:53 | of a clipboard object, and then you push the data
into that clipboard object and that's the clipboard
| | 01:59 | that you'll pass around with the Drag and Drop operation.
| | 02:02 | So my next step is to create a new
variable data typed as a Clipboard.
| | 02:06 | I'll name it Clip.
| | 02:07 | And I will set its data type as Clipboard, and initialize
it using the clipboard classes no arguments constructor.
| | 02:16 | Now, just as I did with the general
clipboard in previous exercises,
| | 02:20 | I'll call it the clipboard objects set data
method, and I'll pass in a format name.
| | 02:26 | The name of this format will be one of the five
standard formats in the clipboard formats class.
| | 02:31 | I will select ClipboardFormats.BITMAP_FORMAT, and then
I'll pass in the data object BD and close the method call.
| | 02:41 | My next step is to initiate the Drag and Drop operation.
| | 02:44 | For this purpose, I use the NativeDragManager
class and it's doDrag Method.
| | 02:49 | The doDrag method takes a number of arguments,
some of which are required and some optional.
| | 02:53 | The first two arguments that are required are
the Drag Initiator and the Clipboard Object.
| | 02:58 | The Drag Initiator for this application will be the
application itself, which I'll refer to as this.
| | 03:04 | Next, I pass in the Clipboard Object that contains the data.
| | 03:08 | I named it Clip previously, and then optionally, you
can add a drag image which is a BitmapData object,
| | 03:15 | which is a graphical presentation that the
user sees as the mouse moves across the screen.
| | 03:20 | I have already created a BitmapData object
that represents the image I'm moving.
| | 03:24 | So I'll pass that in this position as well,
making another use of that same object.
| | 03:29 | That's it.
| | 03:30 | Here are the steps I followed again.
| | 03:32 | I have created the BitmapData Object, and
filled in its data from the Image Control.
| | 03:36 | I have constructed a Clipboard Object and
filled in its data using the Set Data Method,
| | 03:42 | and then I have initiated the Drag and Drop operation
using the Native Drag Manager's Do Drag method,
| | 03:48 | passing in reference to the Initiator, the
Application, the Clipboard Object which I named Clip,
| | 03:53 | and the BitmapData Object which I'm using as the image
the user sees as they move the cursor across the screen.
| | 04:00 | Here's the visual result.
| | 04:02 | I run the application, and now as I
Click and start to move the cursor,
| | 04:07 | you will see a copy of the image show up on the screen.
| | 04:10 | Notice that it's slightly transparent.
| | 04:12 | I can see through the top level image that's being used to
represent the Drag Operation, and see the background image.
| | 04:19 | Now, as you move the image out of the AIR
application, you will see the image goes away.
| | 04:25 | That's because the other applications
aren't capable of displaying it.
| | 04:28 | That's okay though.
| | 04:30 | Now, I'm going to show you some of the things
you are able to do as you drop the image.
| | 04:34 | If you have an Image Manipulation Application,
that's capable of accepting this sort
| | 04:38 | of Drag and Drop operation, you can start it up.
| | 04:42 | For instance, I'm a fan of Adobe Fireworks.
| | 04:44 | Fireworks is one of those applications that's
capable of receiving a Drag and Drop operation.
| | 04:50 | If you have Fireworks, open it up.
| | 04:53 | You can also try any other graphical editing
application you like such as Photoshop.
| | 04:58 | Although, not all applications are able to do this.
| | 05:00 | For instance, if you were to try using Paint, the very
simple graphical application that comes with Windows,
| | 05:06 | you would find that would not accept
the Drag and Drop operation correctly.
| | 05:09 | I'll create a new file in Fireworks, then
I'll switch back to my AIR application,
| | 05:18 | and I'll try dragging the graphic into the application.
| | 05:21 | And you will see that it successfully transfers
the BitmapData over to the graphical application.
| | 05:27 | You can also try this if you are working on the
Mac, dragging the image directly to the Mac desktop.
| | 05:33 | You will see that the image is dragged onto the desktop,
and it's created something called a Picture Clipping.
| | 05:39 | If you are not working on the Mac, and you don't have
any great applications that are able to accept this kind
| | 05:44 | of operation, here's another application
that's in the Chapter 03 Project.
| | 05:49 | Open the application BitmapTarget.mxml.
| | 05:53 | Take a look at its code.
| | 05:54 | In this application, we first have a dragEnterHandler
function that detects whether there is a Bitmap format
| | 06:01 | in the clipboard, that's being transferred to
it, and then it accepts the Drag Drop operation.
| | 06:08 | Within the dragDropHandler function, we are calling
the getData function, we are passing in Bitmap format
| | 06:15 | as the format name, and we are extracting
the data as a BitmapData object.
| | 06:20 | Then, we are constructing an instance of a class
called Bitmap wrapped around the BitmapData.
| | 06:24 | And finally, I'm calling the stage object
addChild method to add the Bitmap to the stage.
| | 06:31 | I'll run the application, and then I'll position
over it on the right side of the screen,
| | 06:36 | go back to the DragOut application, position it on the
left side of the screen, so I can see both applications.
| | 06:42 | And then, I'll Click and Drag the image from the first
application, drop it into the second application,
| | 06:51 | and you will see that it's successfully
being dropped in the target application.
| | 06:55 | So again, you are not limited to dragging
and dropping just between AIR applications.
| | 07:00 | When you initiate a Native Drag and
Drop operation from an AIR application,
| | 07:04 | that data can be moved into any other application hosted
by the operating system, that's capable of supporting
| | 07:11 | that particular kind of Drag and Drop operation.
| | Collapse this transcript |
|
|
4. Using the File SystemUnderstanding file system access in AIR| 00:00 | In this chapter of the video series, I'm
going to describe how applications deployed
| | 00:04 | on the Adobe Integrated Runtime can access the
local file system and create, read and write files,
| | 00:11 | and also create and manipulate directories.
| | 00:15 | All applications deployed on AIR whether they
are built in Flex, Flash or Ajax have the ability
| | 00:20 | to read and write to the local file system.
| | 00:23 | This is because applications deployed as native
applications on the operating system aren't subject
| | 00:28 | to the same security rules as applications
deployed through a web browser.
| | 00:32 | When a Flex application is downloaded to the
web browser and hosted by the Flash player.
| | 00:37 | It's only allowed to operate within the web
browser Sandbox and is not allowed to reach outside
| | 00:42 | and touch the file system, local databases or printers.
| | 00:46 | Applications installed locally can do all these things.
| | 00:50 | When you work with the local file
system, one of the choices you will need
| | 00:53 | to make is whether you work synchronously or asynchronously.
| | 00:57 | I'll talk about this concept in more detail in
later videos, but briefly all file operations have
| | 01:03 | to be handled either synchronously or asynchronously.
| | 01:06 | When you handle a file operation synchronously such as
reading or writing data, the application thread is suspended
| | 01:13 | for as long as the file operation is being executed.
| | 01:16 | Here's what this means to an AIR application.
| | 01:18 | The Adobe Integrated Runtime has multiple threads, but only
one thread that's dedicated to the front-end application.
| | 01:25 | If you use synchronous file operations, any
operations in the application itself such as animations
| | 01:31 | or user interactions are suspended
while the file operation is happening.
| | 01:36 | If you are reading or writing a large amount of data,
| | 01:38 | this can result in the application becoming
temporarily unavailable to the user.
| | 01:43 | So whenever you execute file operations,
that might take more than an instant.
| | 01:47 | You should always use asynchronous operations instead.
| | 01:50 | The nature of an asynchronous operation is that
it executes the file operation in the background.
| | 01:56 | The front-end application thread is still available
to execute animations and receive user interactions.
| | 02:02 | And whenever the asynchronous file operation is
complete, it will dispatch an event that reports to you
| | 02:08 | that the operation is complete and you can react.
| | 02:11 | All of this is made capable by
certain Key ActionScript classes.
| | 02:16 | The file class is designed to represent a single
file or directory in the local file system.
| | 02:21 | The file class executes tasks such as
copying, moving and deleting files,
| | 02:26 | and also has tools for browsing the local file system.
| | 02:29 | When you use the file class to browse, you
see the operating system's browsing interface.
| | 02:34 | For example Windows Explorer's browsing dialog
or on Mac OS X, the finder's browsing interface.
| | 02:41 | The other Key ActionScript Class is the FileStream.
| | 02:44 | This class is responsible for reading and writing
data to the local file system, and it can read
| | 02:49 | and write with multiple modes including
UTF or Unicode text or Binary Streams.
| | 02:56 | All of these abilities and rules
apply to all AIR applications,
| | 02:59 | regardless of whether these applications
are built in Flex, Flash or Ajax.
| | 03:04 | Flex developers however get some extra tools.
| | 03:07 | There is a set of components based
on the Flex List Controls.
| | 03:11 | The ComboBox, DataGrid, List and Tree controls have been
re-purposed into file system versions of the same controls.
| | 03:19 | Whereas the Base List Controls deal with data in the form
of array collections or XML list collections typically.
| | 03:26 | The file versions of these controls get their data directly
from the file system, and they allow the user to navigate
| | 03:32 | and select files and directories
from the file system visually.
| | 03:36 | There is also a special component called the
FileSystemHistoryButton that I'll be describing later.
| | 03:41 | This button gives you a very easy way of linking into the
data provider for a list control or a DataGrid control
| | 03:48 | and letting the user move forward and back
through the directory and file selections.
| | 03:53 | So in the following videos, I'll
demonstrate many of these capabilities.
| | 03:57 | The ability to represent and manipulate files and
directories on the file system, to copy, move,
| | 04:01 | and delete these files, to select the files using
the browsing interface or using the Flex components,
| | 04:08 | and the ability to read and write data
to files that are on the local system.
| | Collapse this transcript |
| Using directory aliases and the File class| 00:00 | In this video, I'm going to describe the use of the
ActionScript File Class, that points to individual files
| | 00:06 | or directories within the local file system.
| | 00:08 | For all of the demonstrations in this chapter, I'll be
working from a project that's part of the exercise files.
| | 00:14 | If you are following along with the exercises, go to
Flex Builder Menu and select File, Import, Flex Project.
| | 00:24 | Click the Browse button next to Archive
file and select Chapter04BeginProject.zip.
| | 00:31 | Notice that there is also a Chapter04EndProject.zip
| | 00:34 | that contains the completed source
code for all of these demonstrations.
| | 00:39 | Select the File and then click the
Finish button to Import the Project.
| | 00:45 | Next, go to the Flex Navigator, View and open
the Project and then open it's Source folder.
| | 00:52 | You will find a number of applications that are ready to
use, then locate the applications, DirectoryAliases.mxml
| | 00:59 | and double-click it to open it in the Editor.
| | 01:02 | If the application opens in Design view click
the Source button to look at it in Source view
| | 01:06 | and then I'll maximize my Editor, so
I can see as much code as possible.
| | 01:10 | This is a very simple beginning
application that has a button
| | 01:14 | which when clicked calls a function, called testAliases.
| | 01:18 | Place the cursor inside the function
and you will be ready to start coding.
| | 01:22 | In order to represent a file or a directory on disk,
you create an instance of the ActionScript File Class.
| | 01:28 | As with all variables you can name
the variable anything you want.
| | 01:33 | In this case, I will declare a local variable to
the function named f and data type it as a file.
| | 01:39 | Notice that you don't need an Import
statement to address the File Class.
| | 01:43 | Now, I will instantiate the File Class by
calling the Classes Constructor Method.
| | 01:48 | When you create a new File object,
you can pass in an initial path.
| | 01:53 | The path is a string value, which can point
either to a particular file or a directory on disk
| | 01:59 | or to a directory file that hasn't yet been created.
| | 02:02 | For this first example, I'm going to
pass in a simple String of file:///.
| | 02:08 | This is a special prefix that's
used in the AIR applications,
| | 02:14 | that addresses the root directory of the current volume.
| | 02:17 | On Windows for instance, if I'm working on the C drive, it
would address the C drive root, on Mac it would do the same.
| | 02:24 | Now to determine what the current
File object is pointing too.
| | 02:28 | I'm going to trace a property of the
File object called the nativePath.
| | 02:32 | The nativePath property of the
File object returns a string value.
| | 02:37 | It's the location of the file or directory represented
by this object, starting from the volume root.
| | 02:43 | I'll save my changes, and now I'm
going to Debug the application.
| | 02:49 | Notice in the background I can see the Flex Builder console.
| | 02:52 | When I click the button, I'll create an
instance of the File object pointing to file:///
| | 02:58 | and then I'll trace the actual location
from its nativePath and you will see
| | 03:04 | that the nativePath value returns a simple backslash ().
| | 03:07 | If you are working on Mac, you should see a forward
slash (/) instead and that represents a basic difference
| | 03:13 | between the two operating systems that the Windows Operating
Systems uses backslashes () to represents directories,
| | 03:19 | well Mac and other Unix based systems
use the forward slash (/).
| | 03:23 | There are other string based prefixes that you can use,
to address various key directories on the file system.
| | 03:29 | For instance, two important directories are called the
Application Directory and the Application Storage Directory.
| | 03:35 | There are other important directories called
the Desktop Directory and the User directory.
| | 03:40 | Each of these can be addressed in one of two
ways, either through a string base prefix
| | 03:44 | or through a static property of the File Class.
| | 03:48 | I will demonstrate the difference between
the two using the Application Directory.
| | 03:52 | I am going to create another File object, this time
I'm going to name it appDir, type casted as file
| | 03:59 | and once again I'm going to instantiate it using
New File and I will put in a prefix of app:/.
| | 04:05 | This is a reserved prefix in AIR which means the
directory in which the application executable is stored.
| | 04:13 | This is a reserved string based prefix which references
he Application Directory that is the directory
| | 04:19 | in which the application executable is stored.
| | 04:23 | Now I'll trace the results of that
expression using the syntax appDir.nativePath.
| | 04:28 | I can address exactly the same directory using a static
property of the File Class named Application Directory.
| | 04:37 | I'll name this variable appDir2, once again data
type it as a file and this time I'll get a reference
| | 04:44 | to that directory using File.applicationDirectory,
then I'll copy and paste the trace command.
| | 04:53 | I'll change the second trace command
to output the nativePath of appDir2.
| | 04:57 | I will Save my changes and Debug again I will click
the button to execute the function and you will see
| | 05:04 | that the two coding approaches give you the same result.
| | 05:08 | In either case, you have created a new
File object, which points to the location
| | 05:12 | of the application that is where it's running from.
| | 05:15 | In this case it's the Output folder of
the Flex Builder Project than Debug.
| | 05:20 | There are three other special directories
that you can address in this manner.
| | 05:24 | The User Home Directory is a directory that's unique
to each individual user on the local file system.
| | 05:30 | The actual location of the user
directory will differ depending
| | 05:32 | on whether you are working on Mac,
Windows Vista or Windows XP.
| | 05:37 | I am working on Windows Vista in this demonstration.
| | 05:39 | So I'll show you what it looks like when I run it on
this system and then describe what happens on the others.
| | 05:44 | I'll create another variable.
| | 05:46 | This time they will be named userDir, I'll set it as a file
and this time I'll get a reference using File.userDirectory
| | 05:55 | and then once again I'll trace
the result userDir.nativePath.
| | 06:02 | I run the application in Debug mode, click the button
to test and you will see that the User Directory
| | 06:08 | on my system Windows Vista points to
C:Usersdavid in a very similar fashion on Mac,
| | 06:17 | you would see a named a directory under the Users folder.
| | 06:20 | Well, on Windows XP, it would be under
the Documents and Settings folder
| | 06:24 | and again the subdirectory would be named for the user name.
| | 06:27 | There are other directories that you can address
directly within the Home Directory of the user.
| | 06:32 | I'll create two more and then trace them.
| | 06:36 | The first will be for the Desktop Directory.
| | 06:44 | This variable will address the Desktop Directory that
is the directory that represents the Visual Desktop
| | 06:50 | that you work with on either Windows or the Mac.
| | 06:53 | I'll trace the nativePath of the Desktop
Directory and then I'll do something very similar
| | 07:00 | for something called the Docs Directory,
that is to save the users own documents area.
| | 07:10 | Once again I'll trace, I'll save and
run the application in Debug mode.
| | 07:20 | Test and you will see that I'm
pointing out to the Desktop Directory
| | 07:25 | and the Documents Directory under my User Directory.
| | 07:30 | There is one other critical directory that you work with.
| | 07:33 | It's called the Application Storage Directory.
| | 07:35 | This Directory is once again unique to each individual user,
| | 07:39 | but it's designed to also be unique
to the particular application.
| | 07:43 | I'm going to create one more variable and I'm going to call
this storageDir, data type it as a File and reference it
| | 07:52 | from File.ApplicationStorageDirectory and
then once again trace its actual location.
| | 07:58 | I run the application in Debug mode.
| | 08:09 | Test the application and this time
you will see a much longer nativePath.
| | 08:13 | I will maximize the console, so we can see the entire path.
| | 08:17 | Once again the actual location of this folder will differ,
| | 08:20 | depending on whether you are working
on Windows XP, Windows Vista or Mac.
| | 08:25 | Working on Windows Vista, the Applications Storage
Directory shows up under an AppData folder.
| | 08:30 | On Windows Vista, the folder shows up under the User's
Home Directory under that in AppData sub-folder.
| | 08:37 | Under that a directory named Roaming and then a
directory which is named for the application id.
| | 08:44 | Notice that the full application id is used in this
case com.lynda.airflex.chapter04 and then the name
| | 08:52 | of the application DirectoryAliases and then finally
under that directory another directory named Local Store.
| | 08:59 | The Local Store directory is always named the same
regardless of which operating system you are on,
| | 09:04 | but the rest of the actual location of the this directory
will again differ from one operating system to another.
| | 09:10 | So that's basically how you address the various directories.
| | 09:14 | Once again, there are string based
prefixes that you can use instead
| | 09:18 | of these static properties, but
they give you the same result.
| | 09:22 | They allow you to address the special
directories that are either unique
| | 09:25 | to the user or to the user and the application.
| | Collapse this transcript |
| Comparing synchronous and asynchronous file operations| 00:00 | In this video, I'm going to describe and demonstrate the
difference between synchronous and asynchronous file access.
| | 00:07 | As I described in the first video in this
chapter synchronous file operations are executed
| | 00:11 | as part of the main application thread.
| | 00:14 | For the period of time it takes to execute a file operation,
the application thread is suspended and any animations
| | 00:21 | or user interactions are prevented during this period.
| | 00:24 | Asynchronous file operations allow the
main application thread to keep executing,
| | 00:29 | while the file operation is executed in the background.
| | 00:32 | To demonstrate the difference, I'll
be working with two applications.
| | 00:35 | The first is named SynchronousFileAcess.mxml.
| | 00:39 | If you are following along in the exercises, go to Flex
Navigator view and open SynchronousFileAccess.mxml.
| | 00:47 | The beginning application has a button
that calls a function named Copy File
| | 00:52 | and then it has instance of a component
named Animated Component.
| | 00:56 | I will run the applications so you can
see what the Animated Component is doing.
| | 01:01 | It uses a timer to simply move an object to
cross the screen every tenth of a second.
| | 01:06 | It's a very simple animation that
was done completely in Flex.
| | 01:10 | If you are curious about how that animation was done, just
take a look at the Source code for the Animated Component.
| | 01:16 | It uses a timer object to make a call to a function, ten
times a second to move a simple rectangle across the screen.
| | 01:23 | Now go back to SynchronousFileaccess.mxml,
| | 01:26 | all file operations can be executed
either synchronously or asynchronously.
| | 01:31 | For instance, in order to copy a file there
are methods called copyFile and copyFile async.
| | 01:38 | The copyFile method executes an operation synchronously
and copyFile async does the same thing asynchronously.
| | 01:44 | For this demonstration, I'm going
to create two file objects.
| | 01:49 | One pointing to a Source file, that's
fairly large and the other pointing
| | 01:52 | to a destination to which we want to copy file.
| | 01:55 | The first variable will be declared
within the function copyFile.
| | 01:58 | I will name the variable fSource, data type it
as a File and instantiate it, using new File
| | 02:07 | and then I'll use the string prefix that points to the
Application folder app:/ from there to the assets folder
| | 02:15 | and from there to a file called largecontacts.xml.
| | 02:20 | This is a file that has something
like 10,000 records in an XML file.
| | 02:24 | So it's going to take a couple of
seconds to copy even on a fast computer.
| | 02:28 | Now, I'll create another variable
named fDest for the destination file.
| | 02:32 | Once again data type it as a File, and I will point this
file to a location within my application storage area,
| | 02:40 | app-storage:/ and I'll name the
destination file simple contacts.xml.
| | 02:48 | Now, I'll copy the source file to the destination file.
| | 02:51 | The code will look like this, fSource.CopyTo once
again notice that there is a CopyTo and a CopyToAsync
| | 03:00 | and I'll pass in the following values, fDest which
is the destination location and then a value of true,
| | 03:07 | which basically means if the file is already there just
overwrite it and then a I'll pop-up an Alert dialog
| | 03:14 | that tells the user that the copy operation is complete.
| | 03:20 | I'll save the changes and run the application.
| | 03:24 | Notice that the application starts
its animations as it starts up.
| | 03:27 | That's because the animated component
launches itself upon Application Startup.
| | 03:32 | Now I'll click the button and notice that for the
duration of the operation that is for as long as it takes
| | 03:38 | to move the content from one location to another.
| | 03:42 | The animation freezes.
| | 03:45 | I will run the copy operation again
and once again you will see
| | 03:50 | that the little box freezes its
position, during the copying operation.
| | 03:55 | Now I will go to another application,
this one AsynchronousFileAccess.mxml
| | 04:01 | and it's very similar to the version that I just created.
| | 04:04 | This time before I execute the copying functionality, I
have added an event listener for an event named complete.
| | 04:12 | Notice that when the complete event occurs, I'm
calling a function called fileCompleteHandler.
| | 04:18 | That function has been declared below
it's name is fileCompleteHandler,
| | 04:22 | it receives an event object as an argument and returns void.
| | 04:26 | I'm going to make two changes to this file.
| | 04:29 | I'm going to move the Alert.show call
that is the dialog box that tells the user
| | 04:34 | that the operation is done into
the function fileCompleteHandler.
| | 04:38 | By the way, I did that by dragging and dropping the code.
| | 04:41 | Something you can do now in Eclipse 3.3 and
then I'll change the function that I'm calling
| | 04:46 | from this source file from CopyTo to CopyToAsync.
| | 04:53 | Now, whenever the file operation is completed,
I'll get the complete event dispatched
| | 04:58 | and that will cause my handler function to be called.
| | 05:01 | I will run the application and let's watch happens.
| | 05:04 | I once again click the Copy File button and
you will notice that the box continuous to move
| | 05:13 | across the screen even the while
file operation is in progress.
| | 05:17 | I will execute the command again and
once again the animations continues.
| | 05:23 | So that's the difference between
synchronous and asynchronous file operations.
| | 05:27 | Throughout the rest of this chapter, I'll be using
synchronous operations, just for their code simplicity,
| | 05:33 | but it's worth knowing that whenever you start dealing
| | 05:35 | with large files you should probably move
over asynchronous operations instead.
| | Collapse this transcript |
| Browsing for files and directories| 00:00 | In this video, I'm going to describe how to use
the File class to allow the user to browse for
| | 00:05 | and select a file from the local file system.
| | 00:08 | For this demonstration, I'll use
an application named Browsing.mxml.
| | 00:13 | That's in the chapter04 Begin Project.
| | 00:16 | If you are following along with the exercises open
that application in Flex Builder from the project,
| | 00:21 | then I'll expand the Code Editor to full
screen, so we can see all of the code.
| | 00:25 | This application has an empty function named browseForFile.
| | 00:29 | The function is being called when
user clicks the Browse button.
| | 00:32 | There is also an HBox container that
contains the label and the text control.
| | 00:36 | I'll use the text control to display the
path of the file selected by the user.
| | 00:43 | In order to initiate a browsing operation
create an instance of the File class.
| | 00:48 | I'm going to declare the File object
outside of any functions,
| | 00:52 | so that I can address it from any
function in the application.
| | 00:57 | I'll declare a private variable named
browseFile and I will data type it as a File.
| | 01:03 | Then I'll initialize it using the File class'
Constructor method and I'll pass in the location
| | 01:09 | of the Application Directory as a string prefix
and then point to the assets folder under that.
| | 01:16 | Now, when I tell the File object to start a browse operation
the browsing interface will start at that directory.
| | 01:22 | Within the browseForFile function, I'm first
going to add a couple of event listeners.
| | 01:27 | The first one will be for an event called Select.
| | 01:33 | The select event generate an event
object typed simply as the event class.
| | 01:37 | So I'll use the constant Event.SELECT
and then I'll call a function
| | 01:42 | that I'm going to have to create called selectHandler.
| | 01:48 | I'll copy and paste that code and then I'll
also listen for an event called CANCEL.
| | 01:53 | If the users cancels the browser operation.
| | 01:57 | The Cancel event will dispatched.
| | 02:00 | Once again the event object will be data
typed as a standard Event class and the name
| | 02:05 | of the eventHandler function for
this event will be cancelHandler.
| | 02:08 | Next, I'll create those two functions.
| | 02:15 | The first one will be named selectHandler, it
will receive an event object as an argument,
| | 02:21 | data typed as the Event class and
return void and within this function,
| | 02:28 | I'll output the path of the selected file using
the text control that's already been declared
| | 02:33 | with an id of selected text.
| | 02:36 | So the code will look like this,
selectedText.text=browseFile.nativePath
| | 02:46 | and this will report the full path of the selected file.
| | 02:49 | If the user cancels the operation, I
will call this function cancelHandler.
| | 02:56 | Once again the event argument will be typed
as a standard Event class and I'll return void
| | 03:02 | and this time I'll pop-up an Alert dialog and I'll
report to the user Browsing operation was canceled.
| | 03:14 | Finally, I'll go backup to the browseForFile method
and now initiate the browsing operation like this.
| | 03:21 | I'll call the File object browse method.
| | 03:24 | Notice that there are a number of different methods here.
| | 03:27 | I'm going to use the simplest version
in this demonstration simply browse.
| | 03:31 | The browse method allows you to
pass in a typeFilter as an array.
| | 03:35 | This is an array of valid file types,
for instance you might limit the type
| | 03:40 | of file the user can select to graphics JPGS or GIFS.
| | 03:45 | I'm just going to make a very simple call.
| | 03:47 | I call the browse method and now
when the user selects a file.
| | 03:51 | I'll get a select event and if they cancel
the operation I'll get a cancel event.
| | 03:56 | I'll test the application now.
| | 03:59 | When I click the Browse button
the Browsing dialog is popped up.
| | 04:04 | If you are working on Windows, you
will see a Windows Explorer dialog box
| | 04:07 | and if you working on the Mac you will see a Finder dialog.
| | 04:10 | I'll select the file from the assets folder
of the application directory and click Open,
| | 04:15 | and I see the result, the nativePath of the selected file.
| | 04:19 | I'll start the browsing operation again and this time
I'll cancel the operation by clicking the Cancel button
| | 04:25 | and I get the cancel event resulting
and showing the Alert pop-up.
| | 04:29 | Now, I will go back to the code and I'll show you that in
the selectHandler function, you can refer to the File object
| | 04:35 | that initiated the browsing function either by its variable
name, as I have done here or if you don't have direct access
| | 04:42 | to that you can address the same
object using the syntax event.target.
| | 04:48 | event.target always points to the object
that dispatched in the event originally.
| | 04:53 | In this case it was the browse File object that
dispatched the event resulting and calling this function.
| | 04:59 | I'll save the changes and run the application again.
| | 05:02 | I'll browse, once again I'll select the file.
| | 05:06 | This time ATextFile.text and click Open and you will see
| | 05:10 | that once again the nativepath of
the file is correctly displayed.
| | 05:15 | As I mentioned, there are also methods that allow you to
select the multiple files and also to select a directory.
| | 05:21 | They are all methods of the File Class and you
call them by first instantiating the File Class,
| | 05:27 | pointing to the folder where you want to start the
browsing operation and then calling the appropriate method
| | 05:33 | and adding the appropriate event listeners
to handle whatever happens
| | 05:37 | when the user either selects a
file or cancels the operations.
| | Collapse this transcript |
| Working with Flex's file access visual controls| 00:00 | In this video, I'm going to describe the use of visual
controls provided in Flex that allow you to navigate
| | 00:06 | and select files and directories from the local file system.
| | 00:09 | These visual controls were described
briefly in the first video in this chapter.
| | 00:13 | They are based on the existing list based
controls that are part of the Flex framework,
| | 00:18 | the List, the ComboBox, the DataGrid and so on.
| | 00:21 | To demonstrate these controls, I'm going
| | 00:23 | to use an application named VisualControls.mxml,
that's a part of the Chapter4 project.
| | 00:29 | If you are following along in the exercises,
open the application in Flex Builder now.
| | 00:34 | I will expand the Source Code to full screen.
| | 00:36 | You'll see that this is a very simple application that
just has an HBox container, a label and a text control.
| | 00:44 | To allow user to navigate and select files
and directories, use one of these controls.
| | 00:49 | I'll start with the simplest stuff
then, the FileSystemList control.
| | 00:52 | I'll declare the FileSystemList control using an MXML tag.
| | 00:56 | I will give it an id of fsList and
then I'll set its initial directory.
| | 01:02 | The directory property points to a File
object, that we first do in actual directory.
| | 01:07 | In this example, I'll use a binding expression that
points to the static property, Files.applicationDirectory.
| | 01:17 | Then I'll create a Button control, I'll give it a
label of Show selected and then a click event listener.
| | 01:26 | Within the click event listener, I'll
call a method called clickHandler.
| | 01:30 | I'll close the Button tag.
| | 01:34 | Then I'll create a Script section and
create the function, clickHandler.
| | 01:40 | The clickHandler function will receive an event
object typed as a MouseEvent and return void.
| | 01:48 | Within the function, I'll go and get the
selected value from the FileSystemList control
| | 01:54 | and I will display the selected files, nativePath
in the text control with an id of selected text.
| | 02:01 | I'll start with the code, selectedText.text equals (=)
| | 02:06 | and then I'll get the selected File
object, fsList.selectedItem.nativePath.
| | 02:13 | In the clickHandler method call, I'll pass in the
event object and then I'll test the application.
| | 02:24 | Notice that as the application
starts up, it points to the directory
| | 02:27 | or folder that contains the application executable.
| | 02:31 | The contents of the listcontrol will differ depending on
whether you are running in Flex Builder or in Debug mode
| | 02:36 | or you run the same application
after packaging and installing it.
| | 02:40 | In this case we're pointing to the bin-debug outlet
folder, that's part of the Flex Builder Project.
| | 02:46 | Notice, that I can click on any item
and then click the Show selected button
| | 02:51 | and I'll see the native path of the selected folder or file.
| | 02:54 | I'll double-click into the assets folder
and that will take me into its contents.
| | 02:59 | I'll select one of the files, largecontacts.xml.
| | 03:03 | Click the Show selected button and now I
will see the full native path of that file.
| | 03:08 | Let's try another one of the visual controls, this time I
will replace the FileSystemList with the FileSystemDataGrid.
| | 03:15 | I'm also going to expand the width
of the application as follows,
| | 03:20 | I'll set the width to 600 pixels and the height to 500.
| | 03:26 | I'll save the changes and run the application and you'll
see that the reason I set the windowed application
| | 03:32 | to a little bit larger width is because the DataGrid control
is going to take a quite a bit more horizontal space.
| | 03:38 | Once again I can double-click down into the assets folder, I
can press the Backspace key to return and I can pick an item
| | 03:46 | out of the DataGrid and click the Show selected
button and I'll see the items native path displayed.
| | 03:52 | Notice that if I go into an area
and I click to Show selected button,
| | 03:55 | without first having selected something,
I'll get a runtime error.
| | 03:59 | Indicating that I'm trying to refer to an object
that's null, that's because the current code assumes
| | 04:05 | that I have selected something from the DataGrid.
| | 04:07 | To prevent that behavior, I'll add an
enabled property to the Button control,
| | 04:12 | and I'll set the value of the property using
a binding expression that looks like this,
| | 04:16 | fsList.selectedIndex not equal to minus one (!= -1).
| | 04:25 | As with the core corollary visual controls in the
Flex framework, if the user has not selected an item
| | 04:30 | from the DataGrid, the list or other visual control,
| | 04:34 | the selected index property returns
a value of negative one (-1).
| | 04:38 | So this expression if the user hasn't
selected something will return false
| | 04:42 | and the button will not be enabled and
the user won't be able to click it.
| | 04:46 | I'll save and test the application again and
you'll see that as the application opens up,
| | 04:50 | once again it's showing the contents of
the initial folder, the application folder,
| | 04:55 | but because I haven't selected anything
from the DataGrid, I can't click the button.
| | 05:00 | When I click on an item, the button
becomes enabled and I can click it.
| | 05:04 | If I double-click into a folder, you'll see that nothing is
selected and therefore once again the button is disabled.
| | 05:11 | I will select an item and click the button
and once again you can see the contents.
| | 05:16 | There are two other visual controls worth looking at.
| | 05:19 | The next one is the FileSystemComboBox,
the FileSystemComboBox is a pull down list.
| | 05:25 | As with the list control, it shows a list
of all the items in the current directory.
| | 05:30 | It shows the current directory name of bin-debug and then it
shows the tree style control, that lets you drill upwards,
| | 05:37 | but the ComboBox doesn't allow you
automatically to move downward, through the tree.
| | 05:42 | If you want that sort of functionality,
instead use a FileSystemTree.
| | 05:47 | I will replace the existing FileSystemComboBox with
the FileSystemTree and once again run the application.
| | 05:54 | This time you'll see that I can navigate
upward and downward through the file tree.
| | 05:59 | Once again I can select a file, click the Show selected
button and see its native path, but because I'm starting off
| | 06:06 | at a root folder, I have access if to
everything from that root folder on down.
| | 06:10 | Unlike the list control, pressing the Backspace
button in this control doesn't take me upward.
| | 06:16 | If I wanted to navigate upward from this root folder up to
its parent directory, I'd have to do that programmatically.
| | 06:22 | But because I'm in a tree control,
once I started at one directory,
| | 06:26 | I have access to everything under
that directory automatically.
| | 06:29 | There is one other visual control worth knowing about.
| | 06:32 | It's called a FileSystemHistory button.
| | 06:34 | The FileSystem history button works like this, I'm going
to put a FileSystemListBack in this time and then right
| | 06:41 | under that I'll add an HBox control
and within the HBox control,
| | 06:47 | I'm going to create two instances of
the class, FileSystemHistory button.
| | 06:52 | The first one is going to be used to navigate backward
to the history of selections in the FileSystemList.
| | 06:59 | I'll set its data provider as follows, I'll
use a binding expression of fsList.backHistory.
| | 07:07 | I'll add an item click event listener.
| | 07:15 | When the user clicks on any item in the
History button, I'll call this function,
| | 07:20 | fsList.navigateBack and I'll pass in a value of event.index.
| | 07:28 | This means, go back the number of times
based on which item in the list I selected.
| | 07:33 | Now, let's take a look at the result.
| | 07:35 | I'll run the application, I'll double-click down
into the assets folder and then pull down the list
| | 07:42 | of available history and you'll see
that bin-debug is in the History list.
| | 07:47 | I'll click to select it and that moves me back to that step.
| | 07:51 | Now, I will close the application and I'm going
to copy and paste the FileSystemHistory button.
| | 07:57 | So I have two of them within the HBox control.
| | 08:00 | For the second one, I'll change the data provider
from fsList.backhistory to fsList.forwardhistory
| | 08:08 | and I'll change the item click
EventListener, so that instead of calling
| | 08:14 | to navigateBack function, it calls
the navigateForward function.
| | 08:19 | Once again I pass in event.index, I'll run the
application, I'll double-click down into the assets folder,
| | 08:28 | take a look at the back button and
you'll see bin-debuggers listed there.
| | 08:32 | I'll go back there, now look at the forward button
and you'll see that the assets folder is listed there.
| | 08:39 | So the FileSystemHistory button is most useful,
with the FileSystemList and the FileSystemDataGrid.
| | 08:45 | Neither of which controls have the ability to
navigate forward and backward on their own.
| | 08:50 | The History button is less useful with the tree control,
because the tree control already offers you the ability
| | 08:56 | to see all parts of the root folders, sub-folder structure.
| | 09:00 | If you use the History button control,
it typically uses two.
| | 09:04 | One to go back in the history and one to go forward, so
that's a look at all of the different visual controls
| | 09:10 | in Flex and AIR that give you direct
access to navigating and selecting files
| | 09:15 | and directories from the local file system.
| | Collapse this transcript |
| Creating and deleting directories| 00:00 | In this video, I'm going to describe
how to use the ActionScript File Class
| | 00:04 | to create new directories in the local file system.
| | 00:07 | As I've described previously, the File Class can reference
either a file or directory in the local file system
| | 00:14 | and it's responsible for creating new directories.
| | 00:17 | You all see as the File Class to move, copy and to
lead directories, I'll show that in the later video.
| | 00:22 | For this demonstration, I'll use an application
named Directories.mxml, if you are following along
| | 00:28 | with the exercises, you can open this
application from the Chapter 04, begin project.
| | 00:34 | I'll open the application in Flex Builder
and then maximize the Code Editor.
| | 00:39 | This application uses a FileSystemTree, with its
directory bound to the applicationsStorageDirectory.
| | 00:45 | Remember that this is the directory that's unique
for each individual user and for each application.
| | 00:51 | Its actual location differs depending on the
operating system on which the application is running.
| | 00:57 | Upon opening the application, the FileSystemTree will
appear to be empty, it's actually pointing at the location
| | 01:04 | of the applications towards directory
on the user's local system.
| | 01:08 | Our goal is to use the FileSystemTree component,
to allow the user to select a parent directory.
| | 01:15 | A place where they want to create a subdirectory.
| | 01:17 | Then we will use the File Class to do
the work of creating the new directory.
| | 01:21 | Place the cursor inside the Create Dir Function and declare
a new variable named parentDir, data typed as a File.
| | 01:30 | The first step before you create an actual
directory, is to determine what the parentDir will be.
| | 01:36 | We'll examine the FileSystemTree
component selectedIndex property.
| | 01:40 | To find out whether the user has selected anything.
| | 01:43 | Put in a conditional block, that
uses this Boolean expression.
| | 01:48 | If fsTree.selectedIndex is not equal to minus
one (!= -1) and this would be the condition
| | 01:56 | where the user has not selected anything from the tree.
| | 01:59 | We'll set the parentDir file objects
reference to the selected item from the tree.
| | 02:07 | We use the selectedItem property and
explicitly cast it as a File object.
| | 02:13 | In the else clause, set the location of the
parentDir to the application directory itself.
| | 02:20 | The syntax for that is the static
property, file.applicationStorageDirectory.
| | 02:26 | So now the logic is that if the user has selected
something, we'll use that as the parent directory,
| | 02:31 | otherwise we will use the applicationsStorageDirectory.
| | 02:35 | The next step before creating a subdirectory is to
determine whether the user has chosen a directory or a file.
| | 02:41 | If the user chose a file, we can't
create a subdirectory under it.
| | 02:45 | For this purpose, user property of
the File Class named isDirectory,
| | 02:50 | this is a Boolean property that returns true or false.
| | 02:53 | If the File object points to a directory that
returns true, otherwise it returns false.
| | 03:00 | Also put in else clause, and we'll come
back to the else clause in a moment.
| | 03:04 | I'll scroll down a bit so we can see this part of the code.
| | 03:07 | Then place the cursor back in the if
clause that only will be activated
| | 03:11 | if the user has chosen a directory as the parent.
| | 03:15 | Now, the next step in creating a new directory is to
create a new File object that points to the location
| | 03:20 | where you want to create the subdirectory.
| | 03:23 | I'll create a new variable and I'll name it newDir
and I'll data type it once again as a File object.
| | 03:29 | To set the physical location of this File object,
I'll use a method of the File Class named resolvePath.
| | 03:36 | The resolvePath method works like this, I'll
put in the name of the parentDir object.
| | 03:42 | Then call the resolvePath method and I'll pass in the name
| | 03:45 | of the subdirectory I want to create,
which I'll name newDir.
| | 03:50 | Whatever value you pass into the resolvePath method,
is appended to the nativePath of the parent object
| | 03:57 | and it becomes a new nativePath the you can refer to.
| | 04:00 | To see the result of that action, I'll trace the
newDir objects, nativePath and I'll run the application
| | 04:09 | in debug mode and we will see what the trace statement says.
| | 04:13 | I'll run the application in the debug mode.
| | 04:16 | As the application starts up once again, it's showing
the FileSystemTree component and it's pointing
| | 04:21 | to the applicationStorageDirectory,
I'll click the Create Directory button
| | 04:26 | and then close the application
and maximize the Console view.
| | 04:31 | The Console view shows the result to the trace statement,
| | 04:34 | displaying the location of the
directory I'm about to create.
| | 04:38 | Notice that it's underneath my applicationsStorageDirectory.
| | 04:41 | Once again the actual location of
the directory will differ depending
| | 04:45 | on whether you are running on Windows
XP, Windows Vista or Mac.
| | 04:49 | Notice that the end of the expression is Local store/newDir,
a backslash () if you are on Windows and a forward slash (/)
| | 04:57 | if you are on Mac and that's the
directory I would like to create.
| | 05:01 | So I will restore the size of the Console.
| | 05:03 | If you are still in debug mode, you can click
the little button that will show red right here
| | 05:08 | and then that will terminate the debugging
session and you are ready to start coding again.
| | 05:13 | Go back to the MXML Editor, place the
cursor after the call to the trace method.
| | 05:19 | Now it's time to actually create the directory, I'll do
this by calling the NewDir objects, createDirectory method
| | 05:27 | and that actually creates the directory on disc.
| | 05:30 | Next, I'll refresh the FileSystemTree, I'll use this
in text fsTree.refresh, ending with the semicolon.
| | 05:38 | Finally I'll use the Alert class to tell
the user, that the operation was successful.
| | 05:47 | I'll call the Alert class a show method and pass
in a literal string as a message Directory created.
| | 05:54 | I also need to handle the condition that can happen,
if the user chooses a file from the FileSystemTree.
| | 05:59 | If they choose a file, we can't
create a directory underneath it.
| | 06:03 | So all I'll do in the else clause of the conditional
block is use the Alert class to show a pop-up message
| | 06:09 | that tells the user, Please select a directory.
| | 06:12 | Now, the application should be complete.
| | 06:17 | Going back up to the top of the code,
in the first conditional clause I check
| | 06:21 | to see whether the user has selected an item from
the tree control, if they have selected an item,
| | 06:27 | I use the selectedItem property cast as
a File and set the parentDir from that,
| | 06:33 | otherwise I set the parentDir to
the applicationStorageDirectory.
| | 06:37 | Then, assuming that they've chosen
a directory which is enforced
| | 06:41 | by this conditional block, then I create a new file object.
| | 06:45 | I set it's location with the resolvePath method
in the name of the directory I want to create
| | 06:50 | and then I create the directory,
refresh the tree to show the result
| | 06:54 | and also pop-up a window telling
them that the action was successful.
| | 06:58 | I'll run the application, I'll
click the Create Directory button.
| | 07:03 | I see the alert message saying
that the directory was created
| | 07:06 | and the FileSystemTree shows me
that I did successfully create it.
| | 07:10 | I'll click into the FileSystemTree and select that now
as the new parentDir, click the button again, click OK.
| | 07:19 | Open the NewDir as the parent and I'll see
another NewDir under that and I can keep
| | 07:24 | on doing this operation as long as I want to.
| | 07:27 | It's also worth noting, that if
you go over to the FileSystem now,
| | 07:31 | you'll find that you have this whole
hierarchical set of directories.
| | 07:34 | A NewDir inside a NewDir, inside a NewDir.
| | 07:38 | Now if you were to call the Create Directory function again,
| | 07:41 | on a directory that was already
created, nothing would happen.
| | 07:45 | You won't get back any bad response, you won't see
a runtime error, the command is simply ignored.
| | 07:51 | So that's how we create directories using the
File Class, using the Create Directory Method,
| | 07:56 | but first ensuring that the parent directory
that we're using is a directory and not a file.
| | Collapse this transcript |
| Creating and manipulating files| 00:00 | In this video, I'm going to describe
how to use the ActionScript File class
| | 00:04 | to manipulate files in the local file system.
| | 00:07 | How to copy, move, delete and move
files to the trash or the recycle bin.
| | 00:12 | For these demonstrations, I'll use an application in the
Chapter04, Begin Project named filemanipulation.mxml.
| | 00:20 | If you are following along with the
exercises, open this application file
| | 00:24 | in Flex Builder and then run the application.
| | 00:27 | The application presents a file system list control, before
the user can use any of the features of the application,
| | 00:33 | they have to indicate where the exercises directory is.
| | 00:37 | Click the Select Exercises Directory button and
then browse to and select the Exercises folder,
| | 00:43 | which I've installed in my desktop directory.
| | 00:46 | I will then click OK and then the file system list
control displays the contents of a subdirectory
| | 00:53 | of the exercises folder named Assetsfiles.
| | 00:56 | The status area of the application indicates
the physical location of this directory
| | 01:01 | and it should contain a single
initial file, a text file .txt.
| | 01:06 | I'll close the application and take a look at the
code, there is bit of code in here that's controlling
| | 01:11 | that initial selection process, including
checking to see whether the directory exists
| | 01:16 | and whether the exercises directory is
selected by the user has the correct structure.
| | 01:21 | In the bottom section of the script area, there
are four functions named copyFile, moveFile,
| | 01:26 | deleteFile and trashFile, which in turn are being
called by four buttons in the panel's control bar.
| | 01:33 | In this first demonstration, I'll show you how
to copy a file, from one file name to another.
| | 01:38 | Place the cursor inside the copyFile method, the first
step in copying a file is to create two file objects,
| | 01:45 | one pointing to the source file and one pointing to
the destination where you want to copy the file to.
| | 01:52 | Declare variable named SRC, data typed as
a File and get its reference from FS list,
| | 01:59 | that's the id of the file system list
control dot selectedItem as File.
| | 02:07 | Next create another variable named dest, also data typed as
a file and point to a location within the files directory,
| | 02:15 | which was represent by a File object named, filesDir.
| | 02:19 | Call it resolvePath method and pass in the
name of the new file you want to create.
| | 02:25 | ANewFile.txt.
| | 02:28 | Now, whenever you execute any of
the file manipulation functions,
| | 02:32 | you can use either a synchronous or an asynchronous version.
| | 02:35 | If you use the asynchronous version, you need to listen for
the complete event and react whenever the operation is done.
| | 02:42 | To do that, call the source object
addEventListener method and dedicate
| | 02:47 | which event you are listening for Event.COMPLETE.
| | 02:50 | When that event is dispatched, you
call a method called completeHandler,
| | 02:55 | which is already declared in this application.
| | 02:57 | Then after the event listener has been created,
copy the file like this, src.copyTo --
| | 03:05 | notice that there are two versions of this method, copyTo
which is synchronous and copyToAsync which is Asynchronous.
| | 03:13 | Use the Asynchronous version, copyToAsync, pas in the
destination file object dest and then a bullian value,
| | 03:22 | indicating whether you want to overwrite
the destination file if it already exists.
| | 03:27 | I'll put in a value of true.
| | 03:29 | Now go down to the completeHandler method, in the
completeHandler, refresh the file system list control
| | 03:35 | like this, fsList.refresh() and that will
cause the list control to reread the contents
| | 03:41 | of the directory and display it to the user.
| | 03:44 | Save your changes and run the application.
| | 03:47 | When the application starts up, once again you'll
need to indicate where the exercises directory is,
| | 03:53 | click the button and select the directory and click OK.
| | 03:56 | Then select the file you want to
copy and click the Copy button,
| | 04:01 | you should see that the new file is created immediately.
| | 04:04 | Next, you will learn how to move a
file from one directory to another.
| | 04:08 | Close the application and place the cursor
in the code inside the moveFile function.
| | 04:13 | In order to move a file, you first need a
destination directory, to make sure you have a place
| | 04:19 | to move the file too, create a new variable named
destDir, data typed as a File and get the reference
| | 04:26 | to the new directory, using the syntax filesDir.resolvePath
and pass in the name of the destination directory DestDir.
| | 04:35 | Now this directory doesn't exist yet, so we need to
create it using the syntax destDir.createDirectory().
| | 04:44 | You could also wrap this line of
code inside a conditional clause.
| | 04:47 | Checking first to see whether the directory
already exists, it's really not necessary though
| | 04:52 | because the createDirectory function, if it tries to
create a directory that already exists does nothing,
| | 04:57 | it doesn't throw a runtime error
or cause any other problems.
| | 05:01 | Now, we'll get a reference to the file we want to move.
| | 05:04 | I have code to do that already in the copyFile function.
| | 05:08 | So I will go up to that function and copy the
line of code that creates the source variable
| | 05:13 | and I'll paste it into the moveFile function.
| | 05:16 | I'll also copy and paste the addEventListener
call right after the creation of the variable.
| | 05:23 | Now, I'll also create a destination file object
that indicates where I want to move the file too.
| | 05:29 | You can't just pass in a directory here, you have to
pass in an actual file name that indicates where you want
| | 05:35 | to move it to and what the new file will be.
| | 05:37 | I'll use the syntax, I'll create a new variable named
destFile data typed as a File and I'll get its location
| | 05:45 | and file name from this syntax,
destDir.resolvePath and then I'll pass
| | 05:51 | in the existing name of the file like this, src.name.
| | 05:55 | The name property returns just the
filename without its location information.
| | 06:00 | Finally, I will move the file by
calling the syntax src.moveToAsync.
| | 06:07 | I will pass in the location I'm moving it
to destFile and a value of true indicating
| | 06:12 | that if the file already exists, I'll overwrite it.
| | 06:16 | The code for the completeHandler is already filled
in, because we did that in the previous demonstration.
| | 06:22 | So I'll save and run the application,
once again select the exercises directory,
| | 06:29 | select the file that I want to
move and click the Move button.
| | 06:33 | You'll see that the file no longer exists in this
directory, instead there is a new directory named destDir.
| | 06:39 | I'll double-click on that directory and you'll
see that the file has been moved correctly.
| | 06:44 | Next, I'll show you how to delete a file.
| | 06:46 | Go back to the code and place the
cursor in the deleteFile function.
| | 06:50 | The first step as before is to get a reference
to the file that's currently selected.
| | 06:56 | I'll go back to the moveFile function and
I'll copy and paste these two lines of code.
| | 07:01 | The line of code that creates the SRC variable
and the one that adds the event listener
| | 07:06 | and I'll paste those lines of code
into the deleteFile function.
| | 07:09 | Before you can delete, you have to determine
whether the user has selected a file or a directory.
| | 07:15 | Put in a conditional clause and this
Boolean expression, src.isDirectory.
| | 07:21 | If the user selected a directory, I'll use
a function called deleteDirectoryAsync.
| | 07:28 | If they selected a file, I'll choose
src.deleteFileAsync like this.
| | 07:34 | In the if clause, I'll call the syntax
src.deleteDirectoryAsync and I'll pass
| | 07:42 | in a Boolean expression indicating whether I want
to delete all of the contents of the directory
| | 07:46 | if it contains anything and I'll pass in a value of truth.
| | 07:50 | In the else clause, I'll call a
function called deleteFileAsync.
| | 07:54 | This function doesn't receive any arguments and
it simply deletes a single file and in either case
| | 08:00 | when the completeEvent is dispatched, the
completeHandler method will refresh the list control.
| | 08:05 | I'll save and run the application, once again when the
application starts up, I'll select my exercises directory,
| | 08:12 | I drill down into the destination directory,
select the file and click the Delete button
| | 08:19 | and you'll see that the directory is emptied out.
| | 08:22 | Now, with the list still having focus, press the
Backspace key and that will take you up one directory.
| | 08:28 | Now select the destDir directory and click
Delete and once again the directory is deleted.
| | 08:35 | Now let's do all the functions, click
ATextFile.text click Copy, click the File, delete it.
| | 08:45 | Select a ATextFile.txt again, copy it, select the NewFile
and Move it and this time remove the destination directory
| | 08:56 | by clicking Delete and you'll see that you are deleting
not just the directory but all of its contents.
| | 09:03 | Finally, there is one more feature to talk about, moving
a file to the Trash or on Windows into the Recycle Bin.
| | 09:10 | For this purpose, you can once again select
from synchronous or asynchronous versions.
| | 09:15 | This time of a function named Move to Trash.
| | 09:18 | In the trashFile function, I'll
once again copy and paste the code
| | 09:22 | that gets the source file reference
and sets up the event listener.
| | 09:31 | Now, instead of deleting, I'm moving to the
Trash and whereas with the Delete functionality,
| | 09:37 | there are two different versions of functions.
| | 09:39 | One for directories and one for files.
| | 09:41 | When you move to the Trash, it's all the same thing.
| | 09:44 | So I will call src.moveToTrashAsync () and once
again when the complete event is dispatched,
| | 09:51 | the completeHandler, method will refresh the list control.
| | 09:54 | I'll run the application, select the exercises
directory when the application opens up, select the file
| | 10:02 | and this time click the Trash button, you'll see that
the file is no longer displayed in the list control.
| | 10:07 | Now, I'm going to minimize everything and go back to my
desktop and take a look at my Recycle Bin and you'll see
| | 10:14 | that the text file has been moved to the Trash.
| | 10:17 | I'll reopen the application, move it over to the
side, go back to the Recycle Bin and I'm now going
| | 10:24 | to restore the file to its original location.
| | 10:27 | On windows you can do this by right-clicking
and selecting Restore.
| | 10:31 | On Mac, you'll need to actually drag
the file to the appropriate location.
| | 10:35 | Then I'll go back to the application still
running and click the Refresh button and you see
| | 10:40 | that the file has been moved back to its original location.
| | 10:43 | So these are the four major features
of file manipulation in AIR.
| | 10:47 | You can do all four features on either directories or
files, copying, moving, deleting and moving to the trash
| | 10:54 | and for each operation there are two versions
for synchronous and asynchronous operations.
| | Collapse this transcript |
| Reading data from a text file| 00:00 | In this video, I'm going to describe how to read
text contents from a file on the local disk.
| | 00:06 | For this demonstration, I will use an application
named ReadingText.mxml from the Chapter04BeginProject.
| | 00:13 | If you are following along with the
exercises, open the file in Flex Builder now.
| | 00:17 | This is a very simple beginning application.
| | 00:20 | It has an empty function named readText and a button
control whose click event results in calling the function.
| | 00:26 | I will expand my Editor to full screen
so we can see as much code as possible.
| | 00:30 | To read text from a file on disk, you need two objects.
| | 00:35 | A File object that points to the file and a
FileStream object that opens and reads its contents.
| | 00:41 | Start by the declaring a variable
named F data typed as a File.
| | 00:45 | Get its location, using this syntax
File.applicationDirectory.resolvePath,
| | 00:53 | and then pass in this location Assets/ATextFile.txt.
| | 00:59 | Next, create a FileStream object.
| | 01:05 | Declare another variable named FS,
set its data type as FileStream,
| | 01:11 | and instantiate it using the FileStream
classes no arguments constructor.
| | 01:15 | The file classes constructor method
just not receive any arguments.
| | 01:20 | You simply instantiate it and then
you connect it up to the file object,
| | 01:24 | using one of two methods, either Open or open Async.
| | 01:28 | As with all file manipulation functions, you can read the
contents from a file either synchronously or asynchronously.
| | 01:35 | I will be working synchronously in this exercise.
| | 01:38 | But if you are working with a very large file, you
may need to use the asynchronous version to make sure
| | 01:43 | that you don't suspend the main application thread,
while the file reading process is happening.
| | 01:47 | To open the file synchronously, call it the FileStream
objects open method and pass in two arguments.
| | 01:53 | A reference to the file you want
to open, and then a mode value.
| | 01:57 | The file mode argument is a string value.
| | 02:00 | There are four constants you can use,
that are members of the class FileMode.
| | 02:05 | Their values are APPEND, READ, UPDATE and WRITE.
| | 02:09 | If you are just getting a value
out of the file, use the Read mode.
| | 02:14 | Now the file is open for reading.
| | 02:17 | Now, declare a variable typed as String
that will receive the value from the file.
| | 02:21 | I will name this variable simply TXT, data type
it as a String, and then you call it a method
| | 02:28 | of the FileStream object named readUTFBytes.
| | 02:32 | There are actually two methods that are
available named readUTF and readUTFBytes.
| | 02:37 | The readUTF method requires a particular end of file
marker at the end of a file which isn't always present.
| | 02:42 | The readUTFBytes method is a bit
more reliable and it works like this.
| | 02:47 | You call it the FileStreams readUTFBytes method, and
you pass in a length value which you read dynamically,
| | 02:56 | using the FileStream object's bytesAvailable property.
| | 02:59 | This is an unsigned integer value that tells you
how many bytes or characters there are in the file.
| | 03:05 | Close the method call and now the data
has been returned to the text variable.
| | 03:10 | Finally, and very important, you should always
explicitly close the FileStream when you are done with it.
| | 03:16 | This ensures that any of the application's
file locks have been removed.
| | 03:20 | Now, we have the value from the
text file in the TXT variable.
| | 03:24 | I will use the alert class and display
the results by calling Alert.show.
| | 03:29 | I will pass in value of the text
property, and then in the second argument,
| | 03:34 | the title of the pop up window, a value of Read from file.
| | 03:40 | That's all the code.
| | 03:42 | Let's review the steps.
| | 03:43 | First you create a file object pointing to the file
you want to read, then you create a FileStream object.
| | 03:48 | You use the FileStream object to open the file
working either synchronously or asynchronously.
| | 03:54 | I'm using synchronous operations here, and
indicate what mode you want to open the file in.
| | 03:59 | I have indicated here that I'm opening it in Read mode.
| | 04:02 | Next, you call the readUTFBytes method and pass in
the FileStream object's bytesAvailable property.
| | 04:09 | That returns the value from the
text file into the String variable.
| | 04:13 | Then you explicitly close the FileStream and
then you have a value that you can work with.
| | 04:19 | I'll run the application to test this.
| | 04:22 | I will Click the button, and you will see the
contents of the text file are read and displayed.
| | 04:28 | If you are working with an XML file, the steps are
very similar, but you also then take the String value
| | 04:35 | that retrieved from the XML contents
and you pass it into an XML object.
| | 04:40 | I have another couple of files in
the source area that I can work with.
| | 04:44 | Here's a file named contacts.xml which
contains a thousand rows of XML formatted data.
| | 04:51 | I'm going to change the contents of this file like this.
| | 04:55 | First of all I will change the name of the file I'm
reading from ATextFile.txt to simply contacts.xml.
| | 05:02 | The next set of steps are exactly the same.
| | 05:05 | I create the FileStream, open the file, read
its contents and save it all as a String.
| | 05:10 | Then, once I have the XML formatted text
as a String, I can parse it by passing it
| | 05:15 | into the constructor method of a new XML object.
| | 05:18 | I will create a variable named
contacts.XML data typed as an XML object,
| | 05:25 | and I will construct it using new XML,
and I will pass in the text value.
| | 05:31 | This time l don't want to use the Alert
class to display the contents of the file.
| | 05:35 | So I'm going to comment that out, and then put
a break point on the last line of the function.
| | 05:40 | When I reach the break point, that will suspend the
application, and I will be able to inspect this XML object.
| | 05:46 | I will save the changes, and this time I
will run the application in debug mode.
| | 05:51 | When the application opens, I will
Click the Read File button.
| | 05:56 | In the background, Flex Builder presents a message,
asking me to switch to the debugging perspective.
| | 06:01 | I will accept the prompt.
| | 06:03 | I will double-click the Variables Tab to inspect
my data, and then take a look at contacts.XML.
| | 06:10 | It may take a few seconds for this to open on
your system depending on how fast your system is,
| | 06:14 | how much memory, how much resources you have.
| | 06:17 | But after the data has been parsed, you
should see that you can inspect the data
| | 06:21 | and drill down through its contents in the Variables view.
| | 06:26 | Now, I'll restore the Variables view
and terminate the debugging session.
| | 06:31 | So that's a look at how to read text files into memory.
| | 06:34 | You use a file object and a FileStream object,
| | 06:38 | and read the value into a String based variable making
sure you have closed the FileStream when you are done.
| | 06:43 | And then if you have simple text, you can simply display
it to the user or do anything else you want with it
| | 06:48 | or if you have XML formatted text, you
can use the XML object to parse the data,
| | 06:53 | and make it available to E4X expressions.
| | 06:56 | Now, if you are not familiar with E4X, which is known as
ECMAScript for XML, it's a great technology to get to know
| | 07:03 | and you can check out the demonstrations of
using E4X in the other videos about Flex 3.
| | 07:08 | Flex 3 Beyond the Basics and Flex 3 Essential Training.
| | Collapse this transcript |
| Writing data to a text file| 00:00 | In this video, I'm going to describe how to
write text to a file in the local file system.
| | 00:05 | For this demonstration I'll use an application in
the Chapter04BeginProject named WritingText.mxml.
| | 00:13 | If you're following along with the exercises
open the application in Flex Builder.
| | 00:18 | The beginning application has an empty function named
writeText, a button whose click event calls the function
| | 00:24 | and the TextArea control with an ID of taSource
that will provide text to be written to the file.
| | 00:30 | Just as when reading a file you need two objects, a file
object that will reference the file you want to write to and
| | 00:37 | the FileStream that will actually open and write the text.
| | 00:41 | To get started place the cursor
inside the writeText function.
| | 00:46 | I'll expand the editor to full screen to see all of the code.
| | 00:49 | Declare a variable named f data typed as a file
| | 00:53 | and indicate its target location.
| | 00:55 | You can't write a file to the application directory; the
application doesn't have permissions to write content to that area.
| | 01:02 | You aren't allowed to directly modify the contents
or files that are in the application directory,
| | 01:07 | that is, the directory for the actual
application is stored or its subdirectories.
| | 01:12 | So instead I'll create a file reference that
points to a location in my desktop directory.
| | 01:17 | I'll set its location and file name with this syntax,
| | 01:20 | File.desktopDirectory.resolvePath and then I'll pass in
the name of the file that I want to create, DestFile.txt.
| | 01:31 | Now I'll create a FileStream object. As when reading
the file, as I demonstrated in the previous video,
| | 01:37 | you declare the variable typed as a
FileStream and then construct the object
| | 01:42 | using the FileStream class's no arguments
constructor method. Next open the file.
| | 01:47 | As when reading the file you can select
from synchronous or asynchronous operations.
| | 01:52 | Because I'm working in a very small text file
and it will take very little time to do,
| | 01:57 | I'll work synchronously this time. I'll open the file
| | 02:01 | I'll call the open method of the FileStream
object and pass in the target file reference
| | 02:06 | and then pass in a FileMode of FileMode.WRITE.
| | 02:11 | You can also select APPEND or UPDATE. You use UPDATE if you're
overwriting the contents of an existing file and APPEND if you're
| | 02:19 | adding text to the end of a file.
| | 02:21 | Because I'm creating a new file
from scratch, I'll choose FileMode.WRITE.
| | 02:24 | Next I'll write the contents of the TextArea control to the file.
| | 02:29 | I'll use a method called writeUTFBytes.
| | 02:35 | And I'll pass in the value as a string
that I want to write to the file
| | 02:39 | and I'll get the value from taSource.text.
| | 02:43 | Then I as indicated in the previous video you
always close the FileStream when you are done.
| | 02:48 | Then I'll use the Alert class to display a pop up window and
tell the user that the operation is complete. I'll pass in
| | 02:55 | strings of File writing complete and then for
the title of the pop up window, Write to File.
| | 03:03 | I'll save the changes and run the application.
| | 03:08 | I'll click the button.
| | 03:10 | I should see an immediate message
indicating that the operation is complete.
| | 03:14 | I'll minimize the application and
Flex Builder, so I can see my desktop.
| | 03:19 | I'll see that the new file now exists
| | 03:21 | and I'll open the file in TextEdit, which is my favorite text
editor. You can use any text editor you like for this operation,
| | 03:29 | and you'll see the text that was written to the file is displayed.
| | 03:32 | Now to show that we're actually overwriting and creating a
new file from scratch each time, I'll close the text editor and
| | 03:39 | move the file to the Recycle Bin
| | 03:41 | or if you are on the Mac, to the Trash Can.
| | 03:43 | I'll go back to the application that's still running,
| | 03:46 | this time showing the desktop in the background
| | 03:49 | and I'll type in some additional text.
| | 03:59 | I'll click the Write to File button.
| | 04:01 | I'll get the message that the file writing is complete
and I'll see the file appears on the desktop immediately.
| | 04:08 | I'll once again open the file in my favorite text
editor and you will see all of the contents displayed.
| | 04:14 | So this is once again how you write text to a file.
| | 04:17 | You call the writeUTFBytes method. You pass in the string
value that you want to place into the file and then you make
| | 04:23 | sure that you close the FileStream when you're done.
| | 04:25 | When you use the writeUTF method, the string that you write to
the file is prefixed with the numeric value that indicates the
| | 04:32 | number of bytes in the file and then when you read the file
instead of using readUTFBytes you can instead use the simpler
| | 04:39 | method readUTF. But both approaches work
| | 04:42 | and in either case you can select from either
synchronous or asynchronous file operations.
| | 04:48 | If you're working with larger amount of text that might take
more than an instant to write to disk, you should always use
| | 04:54 | asynchronous operations, so that the file operation
doesn't result in suspending the main application thread.
| | Collapse this transcript |
| Using temporary directories| 00:00 | In this video, I'm going to describe how to create and use
temporary files and directories on the local file system.
| | 00:07 | The location of temporary files and directories is
different depending whether you are working on Windows XP,
| | 00:12 | Windows Vista or the Mac, but the API in AIR allows you
to use exactly the same code to work with these files
| | 00:19 | and directories, no matter which operating
system the application is deployed on.
| | 00:23 | For this demonstration I will use an application file
in the Chapter04BeginProject named TempDirsAndFile.mxml,
| | 00:31 | if you are following along with the
exercises open the file and the Flex folder.
| | 00:36 | The existing application has three methods called
closingHandler, createTempDir and createTempFile.
| | 00:42 | The createTempDir and createTempFile
functions are being called upon the click event
| | 00:47 | of two buttons at the bottom of the application.
| | 00:50 | Applications can create temporary directories the
whole content that is unique to the individual user
| | 00:55 | and also unique to the current application session.
| | 00:58 | If you are planning on creating
more than one temporary file,
| | 01:02 | it's a good idea to put them all in the same directory.
| | 01:05 | Use this code to create a temporary
directory as a file object.
| | 01:08 | First of all, place the cursor above the functions
| | 01:12 | and declare a private variable
named TempDir datatyped as a file.
| | 01:18 | Don't initialize the object yet, just
declared at the top of the functions.
| | 01:22 | Then go to the createTempDir function and add
this code TempDir equals File.CreateTempDirectory.
| | 01:31 | Now as I mentioned the actual physical location of this
directory is determined partially by the operating system
| | 01:37 | and partially by the Adobe Integrated Runtime.
| | 01:41 | Now trace the location of the file that was created.
| | 01:44 | Add a trace statement and pass
in the value TempDir.nativePath.
| | 01:50 | Remembering that the nativePath property always tells
you the actual location and name of a directory or file.
| | 01:56 | Now save and run the application in debug mode.
| | 02:00 | Click the createTemDirectory button
and you should see in the console
| | 02:06 | in Flex Builder a listing showing you
where the file was created and its name.
| | 02:12 | I'm working on Windows Vista and on
vista temporary files are created
| | 02:16 | in an AppDataLocaltemp folder underneath my home directory.
| | 02:21 | The name of the file starts with fla and ends with .tmp.
| | 02:24 | If you are working on Windows XP the location will be
similar, but the actual physical location will start
| | 02:30 | with documents and settings instead of users and if
you are working on Mac it will look very different.
| | 02:37 | The path of the file starts in a directory named private
which is under the volume route and then continues
| | 02:42 | on with the completely randomized file and directory name.
| | 02:46 | Now I'm going to be creating some spare files along the
way, so you might want to make a note of these files
| | 02:52 | and then go back later and clean them up
manually because temporary directories
| | 02:56 | and files are not cleaned up automatically by the runtime.
| | 02:58 | It's up to you as the developer to take
care of removing them when you are done
| | 03:02 | and I will show you how to do that
at the end of the exercise.
| | 03:06 | Close the application and return to the source code.
| | 03:09 | The code to create a temporary file is very similar.
| | 03:12 | Place your cursor at the top of the functions
| | 03:15 | and declare a private variable named
Temp File once again datatyped as a file.
| | 03:21 | Then go to the createTempFile method use this syntax
to create a new file, tempFile = File.createTempFile,
| | 03:32 | this not only creates a reference
to the location of the file,
| | 03:35 | but actually creates the file on disc at the same time.
| | 03:38 | Then once again call the trace
method and output to the console,
| | 03:41 | the location of the new temporary file,
using the syntax tempFile.nativePath.
| | 03:47 | Run the application in debug mode, click the
createTempFile button and you will see once again
| | 03:56 | in the console the location and name of the
newly created file, close the application.
| | 04:02 | Now I'm going to go to my temporary directory
and show you that the files have been created.
| | 04:06 | I'm going to select just the directory location
under which the file and the directory were created.
| | 04:12 | Copy that to the clip board and then in windows I can
find that file location easily by going to the start menu.
| | 04:19 | If you are working on Windows XP choose the run option,
if you are working on Windows Vista you can simply paste
| | 04:25 | in the location and press enter and that will open
the location of that directory in windows explorer.
| | 04:32 | Here's the temporary directory that I
created and here's the temporary file.
| | 04:37 | If you are working on Mac OS X,
you can follow the same steps.
| | 04:42 | Run the application in the debug mode, then click
the buttons to create a tempDirectory and a tempFile.
| | 04:49 | Leaving the application open, go to the
console and you will see the listing
| | 04:53 | of the location of the Temporary Directory in file.
| | 04:56 | Select the path that prefixes both of those file and
directory names ending with the string temporary items
| | 05:03 | and then copy that string to the clip board.
| | 05:07 | Next switch to Finder, in Finder go to
the menu and select to Go, go to folder.
| | 05:15 | You can also press the associated keyboard shortcut.
| | 05:18 | Paste that value into the dialogue box that
appears by pressing Command V and then click Go.
| | 05:24 | That should result in displaying the
temporary items folder for the current user,
| | 05:28 | you will see the name of the folder
and the name of the file.
| | 05:32 | Now as I mentioned, when you close down the application
these temporary files and directories are not cleaned
| | 05:37 | up for you, you are responsible for taking care of that.
| | 05:40 | I'm going to manually remove these
files from the tempDirectory
| | 05:44 | and then close Windows Explorer
and come back to Flex Builder.
| | 05:51 | In order to clean up the temporary files and
directories as you close the application you have
| | 05:56 | to detect that the application is closing.
| | 05:58 | You can do this through an event dispatched by
the windowed application component named closing.
| | 06:04 | I will be talking about this and other window based events
a lot more in the later chapter all about native windows.
| | 06:10 | For now just go to the code, place the cursor
right at the end of the windowed application tag
| | 06:16 | and add an event listener for the closing event.
| | 06:19 | Make sure you have selected the
closing event and not the close event.
| | 06:23 | Call the method that's already been created
closingHandler and pass the event object.
| | 06:31 | Now go to the closingHandler method and add code
| | 06:34 | to detect whether the temporary
directory and temporary file still exist.
| | 06:38 | For the directory use this syntax if tempDir.exists and then
within the condition clause called tempDir.deleteDirectory
| | 06:51 | and pass in a value of true meaning that you want
to remove all of its contents if there are any.
| | 06:58 | Do the same thing for the file, if tempFile.exists; and then
within that conditional block call the delete file method.
| | 07:09 | Finally at the end of both conditional
blocks add a trace command and indicate
| | 07:20 | when you are debugging temp file and dir delete.
| | 07:27 | Save your changes and once again
run the application in debug mode.
| | 07:32 | Now to demonstrate this once I have created
the Temporary Directory and Temporary File,
| | 07:36 | I will open up windows explorer side by side with the
application, so we can see the temporary directory and file
| | 07:42 | and see what happens as the application closes.
| | 07:45 | I will create the temporary directory
and the temporary file.
| | 07:50 | Next I will go copy the locations of the clipboard,
navigate to that location, again I'm using Windows Vista,
| | 07:58 | so I can simply paste the location into the start
menu and I will sort so I can see the files listed.
| | 08:05 | There is the temporary file on my system it was name
flaBEC.temp and the directory was named fla38C.temp.
| | 08:14 | Now I'm going to move my windows around so we can see both
these Temp Directory and the application at the same time.
| | 08:30 | Now I will close application so notice
that the application closes and the file
| | 08:35 | and directory created by the application are gone.
| | 08:38 | So that's how you manage temporary files and directories.
| | 08:41 | Now notice, in this particular temporary directory that
there are bunch of files there that start with Flex2_,
| | 08:47 | now those are temporary files that are actually
created by Flex Builder and to show you to the behavior
| | 08:53 | of an application that does a good job of cleaning
up after itself I will now close Flex Builder,
| | 08:59 | watching the temporary directory contents and you will see
that as Flex Builder closes everything is deleted from disc.
| | Collapse this transcript |
|
|
5. Working with HTML ContentUsing the Flex HTML component to create a browser| 00:00 | In this chapter I'm going to describe use
of the built-in HTML web browser component,
| | 00:05 | that's a part of the Adobe Integrated Runtime.
| | 00:07 | I described this component briefly in
the AIR 1.0 Essential Training title,
| | 00:12 | the Adobe Integrated Runtime includes a built-in web
browser kernel based on WebKit, the same kernel that's used
| | 00:18 | in the Safari web browser built by Apple.
| | 00:21 | This browser component is capable of
rendering and displaying complex HTML
| | 00:26 | that incorporates cascading style
sheets and complex JavaScript code;
| | 00:30 | in fact one of the most popular demonstrations you will
see of AIR applications is the use of Google Maps one
| | 00:36 | of the more complex and powerful Ajax based applications on
the market rendered in the context of a desktop application.
| | 00:42 | In this video, I will show you how to use the
basics of that HTML component and then later
| | 00:47 | in this chapter I will show you how
to use the more advanced techniques.
| | 00:51 | If you are following along with the
exercises, to get started you will need
| | 00:55 | to import a Flex Project archive
from the Exercises folder area.
| | 00:59 | From the Menu select File, Import, Flex Project,
click the Browse button next to Archive file,
| | 01:09 | go to your Exercises area which is on my Desktop and
navigate to the Chapter05 folder; you will find two files
| | 01:18 | with the .zip extension there Chapter05BeginProject.zip
and Chapter05EndProject.zip.
| | 01:25 | Select the BeginProject file and then when you come back
| | 01:28 | to the Import Flex Project dialog box
click Finish to import the project.
| | 01:34 | Then go the Flex Navigator view and open the project,
go to the source folder and open the file UsingHTML.mxml
| | 01:43 | which you will see as an empty Flex application.
| | 01:46 | Notice that the WindowedApplication tag in this
application doesn't have a layout property;
| | 01:51 | in AIR applications as with all Flex applications the
layout property defaults to a value of vertical meaning
| | 01:58 | that objects will stack vertically
as we place them in the application.
| | 02:02 | To get started in the application,
| | 02:04 | add an ApplicationControlBar container
and sets it dock property to true.
| | 02:10 | The ApplicationControlBar is a special container
that glues controls to the top of the application
| | 02:16 | and it's a great place to put controls
with which the user will interact.
| | 02:19 | Now below the ApplicationControlBar add
an HTML component, give it an id of web,
| | 02:27 | sets it height to 100% and its width also to 100%.
| | 02:34 | The result will be that the HTML component
that is the web browser component takes
| | 02:39 | up all available space in the application.
| | 02:42 | Now go the ApplicationControlBar and add three
components first Label, set the text property of the label
| | 02:50 | to Enter URL then add a TextInput control, sets
its id property to urlInput and finally a Button,
| | 03:04 | give the Button a label of GO and a click event handler that
executes a bit of ActionScript code that sets the location
| | 03:13 | of the HTML component that is the web browser
to the URL that's entered by the user.
| | 03:18 | This can be done with a single line of ActionScript code,
| | 03:21 | so I will do it with inline code rather
than creating a separate function.
| | 03:25 | The code looks like this, web.location
= urlInput.text, that's it.
| | 03:36 | You have just built a complete working web
browser application, save and run the application.
| | 03:41 | You will see that the three controls
the Label, the TextInput
| | 03:45 | and the Button appear in the top application control bar.
| | 03:48 | The central flight area of the
application is the web browser component
| | 03:52 | which defaults to a background color of white.
| | 03:55 | Click into the text input control and expand the size of the
window so that you can see as much of the resulting web page
| | 04:02 | as possible, then type in a complete URL starting
with http:// and then type in any web address.
| | 04:11 | I will type in www.adobe.com, then click the GO
button and you should see if you have Internet access
| | 04:20 | that the web page you requested is
loaded in to the browser component.
| | 04:25 | You should see that the browser is able to handle very
complex presentations including cascading style sheets,
| | 04:31 | any JavaScript code and of course Flash based presentations
| | 04:35 | such as the Flash video that's
currently playing on my screen.
| | 04:39 | To see a more complex example switch to maps.google.com.
| | 04:45 | One important note about entering the URL, you must
enter the entire URL including the http:// prefix.
| | 04:53 | This browser component unlike Internet
Explorer or Firefox does not know how to notice
| | 04:59 | that there is a missing prefix and add it for you.
| | 05:02 | Once again click the GO button and you should see
a fairly complex application, Google Maps up here.
| | 05:08 | Type in any address, for instance I will type in
the old headquarters of Macromedia, 601 Townsend St,
| | 05:15 | San Francisco then I will click Search Maps and
you should see that the map is loaded correctly.
| | 05:23 | Close the application and now we
will add a couple more tools.
| | 05:28 | Place your cursor after the Button still
| | 05:30 | within the ApplicationControlBar container,
add a Spacer and set its width to 100%.
| | 05:39 | A Spacer control is an invisible control
that pushes other objects around the screen;
| | 05:44 | by setting its width to a 100% it will take up all
available space within the ApplicationControlBar
| | 05:50 | and any controls we declare after the Spacer
will be pushed all the way to the right.
| | 05:56 | Now we are going to add back and forward
buttons just like a real browser.
| | 06:00 | Add another Button component, set its label
to Back and add a click event listener
| | 06:07 | and in the click event listener call web.historyBack(),
the historyBack() function is very similar
| | 06:14 | to a JavaScript command called history.back(); it
moves the browser back one step in its history.
| | 06:23 | Right after the back button, add another Button with
the label of Forward, add a click event listener
| | 06:30 | and when the click event for this button occurs
call the web components historyForward() method;
| | 06:36 | save your changes and once again run the application.
| | 06:40 | You should now see that the controls in the application
control bar at the top of the application include the label,
| | 06:48 | the text input and the GO button and over there
on the right the Back and Forward buttons.
| | 06:53 | Click into the text input control and type in a complete URL
to some web site; once again I will start at www.adobe.com,
| | 07:02 | click GO and you should see the first site up here.
| | 07:07 | Next type in another site, I will
change www.adobe.com to www.lynda.com;
| | 07:15 | once again click GO and you should see that site up here.
| | 07:20 | Now try clicking the Back button and you should go
back to the first site and click the Forward button
| | 07:26 | and you should go forward to the second site.
| | 07:29 | So that's the look at the basic features of the
HTML component, there's a lot more you can do
| | 07:33 | with this component including calling
JavaScript code from your ActionScript code
| | 07:39 | and that's what I'm going to show you in the next video.
| | Collapse this transcript |
| Using script bridging with ActionScript and JavaScript| 00:00 | In this video I'm going to describe how to
use the HTML component in the Flex application
| | 00:06 | and call JavaScript based functionality that's
hosted in the web page inside the HTML browser;
| | 00:11 | you will be calling this functionality from your Flex
ActionScript code emulating the JavaScript language.
| | 00:17 | For this demonstration I will use two files an
MXML application file named ScriptBridging.mxml.
| | 00:25 | If you are following along in the
exercises open that file now in Flex Builder
| | 00:29 | and then a web page file named WebPageWithJS.html,
right-click or Control click on the Mac on this file
| | 00:37 | in the Flex Navigator view and
select Open With, Text Editor.
| | 00:42 | If you double click on the file you will probably
end up opening it into Web Browser editor or instead
| | 00:46 | in seeing the page rendered instead
of seeing its source code.
| | 00:50 | The web page with JS file contains
a couple of simple functions,
| | 00:54 | a sayHello function that contains the window.alert method
to pop up a message from the JavaScript environment
| | 01:00 | and a setNameValue function that receives a value argument,
| | 01:04 | gets a reference to an input control
and sets that controls value.
| | 01:09 | Down below there is a heading one tag set
with a simple string, a very simple web page,
| | 01:14 | an input control who's click event calls the
sayHello function, a small data entry form,
| | 01:20 | another input control and another button.
| | 01:23 | Go back to the ScriptBridging application and run it, then
click into the URL text input control and type in the name
| | 01:31 | of the HTML page WebPageWithJS.html,
because you are loading this file
| | 01:38 | from the local hard disk you do not need an
http prefix or any other directory information.
| | 01:44 | The HTML file is in the same output folder as
your compiled application, click the GO button
| | 01:51 | and you should see your local web page loaded right away.
| | 01:56 | Now click the Say Hello button and you should see this
JavaScript pop up window displaying the string Hello
| | 02:02 | from JavaScript, click Okay then click the
Fill Value button and you should see a string
| | 02:09 | of My Name entered into the text input control.
| | 02:12 | Both of these functions are being
executed through JavaScript calls.
| | 02:15 | Now I'm going to show you how to make the
same calls from your ActionScript environment,
| | 02:21 | close the application and return to Flex Builder.
| | 02:24 | In order to make JavaScript calls to the web
browser environment you reference a property
| | 02:29 | of the HTML component named domWindow.
| | 02:33 | This property references the document object that's at the
root of your entire HTML environment in the web browser;
| | 02:40 | so for example if you wanted to call the standard
window.alert function that's a part of JavaScript
| | 02:46 | but you want it to execute it from within your
ActionScript environment, the syntax would look like this,
| | 02:52 | you would start off with the id of your
web browser object which I have called web
| | 02:57 | and then reference its domWindow property.
| | 03:00 | Notice it's spelled with an upper case W in the middle.
| | 03:03 | Then call it whatever methods you want to, so for
instance if I wanted to pop up a window directly
| | 03:08 | and pass in a simple string I could call the alert method,
type in a string, I will put in a string of Hello from Flex.
| | 03:18 | This function is already being called upon the click event
of the first Button down here labeled called JavaScript,
| | 03:24 | I will save the changes, run the application.
| | 03:29 | Once again I will type in the name of the file I want
to view, WebPageWithJS.html, click the GO button.
| | 03:39 | Now I will click the Flex Call JavaScript
button and you will see the exact same behavior.
| | 03:44 | A native pop up window displayed
by the JavaScript environment,
| | 03:48 | click Okay to clear the window
and then close the application.
| | 03:53 | You can also make calls to custom JavaScript
functions, for instance in this page
| | 03:58 | that we are loading there is a function
named sayHello that calls the alert method.
| | 04:02 | So I will go back to the Flex application,
ScriptBridging.mxml.
| | 04:09 | I locate the callJSFunction() method and I
will put in this code web.domWindow.sayHello().
| | 04:18 | Both JavaScript and ActionScript are case sensitive
environments so you must make sure to spell the names
| | 04:23 | and your method calls exactly the same
as they are spelled in the web page.
| | 04:27 | I will save my changes and run the application;
| | 04:31 | once again I will load the page
WebPageWithJS.html and click GO that loads the page.
| | 04:41 | Now I will call the JavaScript
function that's hosted by the page
| | 04:45 | and you will see once again that
the pop window is displayed.
| | 04:48 | I will click Okay to clear the
window and close the application.
| | 04:52 | The web page also has a function called setNameValue,
its getting referenced to an element by its id nameInput
| | 05:00 | and setting its value; this is the equivalent in JavaScript
of setting the text property of a text input control.
| | 05:07 | In order to call this method I'm going to have to pass in
a value, so I will go back to the callJSFunction method,
| | 05:14 | add a line of code above the current call and now I'm
going to call the method within the JavaScript code
| | 05:20 | which is you remember is named
setNameValue using the same syntax as before,
| | 05:26 | web.domWindow.setNameValue and
now I will pass in my name, David.
| | 05:35 | I save the changes and run the application;
once again load the page, click the GO button.
| | 05:46 | Now I will click the Call JavaScript
Function button and you will see
| | 05:50 | that in the background my name has been
filled in the browser hosted text control.
| | 05:56 | So those are the basics of Script Bridging
going between ActionScript and JavaScript.
| | 06:01 | There are some limitations here, for instance you
can't call the get element by id function directly
| | 06:06 | from your ActionScript code because you don't have
the ability to get a direct reference to objects
| | 06:11 | within the web page but you can make most things happen that
you might want by calling functions either that are built
| | 06:18 | into the web environment or custom functions
that you have added to the page yourself.
| | Collapse this transcript |
| Understanding AIR security in JavaScript| 00:00 | In this video I'm going to describe some of the rules that
govern security in AIR applications particularly in regard
| | 00:07 | to which code you can execute and what assets or resources
on the local system that code can access at runtime.
| | 00:14 | Error is built around the concept of security sandboxes,
the capabilities of a particular set of code are determined
| | 00:21 | by the origin of the code and how that affects what's
it allowed to touch in the application environment.
| | 00:28 | Each security sandbox has equivalent permissions,
for example dynamic code that's loaded at runtime
| | 00:34 | from a web based resource cannot be allowed to touch the
local file system, local database or other local resources
| | 00:42 | because that code has not gone through your security
framework and the user hasn't explicitly accepted
| | 00:47 | that code during the installation process,
its not allowed to touch that outer world,
| | 00:52 | that's how security sandboxes are designed.
| | 00:55 | In the classic world of the web browser for example
JavaScript code that's loaded either as part
| | 01:00 | or linked to a web page can touch anything
within that web page and anything else
| | 01:05 | within the web browser security sandbox but
can't move outside the security sandbox.
| | 01:11 | Now the reason this is so important in the world
of AIR is because as soon as you start working
| | 01:16 | with the web browser component you actually have the
ability to download code and execute it at runtime.
| | 01:22 | The question is what is that code allowed to do?
| | 01:26 | There are five security sandboxes known
as the application, remote, local-trusted,
| | 01:31 | local-with-networking and local-with-filesystem sandboxes.
| | 01:36 | I am going to describe each of these
sandboxes, which code is considered to be a part
| | 01:40 | of that sandbox and what that code is allowed to do.
| | 01:44 | The application sandbox consist of everything
within the application folder that is everything
| | 01:50 | that you can reach either through the app:/
URI or through file.application directory.
| | 01:57 | As I have mentioned within previous chapters,
content within that folder cannot be modified
| | 02:02 | by the Flex application itself at runtime
but code within that folder does have access
| | 02:07 | to all other local resources such
as the filesystem and database.
| | 02:11 | Application based code gives you access
to all the privileged AIR system APIs;
| | 02:16 | the APIs that modify the filesystem of the
database and network communication capabilities.
| | 02:22 | On the other hand you cant dynamically import code and
execute it directly from within the application area
| | 02:28 | and for the most part dynamic code
generation techniques are disallowed as well
| | 02:33 | because the application environment contains code that
for the most part has been complied or otherwise checked,
| | 02:39 | that code can touch the local filesystem
but code that you download
| | 02:43 | from outside the application domain
cannot be allowed to do the same.
| | 02:48 | The remote sandbox consists of all the code
that's downloaded from the Internet at runtime
| | 02:54 | such as JavaScript code that's a
part of or linked to a web page.
| | 02:58 | The rules for this code are pretty much the same as classic
web browsers, there are actually a few more restrictions
| | 03:04 | than in a classic web browser environment
because the AIR environment does give you
| | 03:08 | so much access to the local system.
| | 03:10 | If you download Flash documents or Flex applications
at runtime the rules for that code are the same
| | 03:16 | as when the code is run in the Flash Player that is if you
use the HTML component and download a Flex application just
| | 03:24 | because that Flex application is running
in an AIR environment doesn't mean the code
| | 03:28 | within the downloaded application can get to the local
filesystem, it cant and that's the way you want it.
| | 03:34 | This means that any code that the user is running
that's accessing their local resources is code
| | 03:40 | that they have explicitly accepted
during the installation process
| | 03:43 | and not code that's just been arbitrarily downloaded.
| | 03:47 | There are three other sandboxes that apply to locally
stored content, local-trusted content is stored locally
| | 03:54 | and has been explicitly marked as trusted using either the
Flash Player Settings Manager or trust configuration file.
| | 04:02 | These files can read from local data sources and
can communicate with the Internet and don't have
| | 04:07 | to be loaded into the application directory.
| | 04:10 | On the other hand there are some limitations
to the privileges accorded this code
| | 04:14 | that are only available through the application sandbox.
| | 04:18 | The next sandbox is called local-with-networking.
| | 04:22 | This kind of content is made up of a SWF file
that's published with a networking designation
| | 04:28 | that is that's been compiled with networking built-in.
| | 04:31 | Only SWF based content can be considered to be a part of
this sandbox; it does have not to be explicitly trusted
| | 04:38 | by the user to do what it does and it can
communicate with the Internet but it cannot read
| | 04:44 | from local data sources or the local filesystem.
| | 04:48 | Finally, the local-with-filesystem sandbox,
local scripting files are a part of this sandbox
| | 04:54 | when they have not been published with a networking
designation and have not been explicitly trusted.
| | 04:59 | This includes JavaScript files that have not been explicitly
trusted and are not a part of the application sandbox.
| | 05:06 | These files can read from local data sources
but can't communicate with the Internet.
| | 05:11 | There's a lot to know about AIR security and there is some
great resources to help you out with a lot of the details.
| | 05:17 | Here are two article and documentation recommendations,
| | 05:21 | first an article on the AIR Developer
Center at introduction_to_air_security.html.
| | 05:27 | This article covers the basic idea of sandboxes and
describes at a high level what sandboxes are for
| | 05:33 | and what they do and more detailed document
air_security.pdf, at this URL which goes much more in-depth
| | 05:41 | into the world of security in AIR applications.
| | Collapse this transcript |
|
|
6. Using Native WindowsDefining and instantiating native windows| 00:00 | In this chapter of the video series, I'm going to
describe how to define and instantiate Window components
| | 00:06 | that is components that implement
the native window interface,
| | 00:10 | and can float freely independently
of the main application Window.
| | 00:14 | I will be showing you how to create these
Window components, how to instantiate them,
| | 00:18 | how to control the Window appearance,
control the order of display on the screen,
| | 00:23 | and many other facets of Window management.
| | 00:25 | If you are following along with the exercises, go
to Flex Builder, and import Flex project archive.
| | 00:31 | From the Menu, select File, Import, Flex Project.
| | 00:36 | Click the Browse button next to Archive File, navigate
to the Chapter 06 Folder underneath the Exercises area,
| | 00:44 | and import the file Chapter 06 beginproject.zip.
| | 00:49 | Once the project has been imported, open it in
the Flex navigator view, open the source folder
| | 00:57 | and then open the application file DisplayWindow.mxml.
| | 01:02 | This is a beginning application
with just a little bit of code.
| | 01:05 | There are two empty ActionScript
functions named openWindow and closeWindow,
| | 01:10 | and two buttons whose click events
result in calling these functions.
| | 01:13 | To create a native Window in Flex, you create a custom
MXML component that's extended from the Window class.
| | 01:21 | The Window class is similar to
the WindowedApplication class.
| | 01:25 | It represents rectangular area that's actually an
operating system's specific native Window rather
| | 01:31 | than a simple Flex container.
| | 01:33 | When you open a window component, it
results in creating a pop up window
| | 01:38 | that floats independently of the rest of the application.
| | 01:40 | As with all custom Flex components, I recommend
that you create these components in sub-folders
| | 01:46 | of your project rather than in the project source route.
| | 01:49 | In the project, Chapter 06 Begin, there
is already a folder named Windows.
| | 01:54 | All of the native window components I create
in this chapter will be placed in this folder.
| | 01:59 | To create a new native window component, go to the
Project, Right Click on the Windows Folder or Ctrl+Click
| | 02:05 | on the Mac, and select New MXML Component.
| | 02:10 | As with all MXML components, the
file name determines the class name.
| | 02:15 | Give this new component a file name of MyNativeWindow.mxml.
| | 02:20 | In the Based on selector, select Window.
| | 02:24 | As with all Flex components, you can either set the width
and height to absolute values or you can leave them blank.
| | 02:30 | The window will set its height dynamically
to accommodate its child objects.
| | 02:35 | Also as with the Panel, Title Window,
and the application component,
| | 02:39 | the Window component supports the layout property, which you
can set to values either absolute vertical or horizontal.
| | 02:46 | For this first Window component, set the
layout to a value of Absolute and Click Finish.
| | 02:53 | Notice that the custom component code is simply an
MXML component with the root element of mx:Window.
| | 03:00 | As I mentioned earlier, the layout property and the
height and width are set in the Window component.
| | 03:05 | There is also a property you can set here called Title.
| | 03:09 | The Title property determines the value on the
Title Bar of the Window when it appears on screen.
| | 03:14 | So give this Window a title property of My Native Window.
| | 03:18 | Next, create a label component within the Window.
| | 03:24 | Give it a text property once again of My Native Window, and
set its Font Size to 14 pixels, and its Font Weight to Bold.
| | 03:37 | Also, to make the label center automatically in the
Window, use constraint properties of vertical center set
| | 03:43 | to 0 and horizontal center also set to 0.
| | 03:47 | Save your changes.
| | 03:49 | That will be your first Native Window Component.
| | 03:51 | Now go to the application DisplayWindow.mxml.
| | 03:55 | Place the cursor in the openWindow function.
| | 03:58 | I'm going to maximize the Editor to see all of the code.
| | 04:01 | In order to open a Window, you
first instantiate the component.
| | 04:05 | In order to be able to control the Window
object from any code in the application,
| | 04:10 | declare the variable that references
the Window outside of any functions.
| | 04:14 | Place the Cursor above the openWindow
function and make some space.
| | 04:18 | Then declare a new private var named win and data
type it as an instance of the class My Native Window.
| | 04:26 | Notice, as I select the class from
the list of available classes,
| | 04:30 | Flex that are automatically create an import statement.
| | 04:33 | As with all Flex components in action
script classes, you can import the class
| | 04:37 | and then you can reference it only by its class name.
| | 04:40 | Now, go to the openWindow function.
| | 04:42 | I have declared the win variable which is an instance
of My Native Window, but I still have to instantiate it.
| | 04:49 | So in the openWindow method, I'll call it this code,
win = new MyNativeWindow, and I'll construct the object
| | 04:58 | from the My Native Window components,
automatic no arguments construct a method.
| | 05:03 | Next, I'll open the Window on screen
using this syntax win.open.
| | 05:08 | The open method takes an optional
argument, Open Window Active.
| | 05:12 | If set to false, that means open the Window
but don't make it the currently active Window.
| | 05:16 | If you leave this argument out or you set the value
to true, the Window opens and is automatically active,
| | 05:22 | that is it automatically has focused in the Windows
environment, because I do want the Window to be active
| | 05:28 | and because that's the automatic default value of
this argument, I don't need to pass the value in.
| | 05:32 | I will save the changes and run the application.
| | 05:36 | I will Click the Open Window button and you will see
the Native Window appears on screen, and in contrast,
| | 05:44 | a pop up Windows that are completely built within
the Flex environment such as those that are produced
| | 05:48 | by the Alert class or that you create as custom pop
up Windows using the Title Window or Panel containers,
| | 05:55 | this native Window floats independently
of the rest of the application.
| | 06:00 | I will close the Window and then close the application.
| | 06:04 | Now, let's add code to close the Window.
| | 06:06 | I will go to the closeWindow function,
and call the method win.close.
| | 06:11 | Now, after I close the Window, I'm also going to
set the reference to the Window to a value of null.
| | 06:17 | This one is sure that I'm cleaning up after myself closing
down and then destroying references to any existing Windows.
| | 06:24 | This sort of good clean up architecture
prevents memory leaks in your application.
| | 06:28 | Save the change, run the application once again,
try opening the Window, move it off to the side.
| | 06:36 | Click back on the application and Click Close
Window and you should see that the Window closes.
| | 06:42 | Finally, go back to My Native Window
and go onto Design View.
| | 06:48 | I'm going to Restore the Design View
Editor, and then go to the Components View,
| | 06:53 | and drag in a button component and
place it right under the label.
| | 06:57 | I will change the label on the button to
close, and then I'll go back to Source view.
| | 07:03 | I would like to show you that a Window can also
close itself by calling its own close method.
| | 07:10 | I will add a click event handler to the
button component, and then call Close.
| | 07:16 | Save the change, go back to the application and run it.
| | 07:21 | Once again I will open the Window from the
application, and this time I will close the Window
| | 07:26 | from the Window itself, and then close the application.
| | 07:30 | You can see there would still be some more work to do.
| | 07:32 | For instance, in the closeWindow method, if you try to
close it and it was already closed, you might actually have
| | 07:38 | to check first to see whether it was
visible or whether it had been instantiated.
| | 07:43 | Similarly, in the closeWindow method, if the user has not
opened the Window yet, you have to do a little bit more work
| | 07:49 | to make sure you are not trying to reference a null object.
| | 07:52 | But, those are the basics of how to construct
a Native Window and then how to open it
| | 07:56 | and close it using code that's both in the
application and in the Window component itself.
| | Collapse this transcript |
| Controlling native window appearance| 00:00 | In this video, I'm going to describe how to control
the visual appearance of native Windows that you define
| | 00:06 | and instantiate in your AIR applications.
| | 00:08 | For these demonstrations, I'll use an application
named windowappearance.mxml in the Chapter 6 Project.
| | 00:16 | If you are following along with the
exercises, open that application now.
| | 00:19 | I will also use a custom component in the
Windows Folder named MyNativeWindow2.mxml.
| | 00:26 | Once again, if you are following along with the
exercises, open that source code file as well.
| | 00:30 | MyNativeWindow2.mxml is a custom component that looks pretty
much like the version I created in the previous video.
| | 00:37 | It uses MX Window as its root element, has its layout
property set to Absolute, and positions a label
| | 00:43 | and a button control in the center of the Window.
| | 00:46 | The Window appearance application
instantiates the component and opens it
| | 00:51 | and then in the Close Window function this time,
| | 00:54 | checks to see whether the Window component
is null or not, and then closes it.
| | 00:59 | I'll run the application, so we can remind ourselves
of the appearance of a default native Window.
| | 01:04 | I will Click the Open Window button, and you
will see that the Window adopts the chrome
| | 01:09 | or the visual appearance of the hosting operating system.
| | 01:13 | I'm running on Windows Vista.
| | 01:14 | So the Window has an appearance that's
provided by the Vista operating system.
| | 01:19 | I see the Application icon in the upper left hand corner.
| | 01:22 | If I Click the Icon, I get the Control menu.
| | 01:25 | And I also see the various controls in
the upper right corner of the Window
| | 01:29 | to Minimize, Maximize and Close the Window.
| | 01:32 | This chrome or visual appearance will look different
depending on which operating system you are running on.
| | 01:38 | If you are running on Windows XP, then number and
positions of the control should be about the same,
| | 01:43 | but the visual appearance will be a little bit different.
| | 01:46 | And if you are running on Mac OS X, the number and
presentation of the controls will be quite a bit different.
| | 01:51 | It will essentially be a Mac OS X Native Window.
| | 01:54 | I will close the Window and the
application, and return to the code.
| | 01:59 | In order to control the appearance of the native Window
component, you can set properties either declaratively
| | 02:05 | in the MXML declaration of the component or
programmatically at run-time before you open the Window.
| | 02:11 | I'm going to show you in this demonstration,
how to set these values using MXML attributes.
| | 02:16 | The default appearance of a Window uses
a property called system chrome set
| | 02:20 | to a value of standard, and a type set to normal.
| | 02:26 | When you run the application with
these settings active on Windows,
| | 02:29 | you will notice that the native Window is represented
by its own icon in the Task Bar, and you can switch back
| | 02:36 | and forth between the main Window and the
additional native Window by Clicking on those Icons.
| | 02:43 | In this example, I'm going to set the
type of the Window to a value of utility.
| | 02:49 | A utility Window has fewer controls than a normal Window.
| | 02:53 | In Windows, it's also not represented on the Task Bar.
| | 02:56 | I will save the changes, go back to
the application, and run it again.
| | 03:01 | I will Click the button to open the native Window again.
| | 03:04 | And this time, the native Window has a different appearance.
| | 03:07 | In the upper right corner on Windows
Vista and XP, there's only a Close icon
| | 03:11 | where before there was a Minimize, Maximize and a Close.
| | 03:15 | And the upper left corner, you don't
see the Application icon anymore.
| | 03:19 | Also, if you look down at the Task Bar in Windows,
| | 03:22 | you will see that the Utility Window
is not represented by a separate icon.
| | 03:25 | I will close the Window and close the application,
and once again return to the component code.
| | 03:32 | Here's another property that you can set
to get a different look to your Window.
| | 03:36 | The systemChrome property can be set to one of two values.
| | 03:40 | The default value of standard means that the operating
system chrome is used to decorate the borders of the Window.
| | 03:46 | If you instead set the value of systemChrome to none,
that means take away the operating system chrome
| | 03:52 | and just show the chrome that's provided
by the underlying Flex framework.
| | 03:57 | I will go back to Window Appearance
and run the application again.
| | 04:00 | I will open the Window, and this time you will see
that the look of the Window is dramatically different.
| | 04:06 | I still have Minimize, Maximize and Close buttons,
but their appearance is quite a bit different.
| | 04:11 | Also, if I Click in the upper left corner
which I just did, I don't get a Control menu.
| | 04:16 | That's provided only by the operating system.
| | 04:18 | Once again I will close the Window and the
application, and return to the component code.
| | 04:25 | The next property I will show you is called
showFlexChrome which I'll set to a value of false.
| | 04:30 | I will also at the same time set systemChrome to none.
| | 04:34 | I'm going to set three values together,
showFlexChrome = false,
| | 04:39 | systemChrome = none, and this time Type = lightweight.
| | 04:46 | I'll save the changes, run the application again and
once again open the Window, and this time you will see
| | 04:54 | that the native Window shows up as just a white
background without any chrome on the outside.
| | 04:59 | I can still close the Window by pressing the appropriate
keyboard shortcut or by Clicking the Close button.
| | 05:05 | So I will close the Window, close
the application one more time,
| | 05:09 | then I'll come back to native Window, and set some styles.
| | 05:12 | Finally, I'm going to set one more property
transparent, set to a value of true.
| | 05:18 | When showFlexChrome is false, systemChrome is none, type
is lightweight and transparent is true, here is the result.
| | 05:26 | I will run the application.
| | 05:27 | I will open the Window, and all I'm seeing now is the
actual Label and Close button that are a part of the Window.
| | 05:35 | I will close the Window, close the
application, come back to the component again.
| | 05:41 | And this time, I'm going to wrap the label and the
button in a V Box with a background color and a border.
| | 05:47 | I will set the background color to an off white of # EEEEEE.
| | 05:53 | Give the V Box a Border Style of Solid and
a Border Color of Black which is #000000.
| | 06:06 | Then, I'll move the label and button inside the V Box,
give the V Box some padding settings, padding top of 10,
| | 06:15 | padding bottom of 10, padding right
of 10, and padding left of 10.
| | 06:23 | And I'll also set the horizontal align to
center, and the vertical align to middle.
| | 06:31 | Because I'm placing these objects now
within a V Box which automatically lines
| | 06:35 | up its object in a single column from top to bottom.
| | 06:39 | I'll remove constraint and absolute layout properties.
| | 06:43 | Such as X, Y vertical center and horizontal center.
| | 06:47 | I will save the changes, run the
application again, open the Window.
| | 06:53 | And this time, you will see that the Window appears
as a transparent object without any system chrome.
| | 06:59 | Now, in the next video, I will show you
how to work with the transparent Window,
| | 07:03 | and make it move across the screen
when the user Clicks on it and Drags.
| | Collapse this transcript |
| Using transparent windows| 00:00 | In this video, I'm going to describe how to
initiate movement with the transparent Window.
| | 00:05 | When you takeaway the system chrome from a Window,
you remove the ability to capture mouse down events
| | 00:11 | and initiate tracking of the Window
position with the mouse movement.
| | 00:15 | If you want the user to be able to move a
transparent Window, you have to program it.
| | 00:20 | It's a small amount of code, but it's something
you become responsible for as the developer.
| | 00:24 | For this demonstration, I'll use an application
named UsingTransparentWindows.mxml that's
| | 00:31 | in the Chapter 6 Project.
| | 00:33 | I'll also use a component that's in the
Windows folder named MyTransparentWindow.mxml.
| | 00:39 | The code for my transparent Window is pretty much the same
as myNativeWindow2 as it was at the end of the last video.
| | 00:46 | It presents a transparent window that contains
a V Box with a certain color and background.
| | 00:51 | Mouse down events on the V Box will be handled
correctly, but because the outer window is transparent,
| | 00:58 | any mouse down events outside the V Box will be ignored.
| | 01:01 | I'll run the application, and Click
the button to open the Window.
| | 01:07 | When the Window opens, it appears in
the upper left hand corner of my screen.
| | 01:11 | It may appear in a different position
depending on your operating system.
| | 01:14 | If I Click down on the Window, as I'm doing now,
| | 01:17 | and then start to initiate mouse
movement, notice that nothing happens.
| | 01:21 | Also notice that if I Click off the V Box,
the background application takes focus.
| | 01:27 | I will come back to the Main Window,
Click the Close Window button to make sure
| | 01:31 | that the top level Window has been
closed and then close the application.
| | 01:35 | One issue that you might run into when you are working
with Native Windows in Flex is that sometimes you end
| | 01:40 | up with an invisible Window, and
you don't even know it's present.
| | 01:44 | When there is an invisible window present, you won't be able
to launch another application because the AIR Debug launcher
| | 01:50 | which is running the application in
the background is still in memory.
| | 01:53 | If you have this symptom that you are not able to run
an application, go to the Task Manager on Windows,
| | 02:00 | and check the processes list, and
look for something named ADL.exe.
| | 02:05 | Now, I don't have that as an issue right now.
| | 02:07 | I don't see ADL.exe listed here, but if I did,
I would select it, and then Click End Process.
| | 02:14 | If you are working on Mac, you can Click on
the Apple menu, and then select Force Quit,
| | 02:19 | and once again look for the ADL application.
| | 02:22 | And if you see it, Click that application, and then
you will be able to launch your next application.
| | 02:28 | Now, I would like to be able to move the Window
across the screen when the user Clicks and Drags.
| | 02:33 | I showed how to do this technique in the
AIR 1.O Essential Training video series.
| | 02:38 | I did it in that case with a full application.
| | 02:41 | Here, I will do the same thing with the native Window.
| | 02:44 | I will go to the MyTransparentWindow.mxml code, and I will
add a mouse down event listener to the Window component.
| | 02:54 | When the user presses the mouse button
while the cursor is over any visual part
| | 02:58 | of the Window, I will get a mouse down event.
| | 03:00 | I will react by calling this code
this.stage.nativeWindow.startMove.
| | 03:11 | Notice that I'm calling the start move method
from the native window object of the current stage
| | 03:16 | that is the visual presentation area of the current Window.
| | 03:20 | When the user clicks down, I will start the move operation.
| | 03:23 | As long as the user keeps the Mouse Button pressed, and
they move the Mouse around, the position of the Window
| | 03:28 | on the screen will track with the mouse movement.
| | 03:31 | When the user releases the Mouse
button, the movement will stop,
| | 03:35 | and you don't have to do any programming to make it stop.
| | 03:37 | I will save the change, and run the application again.
| | 03:41 | I'll once again open the Window, and
this time I can Click on the Window,
| | 03:47 | and drag it around the screen as much as I want to.
| | 03:49 | Once again when I release the Mouse button
as I will now, and then move the Mouse again,
| | 03:54 | you will see that the Window stops moving by itself.
| | 03:57 | So that's how we handle transparency
and window movement in AIR.
| | 04:01 | You handle the mouse down event on the Window
level, and then you call that start move method
| | 04:06 | as a method of the stages native Window object.
| | Collapse this transcript |
| Working in Full Screen mode| 00:00 | In this video, I'm going to describe the use of Full
Screen display when working with native Windows.
| | 00:05 | All native Windows including an AIR application Window and
any other native Windows that you instantiate and display
| | 00:12 | in an AIR application can be spread
out to take up the entire screen space.
| | 00:17 | When you set a native Window to Full Screen, it gets
rid of all of the system chrome that is the Title Bar
| | 00:22 | and any other controls around the Window,
and expands to fill your whole screen.
| | 00:27 | For this demonstration, I'll use an
application named FullScreen.mxml
| | 00:32 | which you will find in the Chapter 06 Begin Project.
| | 00:35 | If you are following along with the exercises,
open the application in Flex Builder.
| | 00:39 | I am also using a component in the Windows
folder named MyFullScreenWindow.mxml.
| | 00:46 | This component has two empty methods
named displayFullScreen and displayNormal.
| | 00:52 | Each method is called upon a click event of a button.
| | 00:55 | I will go back to the application and run it, and
then Click the button to open the native Window,
| | 01:01 | and show you that it looks like a normal
Window with complete system chrome.
| | 01:05 | I will close the Window and close the application.
| | 01:08 | Then, I'll go back to the component MyFullScreenWindow.mxml.
| | 01:13 | To change Window to display in Full Screen mode, you
set the Windows stage object's display state property
| | 01:19 | like this this.stage.displayState, and
then you set it to one of three values,
| | 01:28 | Full Screen, Full Screen Interactive and Normal.
| | 01:32 | These String values will represent those
constants in a class named Stage Display State
| | 01:38 | which you call like this StageDisplayState.Full_Screen.
| | 01:43 | I will also go down to the function
Display Normal, and put in similar code.
| | 01:50 | This time change it back to a normal display,
| | 01:53 | this.stage.displayState = StageDisplayState.Normal,
and that's all you have to do.
| | 02:04 | Now, when the user Clicks the Full Screen button,
this Window will expand to take up the entire screen,
| | 02:09 | and when they Click the Normal button, it
will showing back down to its original size.
| | 02:13 | I will save the changes, and return
to the application and run it.
| | 02:18 | I will Click the Open Window button,
and there's my native Window.
| | 02:21 | Notice, like all native Windows,
I can drag it around the screen.
| | 02:25 | I will Click the Full Screen button, and the
Window expands to take up the entire display.
| | 02:31 | Now, I'll Click the Normal Display button,
and it returns to its original size.
| | 02:36 | The user can also control and turn
off the Full Screen display.
| | 02:40 | I will Click the Full Screen button again.
| | 02:42 | It expands to take up the entire display.
| | 02:45 | And now, I'll press the Escape key and
notice that the behavior is the same.
| | 02:50 | It returns to normal.
| | 02:51 | Again, you can do this with any native Window, the
application or any other native Window that you pop
| | 02:57 | up from the application simply by setting
its stage object's DisplayState property.
| | Collapse this transcript |
| Changing the order of multiple windows| 00:00 | In this video, I'm going to describe how to control
of the order of Windows in an AIR application.
| | 00:05 | When you open multiple native Windows,
they sometimes overlap each other
| | 00:10 | and they are presented in what's called the Z order.
| | 00:13 | Z order is the relative depth of
Windows relative to each other that is.
| | 00:17 | The reason it is called the Z order is
because it is one of the three dimensions,
| | 00:21 | X being Horizontal, Y being vertical and Z being the depth.
| | 00:25 | You can control the order of the native Windows using
methods of the Window object named order to front,
| | 00:31 | order to back, order to front off,
order to back off and activate.
| | 00:36 | So in this video, I will demonstrate
a couple of these methods,
| | 00:39 | I will be working in an application
named OrderingWindows.mxml.
| | 00:45 | If you are following along in the exercises, you
can open this application from the Chapter6 Project.
| | 00:51 | The application declares three instances of native Windows,
| | 00:54 | one for each of three components
OrderedWindow1 OrderedWindow2 and OrderedWindow3.
| | 01:01 | These three components are very simple Windows
that are almost identical to each other,
| | 01:05 | the only difference being their titles and background
colors, one is red, one is green and one is blue.
| | 01:10 | I will run the application and show you that when I click
the Open Windows button, all three Windows are opened.
| | 01:19 | Window 1, Window 2, and Window 3.
| | 01:23 | The application is set up to handle an event called closing
| | 01:26 | and when that event happens it automatically
closes all of its native Windows.
| | 01:31 | So all we have to do to close all the Windows is just
close the application Window and I'm back to the start.
| | 01:37 | Now, I would like to control the order
programmatically of these Windows.
| | 01:42 | In the application display area, down at the bottom
| | 01:44 | of the code there are three buttons
labeled Window 1, Window 2, and Window 3.
| | 01:50 | And for this demonstration when the user clicks each
button, I want to bring that Window up to the front.
| | 01:56 | So I will add a clickEventHhandler for the first
button and when the user clicks the button,
| | 02:01 | I will call this code win1.orderToFront().
| | 02:07 | I will do the same thing for each of the other two buttons.
| | 02:09 | Click equals (=) win2.orderToFront() and for the
third button click equals (=) win3.orderToFront().
| | 02:19 | I will save the changes and run the application.
| | 02:24 | Once again, when the application opens
up I will click the Open Windows button,
| | 02:27 | I will get all three Windows open on the screen.
| | 02:30 | I will move them around a little
bit so we can all three of them.
| | 02:33 | Then I will come back to the application
Window and click each of the buttons.
| | 02:38 | Clicking Window 1, Window 2 and Window 3 and once again
| | 02:44 | when I close the application, all
of the Windows close automatically.
| | 02:48 | Now, I will change the code so that instead
of orderToFront() I use orderToBack().
| | 03:00 | I will save the changes and run the application.
| | 03:06 | Once again opening the Windows and then moving them
around on the screen so that I can see them all
| | 03:12 | and now I will click the buttons in
reverse order this time sending each Window
| | 03:16 | to the back, Window 3, Window 2 and Window 1.
| | 03:21 | Notice that the Window Z order takes into account not
just AIR-based Windows, but all native application Windows
| | 03:27 | and because I have Flex Builder already running on the
screen, the other Windows are ordered behind that Window.
| | 03:33 | So I will close the application again.
| | 03:36 | This time I will use a function called orderInFrontOf and I
will pass in a value of (this), meaning the current Window,
| | 03:43 | and I will do the same thing for all three Windows.
| | 03:54 | I will save my changes once again run the application.
| | 03:58 | I will open all three Windows, once again I will move
them around so that I can see them all on the screen.
| | 04:05 | And now when I click each button, notice that the
order of the Windows is changing in a minor way.
| | 04:10 | I will click Window 1, Window 2, and
Window 3 and you will see each time,
| | 04:17 | I click the button the Window order is changing, but
the Windows are not disappearing behind Flex Builder.
| | 04:22 | Once again, you can use the activate function as well and
that also has the meaning of bringing a Window up to the top
| | 04:29 | of the Z order so that it overlaps any other Window.
| | 04:32 | So those are some methods of the Window
Class that you can use to control the order
| | 04:37 | of multiple native Windows in an AIR application.
| | Collapse this transcript |
| Handling window events| 00:00 | In this video I'm going to describe the events that
are dispatched when you manipulate native windows.
| | 00:05 | I will be using the application WindowEvents.mxml, this
application creates an instance of a native window based
| | 00:12 | on the OrderedWindow1 component
that was used in a previous video.
| | 00:16 | I will run the application and show that right now all it
does is open the window so that we can then manipulate it.
| | 00:23 | I can then close the window by clicking the Close Window
button or by clicking the controls on the window itself.
| | 00:29 | I will close the application and return to Flex Builder.
| | 00:33 | You can listen for and react to any of the events
that occur as the user manipulates the native window.
| | 00:39 | It is worth looking at the help system for the Window class.
| | 00:42 | This class dispatches many events
having to do with window manipulation.
| | 00:46 | For instance when the window is closed
there are two events that are dispatched,
| | 00:50 | one named closing which is dispatch before
the close happens and one named close
| | 00:55 | which happens after the window has been closed.
| | 00:58 | Similarly, there is one called Display State Changing,
for when the display state is changing to Minimize,
| | 01:03 | Maximize or restore and one that occurs named Display State
Change that is dispatched after the change has happened.
| | 01:09 | There is a Resizing and a Window Resize.
| | 01:12 | Now many of these events are dispatched
as simple event objects.
| | 01:17 | For instance the Close event is
dispatched as flash.events.Event.
| | 01:22 | The same thing is true for the Closing event
but not all native window events are equal.
| | 01:28 | Some of these events dispatch very
specialized event objects.
| | 01:31 | For instance Window Resize dispatches an event
object named FlexNativeWindowBoundsEvent.
| | 01:37 | This event object has properties called the afterBounds
and beforeBounds which return rectangle objects
| | 01:44 | and you can determine from the rectangle that was
returned, the dimensions of the object and the size.
| | 01:50 | So let's take a look at listening for particular events.
| | 01:53 | I will go back to the WindowEvents.mxml application
and place the cursor inside the openWindow method,
| | 01:59 | opening up an empty line of code after the win variable
has been instantiated and before it has been opened.
| | 02:05 | I will call win.addEventListener and first
I'm going to listen for the event Event.CLOSE.
| | 02:13 | When this event is dispatched I will call
the method that is already been declared
| | 02:16 | in this application call winEventHandler.
| | 02:20 | I will do the same thing for the Closing event, I'm going to
copy that little bit of code that sets up the Event Listener
| | 02:28 | and then paste it right below and change the
second one from Event.CLOSE to Event.CLOSING.
| | 02:36 | Since both events dispatch the same kind of event
object, I can reuse the EventHandler function.
| | 02:42 | Then in the EventHandler function
I will add a bit of tracing code.
| | 02:45 | I will put in a trace function
call, a literal string as a label
| | 02:50 | and then the type of the event which is the event name.
| | 02:53 | Now I will run the application in Debug Mode, I
will click the button to open the native window,
| | 03:00 | now watch what happens in the Console
View below as I close the window.
| | 03:04 | First I get the Closing event and
then I get the Close event.
| | 03:09 | You will always get the events in that order
and that will be critical when you want to try
| | 03:12 | to prevent certain behaviors as I
will show you in the next video.
| | 03:16 | Let's take a look at another one of these events.
| | 03:20 | This time I'm going to listen for the event
window_resize, this is the event that occurs
| | 03:25 | when the user has just resized the window.
| | 03:28 | The event object for this event
is not a standard event class,
| | 03:32 | instead it is an instance of FlexNativeWindowBoundsEvent.
| | 03:35 | So once again I will listen for the event and
this time I call the method boundsEventHandler.
| | 03:42 | Then I will go down to the function
that has already been declared
| | 03:46 | in the application and once again I will do a trace.
| | 03:56 | I will save the changes and once again I
will do a trace to output the event type.
| | 04:00 | I will run the application in Debug Mode, open the Native
Window and this time watch what happens as I resize,
| | 04:09 | I'm going to move the cursor to the border of the window,
click down and then resize just a little bit and notice
| | 04:17 | that every time I resize even just a
pixel that event is dispatched again.
| | 04:22 | There are many other events you can listen for
and you can look at the documentation to find
| | 04:26 | out which events are dispatched and what data type
the event object will be when each event occurs.
| | Collapse this transcript |
| Preventing default window behaviors| 00:00 | In this video, I'm going to describe
how to prevent default behavior
| | 00:04 | when certain events of the native window class occur.
| | 00:08 | I use the application PreventDefault.mxml.
| | 00:11 | If you are following along in the exercises,
you can open this application in Flex Builder.
| | 00:17 | In this version of the application, we
are still listening for various events,
| | 00:22 | but notice that at line 16 the addEventListener is listening
for the closing event and dispatching the event object
| | 00:29 | to this specific eventHandler function,
closingHandler, this is an empty function.
| | 00:34 | For each event that ends with ing
such as resizing, closing and so on,
| | 00:41 | you can prevent the default behavior
whenever you want to by calling the method
| | 00:45 | of the event object called preventDefault.
| | 00:48 | Not all events can be prevented.
| | 00:50 | For instance, if it's an event that simply reporting
that something already happened like close or resize,
| | 00:56 | then it's going to be too late, the
event will have already occurred,
| | 00:59 | but for those events that are predicting
future behavior, the preventDefault method
| | 01:03 | in most cases prevent the behavior from occurring.
| | 01:07 | Before I fill in this method, I'm going to
add a visual control to the application.
| | 01:12 | I'll place the cursor after the buttons and add a CheckBox
control, the CheckBox control reflects a Boolean state,
| | 01:20 | its selected property returns either true or false
depending on whether the user has selected the control.
| | 01:26 | I'll set the CheckBox controls id as
okToClose and give it a label of OK to close?.
| | 01:35 | Now, I will go back to the closing handler method.
| | 01:39 | In order to decide what to do I'll take a look
at the selected property of the check box,
| | 01:44 | if not okToClose.selected, so I'll ask the
question, is it okay to close the native window
| | 01:55 | and I'll use the syntax, if not okToClose.selected.
| | 02:00 | So if user has checked the check box, I'll allow the
closing behavior to happen, but if it isn't selected,
| | 02:06 | I'll prevent the behavior like this, I'll
call the method event.preventDefault,
| | 02:12 | I'll save the changes and run the application.
| | 02:16 | I'll open the native window, move it to the side so
I can see the applications interface and now I'll try
| | 02:23 | to close the native window by clicking the
Close button in the upper right corner.
| | 02:27 | If you are working on the Mac click the
Close button in the appropriate location.
| | 02:31 | Notice that the window won't close, I'll go
back to the application and try to close it
| | 02:36 | from the button and again it won't close.
| | 02:40 | Now I'll check the checkbox and close the window by
clicking the button which executes some ActionScript
| | 02:47 | to close the window and the native window closes.
| | 02:50 | I'll open the window again and then once again uncheck the
checkbox, try to close the window from its own interface
| | 02:58 | and it won't work, come back to the application,
click the checkbox go back to the native window
| | 03:04 | and close it from here and now it closes correctly.
| | 03:07 | The ability to prevent this default
behavior is important because for example,
| | 03:12 | if the user closes the application window
before we've closed all the other windows
| | 03:17 | that can cause certain problems leaving
invisible windows in memory and so on.
| | 03:21 | By selectively listening for the closing event and other
events that you may want to prevent, you can handle them
| | 03:28 | and then checking your conditions, call
the event objects preventDefault method
| | 03:33 | to stop that future behavior from happening.
| | Collapse this transcript |
|
|
7. Using Native MenusCreating native menus| 00:00 | In this chapter of the video series I'm
going to describe the use of Native Menus.
| | 00:05 | A native menu is a menu component
that's hosted and presented
| | 00:08 | by the hosting operating system of the AIR application.
| | 00:11 | In contrast to pure Flex based menus which
are always presented inside the Flex window,
| | 00:17 | a native menu is presented either as part of the native menu
that wraps the Flex application or for example in Mac OS X
| | 00:25 | as part of the native operating system interface.
| | 00:27 | If you are following along with the exercises
| | 00:29 | in this chapter you can import the Flex
project that contains all of the starting code.
| | 00:34 | From the Flex Builder menu select File, Import, Flex
project, click the Browse button next to Archive File,
| | 00:43 | navigate to the Chapter07 folder under the Exercises area
and select Chapter07BeginProject.zip, open the project
| | 00:54 | and click Finish and that will
import the project into Flex Builder.
| | 00:59 | Then go to the Flex Navigator view, open
the project, open it's source folder
| | 01:04 | and then open the application file UsingNativeMenu.mxml.
| | 01:09 | This application has two empty
methods named init and selectHandler.
| | 01:13 | The init method is being called upon the
applicationComplete event of the application,
| | 01:18 | the selectHandler is an event handling
function that I'll use later in this exercise.
| | 01:23 | When you create a menu you always start off by
creating an instance of the NativeMenu class,
| | 01:28 | this class can be added either to
a Windows or to a Mac environment,
| | 01:32 | but you add it differently depending
on which operating system you are in.
| | 01:36 | In this video I'm going to show you how to use
the particular code for your operating system
| | 01:41 | but then in the next video I'll show
you how to dynamically determine
| | 01:45 | which operating system is currently
hosting the AIR application
| | 01:49 | and execute the correct code for the current user.
| | 01:52 | To get started, place the cursor inside the
empty init method and add an extra line of code.
| | 01:57 | The first step is to create a menu object, declare a local
variable named Menu, data typed as the NativeMenu class
| | 02:06 | and instantiate it using the NativeMenu
class's no arguments constructor method.
| | 02:12 | I'll expand my editor to see as much code as possible.
| | 02:16 | Now for each item you want to add to the menu,
create an instance of the NativeMenuItem class.
| | 02:22 | When you instantiate this object and
call the constructor method you can pass
| | 02:26 | in a string value which will be the menu item's label.
| | 02:29 | Create a new menu item like this, var
menuItem1, data typed as a NativeMenuItem.
| | 02:39 | Then instantiate it using =new, then call the constructor
method of the class NativeMenuItem and then pass in a label.
| | 02:49 | I'll put in a label of File.
| | 02:52 | Next you'll listen for the Select event, when the user
selects a particular menu item it dispatches a Select event
| | 02:59 | and you'll pass the event object to the predeclared
selectHandler method like this, MenuItem1.addEventListener,
| | 03:09 | listen for the event that's represented
by the constant Event.SELECT
| | 03:14 | and pass the event object to the selectHandler method.
| | 03:19 | Now add the menu item to the menu like this
menu.addItem and pass in the menu item.
| | 03:27 | Now you will create another menu item.
| | 03:33 | Declare another variable named menuItem2 once again
data typed as a NativeMenuItem object and constructed
| | 03:41 | from the class's constructor method and this time pass
in a label of Edit, the next two steps are the same
| | 03:50 | as for the first menu item, so I'll go up to the previous
two lines and select the code that adds the event listener
| | 03:57 | and adds the menu item to the menu, copy that to the
clipboard and then paste it at the end of the method,
| | 04:06 | then I'll go back and change menuItem1
to menuItem2 for both bits of code.
| | 04:12 | Now the next step is to actually
add the menu to your application.
| | 04:17 | The code for this will look a little bit different
depending on whether you are working on Windows or the Mac.
| | 04:22 | For Windows, you add the menu to the actual
native window that wraps the application.
| | 04:27 | The code looks like this, stage.nativeWindow.menu=menu.
| | 04:34 | Now if you are working on Mac and I'm not, so I'm just
going to comment this code out once I've typed it in,
| | 04:41 | for Mac OS X you use a bit of code that looks like
this, NativeApplication.nativeApplication.menu=menu.
| | 04:53 | When you code this code on the Mac it replaces
the standard File, Edit menu that displays
| | 04:59 | on all Mac native applications, it's also possible to
add menu choices to a Mac menu if you want and I'll talk
| | 05:06 | about that a little bit more in the next video.
| | 05:08 | Now again I'm running on Windows here, so I'm
going to comment that code out and I'm only going
| | 05:12 | to use the Windows version, stage.nativeWindow.menu=menu.
| | 05:17 | Now I will go down to the selectHandler method and
I will add a call to the trace method to detect
| | 05:23 | and report when the user selects a menu item.
| | 05:26 | I'll pass in a literal string Menu item
selected and then I will concatenate the label
| | 05:35 | of the selected menu item like this event.target.label.
| | 05:42 | Now I will run the application in Debug Mode.
| | 05:45 | When the application appears it displays my two menu
items at the top, now again if you are working on Mac OS X
| | 05:54 | and you used the Mac specific code that I showed you, then
you'll see the menu choices appear at the top of the screen.
| | 06:00 | Select either of the menu items and you
should see in the console in the background
| | 06:05 | that the trace method is outputting
the selected menu's label.
| | 06:08 | There is the File and there is the Edit menu item.
| | 06:12 | Now again in the next video, I'll show you how
to determine which kind of menu is supported
| | 06:17 | and then add it to the right place dynamically.
| | Collapse this transcript |
| Adding native menus to windows and applications| 00:00 | In this video, I'm going to describe
how to dynamically determine
| | 00:04 | which operating system the application is currently
running in and then how to use the appropriate code
| | 00:09 | to add a native menu to either the native
window or to the native application.
| | 00:14 | For this demonstration, I'll use
the application AddingMenu.mxml.
| | 00:19 | In this version of the application
the code that constructs the menu sets
| | 00:24 | up event listeners has been wrapped
into a function called createMenu.
| | 00:28 | This function returns a native menu
object and then in the init method,
| | 00:33 | the returned object from that function is
passed to the menu object of the native window.
| | 00:37 | Once again the application in its current state only
works correctly on Windows and if you are running it
| | 00:43 | on Mac you'd right now want to comment out the line
of code at line 11 and uncomment the code at line 13.
| | 00:50 | But in order to dynamically determine
where to place the menu,
| | 00:53 | we can use a property named supportsMenu that's implemented
| | 00:57 | on both the native window class
and the native application class.
| | 01:01 | In both cases, it's implemented as a static property
meaning that you call the property as a member
| | 01:06 | of the class definition rather
than an instance of the class.
| | 01:10 | To make sure that you are only trying to add a
menu to a native window where it's supported,
| | 01:15 | wrap the existing line of code in a
conditional block that looks like this.
| | 01:19 | if (NativeWindow.supportsMenu) then put in a pair of
braces and move the code that's currently adding the menu
| | 01:29 | to the native window into the braces
that follow the Boolean expression.
| | 01:33 | Now, you'll only be adding the menu where it works.
| | 01:36 | You can do something very similar for the Mac,
place the cursor after the comment for Mac
| | 01:42 | and add a conditional clause if
(NativeApplication.supportsMenu).
| | 01:49 | Once again, add a pair of braces after the if clause.
| | 01:53 | Now move the commented code into the if clause, remove
the comments and change the code so that instead of trying
| | 02:03 | to retrieve a menu object, we're simply
taking the value from the createMenu function
| | 02:08 | and passing that to the native applications menu.
| | 02:11 | Now, here is a very important note
about working on Mac OS X,
| | 02:15 | native applications in Mac OS X
already have a standard menu.
| | 02:20 | When you pass a native menu to the menu object in
this fashion, you are replacing the standard menu.
| | 02:27 | The standard menu has many choices
like File, Edit and so on.
| | 02:31 | If instead you want to add items to the standard
menu, using method of the menu object called Add Item
| | 02:38 | and then you'll be adding the menu to the existing menu.
| | 02:41 | This code however should work for this demonstration.
| | 02:44 | I'll save the changes and run the application and you'll
see on Windows once again that the menu appears correctly
| | 02:51 | and if you are working on Mac OS X, you should
see that the menu works there correctly as well.
| | Collapse this transcript |
| Using submenus and keyboard shortcuts| 00:00 | In this video, I'm going to describe how to add submenus
to native windows and also how to use keyboard shortcuts.
| | 00:07 | For this demonstration, I will use an
application named SubmenusAndShortcuts.mxml that's
| | 00:13 | in the Chapter07, Begin Project.
| | 00:16 | If you are following along with the exercises
open the application in Flex Builder.
| | 00:20 | In this version of the application, I'm once again creating
a menu and then adding it either to the native window
| | 00:27 | or the native application depending on the operating system.
| | 00:31 | In the createMenu method, I'm now adding submenus.
| | 00:35 | A submenu is a menu that appears when
the user clicks on a top level menu item.
| | 00:39 | For instance, if the user clicks on the FileMenu item,
I would like to display a submenu that includes item
| | 00:45 | such as Open, Close and other file related actions.
| | 00:49 | Currently, I'm getting the submenu
from a method named createFileMenu,
| | 00:54 | which is declared a little further down in the code.
| | 00:56 | To see this behavior, I have placed
the cursor after the line of code
| | 01:00 | that creates the menu inside the createFileMenu method.
| | 01:04 | Then I will add a couple of new items to the menu.
| | 01:07 | I will call menu.addItem and then I will
pass in a new NativeMenuItem and I will add
| | 01:16 | in a string of Open, as the MenuItem' label.
| | 01:19 | I will add another item, once again
adding the NativeMenuItem,
| | 01:25 | using its constructor method and
this time the label will be close.
| | 01:32 | I need to make sure that I have added the
right number of parenthesis at the end
| | 01:35 | of each line of code, that code should now work.
| | 01:39 | Now, as you add more items to the menu,
it becomes a little bit cumbersome
| | 01:44 | to call the addEventListener method for each menu item.
| | 01:47 | In fact, you can actually listen for an event at the
top level menu rather than on each individual menu item.
| | 01:54 | So that's what I will do.
| | 01:56 | I will go back to the createMenu method and I'm going to
take the addEventListener code that's currently listening
| | 02:01 | on a single item, I'm going to cut it to the clipboard
| | 02:06 | and then move it below the first
line of code that creates the menu.
| | 02:10 | I will paste it in and then I will change the member
| | 02:14 | on which the addEventListener method is
called from MenuItem1 to simply menu.
| | 02:19 | Then I will go locate the addEventListener
call for MenuItem2 and I will remove that.
| | 02:25 | I now have a single event listener for the entire menu and
it will work whether the user chooses a top level MenuItem
| | 02:32 | without a submenu or individual submenu items.
| | 02:35 | I will save the change and run
the application in Debug mode.
| | 02:40 | Now, watch what happens, when I click the top level
item that has a submenu and select one of its items,
| | 02:47 | I get feedback in the form of a trace output in the console.
| | 02:51 | I will do that again, for File, Close
and you should see the same reaction.
| | 02:56 | Now, when I click Edit at this point,
I'm not getting any feedback and that's
| | 03:00 | because the Edit menu item also has a submenu,
which is being created in the createMenu method
| | 03:06 | and it's shown here currently on line 37 of my code,
| | 03:10 | where I'm setting that top level object submenu using
the createEditMenu method, so let's go to that method.
| | 03:18 | This time, as I create an addItems to the menu,
I'm going to return a reference to that item,
| | 03:25 | so that I can modify its behavior a little bit.
| | 03:28 | Within the createEditMenu, I'm first going to create a new
variable named copyCmd, data typed as a NativeMenuItem.
| | 03:38 | Then I'm going to call menu.addItem and
as before, I will instantiate the object,
| | 03:46 | using the NativeMenuItem classes constructor method.
| | 03:52 | Now, that should be enough, but I would
also like to add a keyboard shortcut.
| | 03:57 | To add a keyboard shortcut to a MenuItem, set its key
equivalent property like this, copyCmd.keyEquivalent = --
| | 04:09 | and then the letter that I want to attach.
| | 04:11 | The automatic behavior will be then on Windows, the
user will be able to hold down the Ctrl key and press C
| | 04:17 | and on Mac, they will be able to hold down the Command key
and press C and that will have the same functional effect
| | 04:23 | as selecting the menu from the item with the mouse.
| | 04:25 | Now, I will do the same thing and
I will create a paste command.
| | 04:32 | Once again data typing it as an instance of
NativeMenuItem, I will add the item to the menu
| | 04:37 | and I will construct the NativeMenuItem
and pass in a label of Paste.
| | 04:48 | I will make sure I have added my closing parenthesis
in both lines of code and then for the Paste command,
| | 04:55 | I will once again add a keyboard
shortcut using the key equivalent property
| | 04:59 | and for this menu item I will choose
the letter P. I will save the changes
| | 05:06 | and run the application, once again in Debug mode.
| | 05:13 | When the application opens up, I will open the Edit menu
and select Copy and I should see the MenuItem is selected
| | 05:21 | and then I will select to paste and I should
once again see that the MenuItem is selected.
| | 05:26 | Now, I will press the appropriate keyboard shortcuts.
| | 05:29 | Here's Ctrl+P and here's Ctrl+C and
you will see the trace output appear
| | 05:35 | in the console and Flex Builder in the background.
| | 05:38 | This should be working in the same way on
the Mac OS X, instead of pressing Ctrl+C
| | 05:42 | or Ctrl+P, you will press Command+C or Command+P.
| | 05:46 | So that's a look at adding submenus and
using keyboard shortcuts on NativeMenuItems.
| | Collapse this transcript |
| Using the FlexNativeMenu control| 00:00 | In this video, I'm going to describe how
to use a component named FlexNativeMenu.
| | 00:05 | This is a Flex component that's wrapper for the standard
native menu object, that makes it a lot easier to declare
| | 00:11 | and use a native menu at the application level.
| | 00:14 | For this demonstration, I will use an application named
UsingFlexNativeMenu.mxml, if you are following along
| | 00:20 | in the exercises, you can open this application
file from the Chapter07 Begin Project.
| | 00:27 | Open the application and take a look at the source code.
| | 00:29 | There's an XML packet that has a root
element and then two menuitem elements.
| | 00:34 | The menuitem elements represent
NativeMenuItems, each with a label.
| | 00:38 | Within those, there are menuitem
elements as well, this is just XML.
| | 00:43 | But notice that the format attribute is set to e4x,
this is going to allow us to address each of the items
| | 00:49 | within the XML content using e4x expressions.
| | 00:54 | Now, to take this XML structure
and pass it into a NativeMenu,
| | 00:59 | place the cursor after the windowed
application tag and add a pair of mx menu tags.
| | 01:05 | This will be the menu property of
the windowed application component.
| | 01:09 | There's a bit a magic that will happen here.
| | 01:11 | You may remember if you watched the earlier videos that
when you construct a NativeMenu using ActionScript code,
| | 01:17 | you have to determine dynamically whether you
are going to add the menu to the NativeWindow
| | 01:22 | or to the NativeApplication, that is whether
you are running on Windows or the Mac.
| | 01:27 | When you use this architecture,
you don't have to worry about that
| | 01:30 | because the windowed application
component takes care of it for you.
| | 01:34 | Now, within the menu property declaration,
declared instance of the FlexNativeMenu component,
| | 01:40 | set its DataProvider using a binding
expression to the XML object, myMenuData.
| | 01:46 | You don't want to show the root element of the XML.
| | 01:49 | So set a property named showRoot to a value of false.
| | 01:53 | Also, you have to tell the FlexNativeMenu
object, what element or attribute
| | 01:58 | of the XML structure to use as its label.
| | 02:01 | Set the labelField to the value of @Label.
| | 02:05 | This is an e4x expression that says
each element has a label attribute,
| | 02:10 | from which we will get the label
value, that should do the trick.
| | 02:14 | Go ahead and close the tag and run the application.
| | 02:17 | Now, if you are running on Windows as I am, you should
see that the menu appears as a part of the NativeWindow
| | 02:22 | and if you are running on the Mac, you
should see the same menu appear at the top
| | 02:27 | of the Mac interface as the Application menu.
| | 02:29 | Now, close the application and I will show you
how to handle the events that are dispatched
| | 02:34 | when the user selects various items from the menu.
| | 02:37 | When the user selects an item from the
menu, you get an event named itemClick.
| | 02:41 | Add an itemClick event listener attribute and put in some
ActionScript code to call a new method that we'll create
| | 02:47 | in a moment named itemClickHandler
and pass the event object.
| | 02:54 | Now, go down to the Script section and create
that function, make it a private function.
| | 03:00 | Once again its name is itemClickHandler and this
time the name of the event class that will be used
| | 03:07 | as the event object is FlexNativeMenuEvent typecast the
event argument as FlexNativeMenuEvent and return void
| | 03:16 | from the method and now place a breakpoint
on the last line of the function,
| | 03:22 | that is the function with the closing brace.
| | 03:25 | Save your changes and run the application in Debug mode.
| | 03:31 | Go to the menu and select any item,
I will select the Copy item.
| | 03:35 | In the background, Flex Builder may ask you to go
into the debugging perspective, if so click Yes.
| | 03:41 | If it doesn't prompt you to go into the debugging
perspective, but you are still on a breakpoint,
| | 03:46 | just go to the debugging perspective manually.
| | 03:48 | Now, double-click the Variables tab to expand
it to full screen and examine the event object.
| | 03:54 | Notice that the event object is typed as FlexNativeMenuEvent
and it has properties named index, item and label.
| | 04:03 | The label property is the label
that was applied to the item.
| | 04:07 | The item is the XML note that generated this menu item
and the Index is the ordinal position of this menu item
| | 04:14 | within its submenu, in this case it's the first item.
| | 04:17 | So index is set to a value of zero.
| | 04:20 | Double-click the Variables tab again to restore to
regular size and then terminate your debugging session.
| | 04:26 | Go back to the Flex Development perspective and
place the cursor inside the itemClickHandler method
| | 04:33 | and put in your trace command this time and
report the event objects label property like this.
| | 04:39 | Item clicked: -- put in a literal string of Item
clicked then concatenate to that event.Label.
| | 04:49 | Save your changes, remove the breakpoint.
| | 04:52 | Once again, run the application in
Debug mode and then as you interact
| | 04:57 | with the menu, watch the console in Flex Builder.
| | 05:00 | I will select an item and I should see a trace message
in the console reporting which menu item was selected.
| | 05:10 | So that's how we use the FlexNativeMenu component to
generate a native menu that's part of the application.
| | 05:16 | ?Its advantage over the standard native menu
class is that you can declare it in MXML,
| | 05:21 | whereas the standard menu object can
only be declared in ActionScript.
| | 05:25 | Also you can dynamically populate the NativeMenu object
from XML formatted data that you can either hard code
| | 05:31 | in your application or retrieve it run time perhaps
using http service or some other data retrieval method.
| | Collapse this transcript |
| Using context menus| 00:00 | In this video, I'm going to describe how to use
the FlexNativeMenu object to create a context menu.
| | 00:06 | That is a menu that appears when the user
places the mouse cursor over an object
| | 00:11 | and either right-clicks or on the Mac Ctrl+clicks.
| | 00:14 | For this demonstration, I will use an application
named UsingContextMenu.mxml, if you are following along
| | 00:21 | with the exercises, you will find this
application in the Chapter07, Begin Project.
| | 00:26 | In this application, there is a simple label
control at the bottom, it's positioned in the center
| | 00:32 | of the screen and has a simple text value.
| | 00:35 | There is also an XML structure with two menu
item elements, one with the label of Upper Case
| | 00:40 | and the other with the label of Lower Case.
| | 00:43 | You can declare a FlexNativeMenu object either in
MXML as I did in the previous video or in ActionScript
| | 00:50 | because I already showed you the MXML
version, this time I will use ActionScript
| | 00:54 | and then you can choose whichever approach you like.
| | 00:57 | In this application, there's already a variable
named myMenu which is data typed as FlexNativeMenu.
| | 01:03 | Place the cursor in the init method and initialize
myMenu using the FlexNativeMenu constructor method.
| | 01:14 | Next, set its dataProvider.
| | 01:17 | I'm setting all of the same properties
as I did in the previous video.
| | 01:20 | This time just using ActionScript instead of MXML.
| | 01:23 | I will set myMenu.dataProvider to the menuData XML object
| | 01:29 | and as before I will set the menus,
showRootProperty to false.
| | 01:33 | This will prevent a menu item from
appearing for the root element.
| | 01:40 | Now, I will set its labelField, the labelField
properties is string, so it gets wrapped in quotes.
| | 01:47 | But I'm still using an e4x expression of @Label, this
means that the label attribute of each element is used
| | 01:55 | as the label for the menu item and
then I will add an event listener.
| | 02:00 | When the user select an item from this
menu, I will get an event named itemClick,
| | 02:06 | the itemClick event generates an event
object typed as FlexNativeMenuEvent.
| | 02:11 | So I will listen for that event using the itemClick
constant and then I will pass the event object
| | 02:17 | to the predeclared itemClickHandler method.
| | 02:21 | Finally, I will associate this menu object
with the label control as its context menu.
| | 02:27 | To do that I will call a method of the
menu control called SetContextMenu.
| | 02:33 | I will pass in the visual control
that I want to associate it with.
| | 02:37 | In this case it's the label with an
id of LBO, that's already declared
| | 02:41 | at the bottom of the application, that's it.
| | 02:44 | This function is already being called upon the
creation complete event of the application.
| | 02:49 | So as the application starts up, I create the
menu, I set its data provider, set the show root
| | 02:55 | and labelFfield properties to determine the structure
and presentation of the menu at the event listener
| | 03:01 | and then associate it with the visual
control using the setContextMenu method.
| | 03:06 | Now, I will go to the itemClickHandler method and
add some code to determine what I'm going to do.
| | 03:12 | I will put in a conditional clause and
I will inspect the value of event.Label.
| | 03:17 | As I showed in the previous video, this
property is the label of the selected menu item.
| | 03:22 | I will compare event.Label to a value of Upper Case.
| | 03:27 | If the label property of the event object is Upper
Case, I will transform the label's text property
| | 03:35 | to an Upper Case value, using LBO.text=LBO.text.toUpperCase.
| | 03:45 | Then I will put in an else clause, I will copy and paste
that code into the else clause and I will change it so that
| | 03:54 | if the user selects Lower Case, the only other
menu item I will transform the text to Lower Case.
| | 04:00 | I will save the changes and run the application.
| | 04:03 | When the application opens, it displays the menu in the
center of the screen, I will right-click on the label
| | 04:09 | and select Upper Case and you will
see its text is transformed.
| | 04:13 | I will right-click again and select Lower Case
and you will see that the text is transformed.
| | 04:17 | Again, this should work exactly the same on a Mac.
| | 04:21 | The only difference will be that if you are
working with a Mac without a right mouse button,
| | 04:25 | you should hold down the Ctrl key and click instead
and you should still see the exact same context menu.
| | Collapse this transcript |
| Displaying menus in the system tray or Dock| 00:00 | In this video, I'm going to describe how to
apply a native menu to the system tray icon
| | 00:06 | when you are running an AIR application in Windows
or to the Dock when you are running in Mac OS X.
| | 00:11 | For this demonstration, I will use an application named
SystemtrayAnddock.mxml in the Chapter07BeginProject.
| | 00:19 | If you are following along with the exercises,
open the application in Flex Builder now.
| | 00:23 | This is another version of the previous application
that applies a native menu as a context menu.
| | 00:30 | In the init method, an object named myMenu
is created, datatyped is FlexNativeMenu
| | 00:36 | and then the menus set context menu method is called
to associate the menu with a particular visual control.
| | 00:43 | In this application, we are going to take that same
menu and apply it instead to the system tray icon
| | 00:48 | in Windows or to the Dock icon on the Mac.
| | 00:51 | To get started this version of the application
already implements a system tray icon.
| | 00:56 | Notice that lines 11 and 12 of the application there is an
Embed metadata tag and associated variable named icon16.
| | 01:04 | This results in embedding a 16 square pixel graphic in the
application and associating it with the variable icon16.
| | 01:12 | Then in the beginning of the init method,
there is a bit of code that checks
| | 01:16 | to see whether the current application
supports the system tray icon.
| | 01:20 | Switching over to Mac OS X, if you are running the
same application on MAC OS X you'll be able to see
| | 01:26 | that the application context menu appears
when the user right-clicks or clicks
| | 01:31 | and holds down their mouse button while the mouse is
over the system Dock icon representing the application.
| | 01:36 | The code that executes this functionality is down
towards of the middle of the application where it says
| | 01:42 | if NativeApplication.supportsDockIcon
then dockIconMenu = myMenu.
| | 01:49 | I will run the application and we'll see the behavior.
| | 01:51 | As the application opens up, the Mac operating
system automatically displays an icon on the Dock
| | 01:58 | when you run this application from within Flex Builder
you are actually running the AIR Debug Launcher
| | 02:04 | in the background.
| | 02:05 | And so the icon you see and any legend such as
the one I'm showing right now will indicate ADL.
| | 02:11 | When you run the same application after packaging
and installing it using the AIR installer,
| | 02:16 | you'll see the applications icons instead.
| | 02:19 | Either way, the user can move their mouse cursor
over the icon in the Dock and then either right-click
| | 02:25 | or hold down their mouse button for a few
seconds until the context menu appears,
| | 02:29 | because I have a two button mouse I'll
right-click and I'll see the customized menu
| | 02:35 | and once again they are my custom functions to take the
label in the middle of the application and change it
| | 02:40 | to uppercase or to change it to lowercase.
| | 02:44 | So you'll see that this same menu object can be used in
many different ways, as a context menu for any visual object
| | 02:51 | or as a system tray menu if you are running on Windows
or as a Dock menu if you are running on Mac OS X.
| | Collapse this transcript |
|
|
8. Monitoring Network ConnectionsUnderstanding network monitoring| 00:00 | In this chapter of the video series, I'm going to describe
the use of network monitoring tools that allow you to detect
| | 00:06 | at runtime whether an AIR application
has accessed to network resources.
| | 00:11 | AIR applications are frequently designed to be
occasionally connected, meaning that when they have accessed
| | 00:16 | to the network they can get their data
and the files from an application server
| | 00:20 | and when they are not connected they can get their
data and resources from the local file system.
| | 00:25 | An application that's connected to the internet frequently
gets its data through a middle way or application server
| | 00:31 | that in turn tucks to a network hosted database.
| | 00:34 | Other network resources that an AIR application
might use, might include xml files or other content
| | 00:40 | but when that same application is hosted on a computer
that's currently disconnected from the network
| | 00:45 | but for certain applications it can make sense to have
the applications still be useful even when disconnected.
| | 00:52 | For example, an AIR base client application might
use the local file system and the local database.
| | 00:58 | The network monitoring tools allow you to determine
proactively whether the network resources are available
| | 01:03 | at any given time and then you can make an intelligent
decision as to which resources you will address.
| | 01:10 | The network monitoring classes are implemented
through a class called ServiceMonitor.
| | 01:15 | This is a superclass that implements the entire network
monitoring framework and then there are two subclasses
| | 01:20 | which is the ones that you actually
instantiate in your AIR application.
| | 01:26 | The subclasses include the URLMonitor class that
allows you to monitor endpoints or network resources
| | 01:32 | that can be reached through HTTP and HTTPS communications
| | 01:37 | and another component named SocketMonitor that's
designed to be able to monitor other endpoints.
| | 01:42 | For example, you might want to monitor whether
an RTMP endpoint, that's used for messaging
| | 01:47 | and the data management service might be available.
| | 01:51 | Here are the steps you follow for setting up monitoring.
| | 01:54 | First, you create a monitor object.
| | 01:56 | The object should be typed as either
URLMonitor or SocketMonitor.
| | 02:00 | You typically don't use the ServiceMonitor class directly.
| | 02:04 | You tell the monitor object as you set it up,
what is the endpoint, that is what is the URL
| | 02:09 | of the resource that you want to monitor.
| | 02:12 | Then optionally set a pollInterval property to a
set of milliseconds to indicate how often you want
| | 02:18 | to monitoring object to ping the
server and determine its availability.
| | 02:22 | By default the pollInterval property is set to
zero and in this case the status check only happens
| | 02:28 | when the network availability changes as
determined by and reported by the operating system.
| | 02:33 | Alternatively, you can set pollInterval to
a positive number in terms of milliseconds.
| | 02:38 | For example, 2000 would mean that the
pollInterval is every two seconds.
| | 02:43 | Then the component that you are using for monitoring
either URLMonitor or SocketMonitor will communicate
| | 02:49 | with the server once each time that period elapses.
| | 02:52 | Once you have set it all up you start the monitor object.
| | 02:55 | Then each time the network status changes,
you will get an event named status.
| | 03:01 | So those are the steps and in the following
two videos I will show you exactly how
| | 03:05 | to implement this using both components
URLMonitor and SocketMonitor.
| | Collapse this transcript |
| Using the URLMonitor| 00:00 | In this video, I'm going to describe
the use of the URLMonitor class.
| | 00:04 | This class allows you to monitor the availability of the
resource that you communicate with over HTTP or HTTPS.
| | 00:12 | For the demonstrations in this chapter, I will be using
a Flex Project that's available in the exercises area.
| | 00:17 | If you are following along with the
exercises you can import the project.
| | 00:22 | Go to the Flex Builder Menu and
select File, Import, Flex Project.
| | 00:28 | Click the Browse button next to Archive
file, navigate to the Chapter08 folder
| | 00:32 | in the Exercises area and select Chapter08BeginProject.zip.
| | 00:39 | Then, when you come back to Import
Flex Project, click Finish.
| | 00:43 | Go to the Flex Navigator view and open
the project and open its source folder
| | 00:48 | and then open the application UsingURLMonitor.mxml.
| | 00:55 | This application has two embedded graphics named
availableIndicator and notAvailableIndicator.
| | 01:01 | These graphics will be used to display the
availability of network resources at runtime.
| | 01:06 | At the bottom of the application, there is
an image component, the source property,
| | 01:10 | is bound to the notAvailable image icon and
a label control with an id of statusLabel.
| | 01:15 | When you start up the application initially it
simply displays the notAvailable indicator graphic
| | 01:21 | and a message Checking URL status.
| | 01:24 | Close the application and return to the code and
then place your cursor above the init method.
| | 01:29 | The first step in network monitoring is
to create an instance of a monitor object.
| | 01:34 | In this case, I will use the URLMonitor class.
| | 01:37 | Declare a private variable name it
monitor and data type it as URLMonitor.
| | 01:44 | Now move the cursor into the init method.
| | 01:46 | Now I will instantiate the variable using
the URLMonitor class's Constructor method.
| | 01:52 | This constructor method requires an
instance of the URLRequest object.
| | 01:57 | So I will add new URLRequest and then I will passing
| | 02:02 | to that constructor method the actual
location of the resource I want to monitor.
| | 02:07 | In this case, I'm going to use http://localhost that
is a service that's available on my local system.
| | 02:15 | Next, I will start the monitor.
| | 02:17 | Now as the monitor starts up it's going to
send out an initial request to this location.
| | 02:24 | When the response comes back it will
determine whether it got back a valid response
| | 02:29 | and at that point it's going to
dispatch an event, named status.
| | 02:33 | So now before I start the monitor,
I will add an event listener.
| | 02:36 | I will make a little bit of space before they call to the
start method and add this code monitor.addEventListener
| | 02:43 | and I will select the constant
StatusEvent.STATUS to represent the status event.
| | 02:50 | Then I will react by calling an event listener function
that I will need to create, named statusHandler.
| | 02:56 | Now create that function.
| | 02:59 | Place the cursor after the init method and create
another new function, name this one statusHandler.
| | 03:07 | As with all event handler functions
this will receive an event argument
| | 03:12 | and this one will be data typed as StatusEvent.
| | 03:16 | The function returns void and initially all we are going
| | 03:20 | to do is trace the current availability
of the network resource like this.
| | 03:31 | I will put in a little string of Available then
I will concatenate it to event.target.available.
| | 03:39 | The available property is a member of the
URLMonitor class and it's a boolean value
| | 03:44 | that indicates whether the monitored
resource is currently available.
| | 03:47 | I will save my changes and run the application.
| | 03:51 | Now notice initially that I haven't started up
my web server even in fact you have WAMP or MAMP
| | 03:57 | or any other web server currently running on the standard
port 80 on your local machine, turn it off before this test.
| | 04:03 | Now I will run the application in Debug mode.
| | 04:07 | As the application starts up it sends out an initial ping
and notice in the Console view at the bottom of Flex Builder
| | 04:13 | that I get back a message Available: false.
| | 04:17 | Now I'm going to close the application
and I'm going to start up my web server.
| | 04:21 | If you are working on Windows and you followed
the earlier instructions in this video series,
| | 04:25 | you have installed a product named WAMP and if you
are working on Mac you might have installed MAMP.
| | 04:31 | Go ahead and start up that server now.
| | 04:33 | On Windows Vista, I will go into the Start Menu and
type wamp and locate the menu choice start WampServer.
| | 04:40 | I will wait for few moments until the server
started and I will be able to tell on windows
| | 04:46 | that the server is completely started by looking at
the system tray icon in the lower right-hand corner.
| | 04:51 | I should see that the indicator needle is all
the way to the right and if I move the cursor
| | 04:56 | over the icon I get a tool tip server online.
| | 04:59 | Now I will run the application
again, once again in Debug mode.
| | 05:04 | I will wait a moment and this time I
get back a message Available: true.
| | 05:09 | Now I'm going to add some logic
to the statusHandler function
| | 05:13 | to manipulate the visual interface of the application.
| | 05:16 | I have closed down the application and now I will go to the
statusHandler method and I will add a conditional clause
| | 05:23 | if (event.target.available) and now I'm
going to make two changes to the interface.
| | 05:31 | First I will set the imgIndicator.source
| | 05:34 | to the bound availableImg object that's the embedded graphic
represent availability and I will change statusLabel.text
| | 05:44 | to Network available and in the else clause I will set
imgIndicator.source to notAvailableImg and once again,
| | 05:57 | modify the statusLabel's text property and I
will put in the string Network not available.
| | 06:06 | I will save the changes and run the application,
noting this time that the WampServer is running.
| | 06:13 | Notice as the application starts up initially it says it's
Checking the URL and then it reports Network available.
| | 06:19 | I will close the application.
| | 06:22 | Now I will go down to the WAMPSERVER
and turn off the services.
| | 06:25 | You can do the same thing at the MAMP
server if that's what you are using.
| | 06:28 | For WAMP, I will click on the icon in the system tray
and select Stop All Services, then I will wait a moment
| | 06:35 | for the service to shutdown then I will run
the application again and after a few seconds,
| | 06:40 | you will see the message Network not available.
| | 06:42 | Now in the next video, I will show
you how to set the polling interval
| | 06:46 | so that you can control how often you
are rechecking network availability.
| | Collapse this transcript |
| Setting the pollInterval property| 00:00 | In this video, I'm going to describe
the use of the pollInterval property.
| | 00:04 | This numeric property allows you to
determine how often a monitoring object checks
| | 00:09 | for the availability of a network resource.
| | 00:12 | By default, the pollInterval property
is set to a value of zero
| | 00:16 | and in this case a monitoring object
will check availability upon starting
| | 00:20 | and then only will be retriggered whenever the
operating system informs the monitoring object
| | 00:25 | of a change in network availability.
| | 00:27 | For this demonstration, I will use an
application named UsingpollInterval.mxml.
| | 00:34 | This is the same application as
was built in the previous video.
| | 00:37 | It creates a URLMonitor object.
| | 00:40 | It starts the monitor object and then listens for the status
event which occurs whenever network availability changes.
| | 00:48 | Now because I'm working with an application server on my
local system, it will always be available or unavailable,
| | 00:54 | but its availability won't be effected
by general network availability.
| | 00:58 | So the default behavior of the monitor object that is
| | 01:00 | to check its availability whenever the operating
system network capability is turned on and off,
| | 01:06 | won't be useful for this example, instead
I will set the pollInterval property.
| | 01:10 | So I will go to the init method and I will
add this code monitor.pollInterval = 2000.
| | 01:19 | The pollInterval property is measured in milliseconds.
| | 01:22 | So this means I want to monitor to
recheck availability every two seconds.
| | 01:26 | I will save my changes and run the application and
on my system I first made sure that I'm running WAMP,
| | 01:33 | my application server with the integrated web server.
| | 01:36 | As the application starts up, it initially
reports that the network is available.
| | 01:41 | Now I will go down to the system tray and if
you are running on Mac you want instead to go
| | 01:46 | over to the MAMP application or
you can follow a similar operation.
| | 01:50 | I will click the System Tray icon
and select Stop All Services.
| | 01:54 | It takes a few moments for the service to shutdown but you
will see that the application reacts almost immediately.
| | 02:00 | Now I will go back to the WAMP System Tray icon, once
again click it and this time select Start All Services
| | 02:07 | and once again the application reports
that the network is now available.
| | 02:11 | So the advantage of the pollInterval property when you
set it to a very tight time frame such as two seconds is
| | 02:17 | that you will be notified of changes in
network availability almost immediately.
| | 02:22 | The disadvantage of this approach is that you are
using up network in application server resources
| | 02:27 | because every two seconds you repinging the server
and if you have hundreds or thousands of clients
| | 02:33 | out there, you might overload your server.
| | 02:35 | So if you use the pollInterval property just be aware
that it is creating network in application server traffic
| | 02:42 | and you should balance the use or overuse of those network
resources against the need for the local client application
| | 02:48 | to know when network availability
has changed as quickly as possible.
| | Collapse this transcript |
| Using the SocketMonitor| 00:00 | In this video, I'm going to describe
the use of the SocketMonitor component,
| | 00:04 | that allows you to monitored network resources other
than those that you communicate with over HTTP or HTTPS.
| | 00:12 | For this demonstration, I will use the
application UsingSocketMonitor.mxml.
| | 00:17 | If you are following along with the exercises
you can open this file in Flex Builder.
| | 00:22 | This is the same application that I
was working on in the previous videos.
| | 00:27 | It currently uses the URLMonitor class.
| | 00:29 | To check for a resource at localhost under http it
gives an event listener to listen for the statusEvent
| | 00:36 | and when that event occurs, it
reports current network capability.
| | 00:40 | Because I have set the pollInterval property
at two seconds, it rechecks every two seconds.
| | 00:46 | Now for this demonstration, instead
of checking for the availability
| | 00:49 | of the Apache web server, that's
living at port 80 on local host.
| | 00:53 | This time I'm going to check for the availability of MySQL,
which operates on and listens at port 3306 by default.
| | 01:02 | The URLMonitor class won't be able to do this.
| | 01:04 | It only communicates over HTTP.
| | 01:06 | So I'm going to make a few changes.
| | 01:08 | First I will go to the import statement at the top
of the scripting section and I will change the import
| | 01:13 | from air.net.URLMonitor to air.net.SocketMonitor.
| | 01:19 | Then I will go to line 19 and change the data type of
the monitor variable from URLMonitor to SocketMonitor
| | 01:27 | and then I will go down to the
instantiation of the object at line 23
| | 01:32 | and change the constructor method in the same way.
| | 01:34 | Now the SocketMonitor constructor
method takes two arguments instead
| | 01:40 | of the single argument I passed
into the URLMonitor constructor.
| | 01:44 | The first argument is a string which
is the host I want to communicate with.
| | 01:48 | You no longer use URLRequest in this case.
| | 01:51 | So I'm going to change this first argument.
| | 01:54 | I will take the parenthesis, I won't be instantiating
URLRequest and I also won't prefix localhost with http.
| | 02:03 | I'm now only indicating where is the
server I want to communicate with.
| | 02:07 | Then I will move over to after the declaration of the host
and I will add the port number which is 3306 and again,
| | 02:15 | this is the port number that MySQL listens on by default.
| | 02:19 | The rest of the code is exactly the same.
| | 02:21 | You are listening for a StatusEvent,
you are still starting the monitor
| | 02:26 | and in this example I'm still polling every two seconds.
| | 02:30 | Now I have started up WAMP already.
| | 02:32 | My server is running including both Apache and MySQL so I
can now run the application and as the application starts
| | 02:39 | up the SocketMonitor component makes an initial
check and finds that MySQL is available.
| | 02:46 | Now I will turn off the MySQL service.
| | 02:48 | If you are working on Windows with WAMP, you can get to
the service administration tools to the system tray icon.
| | 02:54 | If you are working on the Mac with
MAMP, go to the MAMP application
| | 02:58 | and click on the MySQL tab and
turn off the service from there.
| | 03:03 | In MAMP, we turn it off like this.
| | 03:05 | I will go to MySQL, Service, Stop Service.
| | 03:11 | It should take less than two seconds for the application
to determine that MySQL is no longer available.
| | 03:17 | Now I will turn MySQL back on.
| | 03:19 | I will go back to the system tray icon, I will select
MySQL, Service, Start/Resume Service and once again
| | 03:29 | within two seconds the application reports availability.
| | 03:33 | Now again, if you are working on the Mac and
you are using the MAMP integrated server bundle,
| | 03:37 | you will go to the MAMP application
and shutdown MySQL from there.
| | 03:41 | Either way the application should correctly
determine that MySQL is either turned on or turned off
| | 03:47 | and it can then make an intelligent
decision as to whether it should communicate
| | 03:51 | with the network or with the local database.
| | Collapse this transcript |
|
|
9. Using the Local DatabaseUnderstanding the integrated SQLite database| 00:00 | In this chapter of the video series,
I'm going to describe how
| | 00:03 | to integrate the local database that's
a part of AIR into your applications.
| | 00:08 | The Adobe Integrated Runtime includes an embedded
database engine based on the SQLite open source database.
| | 00:15 | When you create a new database you stored on the
local system as a file with the .db file extension.
| | 00:21 | You will use classes that are a part of
the AIR libraries to create the database
| | 00:26 | and communicate with it with SQL statements.
| | 00:29 | The location of each database file
and its name is up to you.
| | 00:33 | The only requirement is that the
database files must be placed in a folder
| | 00:36 | to which your AIR application can
read and write the content.
| | 00:40 | For example, you might placed the file
in the Application Storage folder.
| | 00:44 | That's the folder that's unique to each application and
to each user on the local system or you might place it
| | 00:50 | in a specific location under the user's home directory,
| | 00:53 | represented in AIR by the userDirectory
property of the File class.
| | 00:57 | Here are the basic steps for using a local database.
| | 01:01 | First you designate the location and name of the
database file by representing it in a file object.
| | 01:07 | Then you connect to the database
with a class called SQLConnection.
| | 01:11 | You will take the file class and pass
it to the SQLConnection's Open method.
| | 01:15 | Then you will create a statement
represented by an SQL Statement object
| | 01:19 | and connect the SQLStatement to the connection.
| | 01:22 | Finally, you will execute the statements.
| | 01:25 | All database operations can be either synchronous or
asynchronous in much the same way as file system activities.
| | 01:32 | The implications of synchronous versus asynchronous
operations are the same as with file system activities.
| | 01:39 | If you execute a long-running operation synchronously,
it results in suspending the main application thread
| | 01:45 | and any animations or user interactions are
prevented for the duration of the database operation.
| | 01:51 | If you instead use asynchronous operations, the
application thread can continue to operate independently
| | 01:57 | or the database operation runs in the background.
| | 02:00 | When you work with the SQL connection
and SQL Statement classes,
| | 02:04 | you communicate with the database
using SQL, Structured Query Language.
| | 02:08 | The implementation of the SQL language and SQLite is not
as extensive or deep as it is in say Oracle or SQL Server,
| | 02:17 | but you will find that all of the standard SQL
Statements that you might expect are supported.
| | 02:22 | For example, basic statements such as Select,
Insert, Update and Delete allow you to add,
| | 02:28 | maintain and retrieve data from your database at runtime.
| | 02:31 | You will also have a very strong implementation of data
definition language statements including the ability to add
| | 02:38 | and drop Tables, Indexes, Views and Triggers.
| | 02:42 | There are certain things that are not available in SQLite.
| | 02:45 | For instance, Foreign Key Constraints, another more
advanced database functionality is not available.
| | 02:50 | To find out more about what you can and can't
do in SQLite, check the Flex 3 documentation,
| | 02:56 | specifically section labeled local database SQL support.
| | 03:00 | In the remaining videos of this chapter, I will show you
how to create a database, add data, maintain the data,
| | 03:07 | retrieve the data and how to maintain
transactions and at the end of this chapter,
| | 03:12 | I will talk about how to create an occasionally
connected application that gets its data primarily
| | 03:17 | from a network based database and then when the network
isn't available instead can move to using the local database
| | 03:24 | and then when it's connected again, can synchronize
and move that data back into the network.
| | Collapse this transcript |
| Creating and connecting to a database | 00:00 | In this video, I'm going to describe how to
create a new database using a combination
| | 00:05 | of the File class and the SQLConnection class.
| | 00:08 | For all the demonstrations in this chapter, I will be
using a Flex Project that's part of the Exercises area.
| | 00:14 | If you are following along in the
exercises you can import the project now.
| | 00:18 | From the Flex Builder Menu, select
File, Import, Flex Project.
| | 00:24 | Click the Browse button next to Archive file, navigate
to the Chapter09 folder under the Exercises area
| | 00:31 | and select the file Chapter09BeginProject.zip.
| | 00:35 | As with all chapters there is also a project that contains
the ending code for all demonstrations in the chapter.
| | 00:41 | After you have finished importing the
project, go to the Flex Navigator view,
| | 00:46 | open the project and open the project's source folder.
| | 00:49 | Then open an application named CreateDatabase.mxml.
| | 00:54 | This beginning application has an
empty function named createNewDatabase
| | 00:58 | and a button whose click event handler calls the function.
| | 01:02 | In order to create a new database, you will first
instantiate a file object and point the file objects path
| | 01:08 | to the location of the database file you want to create.
| | 01:11 | Then you instantiate an SQLConnection
object and call its Open method.
| | 01:15 | There are two versions of the open method, one for
synchronous operations and the other asynchronous.
| | 01:20 | For this demonstration, I will use synchronous operations
| | 01:23 | and then I will show you the asynchronous
version in a later video.
| | 01:27 | Place the cursor above the createNewDatabase
function and make some space.
| | 01:31 | You typically declare the SQL Connection
object outside of any functions
| | 01:36 | so that you can then address the object
from any function in the application.
| | 01:40 | I will declare the variable like this, private
var sqlConn, data typed as SQLConnection.
| | 01:47 | I will also declare a variable named
SQLFile, data typed as a File class.
| | 01:54 | This is the same file class that you used in file management
operations that I demonstrated in an earlier video.
| | 02:02 | Now move the cursor to the createNewDatabase function.
| | 02:05 | You can place the database anywhere on disk as long it sits
in a folder to which your application has read/write access.
| | 02:12 | The most common place to create a local database
is somewhere within the user's home directory.
| | 02:17 | For instance, you could use the userDirectory property
of the File class and then use its resolvePath property
| | 02:23 | to designate the name and location of the database
under there or if you want to bury the database
| | 02:28 | in the application storage area, you
could place it in the app storage folder.
| | 02:33 | For this demonstration, I'm going to
place the database on the user's desktop,
| | 02:37 | so that we can easily see when
the database has been created.
| | 02:40 | Within the createNewDatabase function, set the reference
of SQLFile as follows, File.desktopDirectory.resolvePath
| | 02:51 | and then passing the name of the
database you want to create.
| | 02:54 | I'm going to call it Contacts.db.
| | 02:58 | Next, instantiate the connection,
sqlConn = new SQLConnection.
| | 03:06 | The SQLConnection class's Constructor
method doesn't receive any arguments.
| | 03:10 | Now you will open the connection using the file objects
as follows, sqlConn.open and then pass in sqlFile
| | 03:19 | as the reference, that is the location
of the file that you are connecting to.
| | 03:24 | The second argument of the Open method is the
mode in which you are opening the database.
| | 03:29 | There are three available modes represented
by constants in the class SQLMode.
| | 03:34 | The modes are Create, Read and Update.
| | 03:36 | If you want to create a brand new
database call SQLMode.CREATE.
| | 03:41 | That's also the default value.
| | 03:43 | So if you didn't pass this argument
at all it would have the same result.
| | 03:46 | It's also worth mentioning that if you call this
code passing in the create mode and you connect
| | 03:51 | to a database file that already exists it will
be the same thing as opening the mode as Update.
| | 03:57 | So you won't actually be overwriting or creating a
brand new database if you called the create mode again.
| | 04:03 | Now, I'm going to close the database so that I can show you
| | 04:06 | that simply opening the database
actually creates the database file.
| | 04:10 | Then I will add a trace method in so that
when I run the application in Debug mode,
| | 04:15 | I will see that the function executed successfully.
| | 04:18 | I will save the change, run the application in Debug mode.
| | 04:24 | Now I'm also going to restore the size of the Flex
Builder so that I can see my desktop in the background.
| | 04:30 | I will move the application off to the side.
| | 04:32 | I will click the Create Database
button and you will see two things.
| | 04:37 | First of all, in the Flex Builder Console
view, I see the trace output Database created
| | 04:43 | and on my desktop I see the new database
file has been created, Contacts.db.
| | 04:49 | Now again, if you call the same code again using the
mode of SQLMode.CREATE, it won't recreate the database.
| | 04:58 | It will detect that the database already exists
| | 05:01 | and it will simply open the database
and allow you to read and write data.
| | 05:05 | So that's how you create a database
using synchronous operations.
| | 05:09 | In the next video, I will show you how to do
the same thing using asynchronous operations.
| | Collapse this transcript |
| Using asynchronous database operations| 00:00 | In this video, I'm going to describe how to use asynchronous
operations when working with the local database.
| | 00:06 | Just as when working with the local file
system, synchronous operations can have a result
| | 00:11 | of suspending the main application thread.
| | 00:13 | If you execute a long-running query this can freeze the
applications animations, user interactions and anything else
| | 00:20 | that you might want the user to be able to see.
| | 00:23 | To prevent this from happening, you can asynchronous
operations and then the SQL operations will run
| | 00:28 | in the background freeing the main
application thread to remain interactive.
| | 00:33 | For this demonstration, I will use the application
AsynchronousSQL.mxml in the Chapter09Begin Project.
| | 00:41 | If you are following along with the
exercises, you can open this application now.
| | 00:45 | This is the same application I built in the previous video.
| | 00:48 | It currently opens the SQL database synchronously and
then immediately response by closing the connection.
| | 00:55 | I am going to change this version of
the application to create a new copy
| | 00:59 | of the database which we will now call ContactsAsync.
| | 01:03 | Go to line 13 where the name of the
database is determined and change the name
| | 01:07 | of the database file from Contacts.db to ContactsAsync.db.
| | 01:14 | Next, go to line 15 that calls the open method
and change from the open method to openAsync.
| | 01:20 | When you open a database asynchronously,
the operation will happen in the background.
| | 01:25 | When the operation is complete the connection
object dispatches an event called open.
| | 01:30 | This event and most of the others that
are the part of the local database system
| | 01:34 | in AIR is dispatched as an event object typed as SQLEvent.
| | 01:38 | Place the cursor above the Async method and make an extra
line of code and add a call to the add event listener
| | 01:44 | like this, sqlConn.addEventListener listen for SQLEvent.OPEN
| | 01:53 | and then call a method called openHandler
which we will need to create.
| | 01:57 | Now place the cursor at the bottom of the
script section below the existing function
| | 02:02 | and create a new function named openHandler, which
receives an event argument, data typed as SQLEvent.
| | 02:11 | Return void and add the braces.
| | 02:15 | Now move a little bit of code around.
| | 02:17 | Go back to the createNewDatabase function
and locate the code sqlConn.close.
| | 02:23 | Because we are now opening the connection
asynchronously we shouldn't immediately close it so cut
| | 02:28 | and paste that code and move it into the openHandler method.
| | 02:35 | Similarly, we only want to notify the user that the
database has been created when this event is handled.
| | 02:41 | So go back to the createNewDatabase
and comment out the trace method call.
| | 02:46 | Go back to the openHandler method
and add a call to Alert.show.
| | 02:51 | Remember to always select the Alert class from
the list of available classes and that will ensure
| | 02:57 | that the appropriate import statement is added.
| | 02:59 | In the Alert.show method pass in two strings
Database successfully created and Opened.
| | 03:12 | Save your changes and run the application,
this time in Normal mode.
| | 03:19 | Click the Create Database button and you should see
the message appear, Database successfully created.
| | 03:25 | I will close the application, minimize
Flex Builder and show you
| | 03:31 | that ContactsAsync.db was successfully
created on the desktop.
| | 03:35 | So that's a look at how to use
asynchronous database operations.
| | 03:39 | For simplicity, I will primarily use synchronous
operations in all these demonstrations but I will also say
| | 03:45 | that most application deployed using the Adobe Integrated
Runtime, use asynchronous SQL operations to ensure
| | 03:52 | that the main application thread isn't
tied up while the database is active.
| | Collapse this transcript |
| Creating database tables| 00:00 | In this video, I'm going to describe how to
create a Database table in the local database.
| | 00:06 | I'll be using the SQL connection class again to open the
Database and then I will use a class called SQL statement
| | 00:13 | to encapsulate an SQL command and
execute it against the local Database.
| | 00:17 | For this demonstration I will use
the application CreateTable.mxml,
| | 00:22 | that you'll find in the Chapter09BeginProject.
| | 00:25 | If you are following along with the
exercises, you can open this application now.
| | 00:29 | In this version of the application, the code to open the
database has been moved into a function named openDatabase.
| | 00:37 | As in the earlier video that opened
the Database synchronously.
| | 00:41 | I use an SQL File object to define the location
of the Database as Contacts.db on my desktop.
| | 00:49 | Then I create a SQLConnection object and open the Database.
| | 00:54 | That function is in turn being called
by function called create NewTable
| | 00:58 | and that's where I will execute the new code.
| | 01:01 | Place the cursor in the create NewTable function and then
make a little bit of space after the call to open Database.
| | 01:08 | The first step is to create an instance of the SQL statement
class, declare a local variable named stmt for statement,
| | 01:18 | datatyped as SQL statement and instantiate it using
the SQL statement classes no arguments constructor.
| | 01:26 | Next, Set the statement objects SQLConnection
property to the connection that's already been opened.
| | 01:33 | stmt.sqlConnection = sqlConn.
| | 01:38 | The Next step is to add a text property.
| | 01:42 | The statement's text property is the
SQL statement that you want to execute.
| | 01:46 | I'm going to use some Data definition
language to create a new table named Person.
| | 01:52 | The code will look like this.
| | 01:54 | Stmt.text = then I will add a command to create a table.
| | 02:00 | I'll add clause named if not exists.
| | 02:04 | This means that if the table I'm about to
create already exists, I shouldn't recreate it.
| | 02:09 | Next I will put in the name of the
table and an opening parenthesis.
| | 02:13 | I'll close that little string then add a plus
operator to concatenate me to the next value.
| | 02:20 | Now, I'll add each of the columns one at a time.
| | 02:24 | The first column will be the primary key named person id.
| | 02:27 | Each column gets the name, a data type and any modifiers.
| | 02:34 | For the primary key I will use an integer column.
| | 02:37 | I'll declare that it's going to be the primary key
and also that it's an Auto Incrementing column.
| | 02:44 | So that as I add new records to the database
table, if I don't indicate a person id value,
| | 02:49 | the database will simply assign the next available value.
| | 02:53 | It's worth mentioning that SQL light
allows you to add explicit values
| | 02:57 | to primary key columns, even if
they marked as Auto Increment.
| | 03:00 | That isn't the case for all Databases.
| | 03:03 | I'll put in a comma, close this string and add a plus
operator and go to the next line to add the next column.
| | 03:11 | The rest of the columns are all going to be string values,
| | 03:15 | which in SQL Light as implemented in
AIR is datatype called simply Text.
| | 03:21 | So, each Database column will have a name.
| | 03:23 | The first one will be Firstname and a Data type of Text.
| | 03:31 | The Next, we'll have a data type of
lastname and data type of Text and so on.
| | 03:38 | Now to speed up this operational a little
bit, I'm going to clone this line of code.
| | 03:42 | In Flex Builder and all of the clips, you can hold down the
Ctrl and Alt key on Windows or the Command and Option key
| | 03:48 | on the Mac and press the down cursor key and
that will copy and paste that line of code.
| | 03:54 | I'll create a bunch of column definitions and then
go through and change their names appropriately.
| | 04:00 | Street address, city, state, email and phone, that'll
be the last column, so, I won't put in a comma,
| | 04:16 | instead I will put in a closing parenthesis and then I'll
close the ActionScript statement with the semicolon.
| | 04:25 | Now, I'll execute the statement for any SQL statement you
simply call the SQL Statement Object's Execute method.
| | 04:34 | There are some optional arguments including
managing, fetching order and item responders.
| | 04:40 | If you're familiar with how to use items responders
for instance, when we're using RPC components
| | 04:44 | such as remote object, you can
use a similar architecture here.
| | 04:48 | For this demonstration though because
I'm working synchronously,
| | 04:51 | I'll simply call the Execute method with no arguments.
| | 04:54 | Every time you call the execute method of an SQL statement.
| | 04:58 | It generates an internal object.
| | 05:01 | You can retrieve the result object as a class
named as SQLResult, like this; var result,
| | 05:08 | datatyped as SQL Result equals and then you
call the statement objects GetResult method.
| | 05:20 | Finally, I'll add a Trace statement and
indicate that the table was created.
| | 05:28 | I'll save the changes and I'm going to place a break point
right here at line 36, where I'm executing the trace method.
| | 05:36 | This is after I've executed the
statement and retrieved the result.
| | 05:39 | This will allow me to debug the result object.
| | 05:42 | I'll run the application in debug mode, click the create
Database button, that will take me to the break point
| | 05:51 | in flex builder, where all open the flex debugging
prospective and then double click on the Variables tab
| | 05:57 | to inspect the Data and take a
look at the SQL Result object.
| | 06:02 | The SQL Result object will differ in its content,
depending on what kind of SQL statement you've executed.
| | 06:09 | For instant, when you're creating a Database table.
| | 06:12 | The Data property of the SQL Result object is no.
| | 06:15 | On the other hand, if you retrieve data, the
Data property will refer to the return Data.
| | 06:20 | Similarly, If you were to execute an insert an update or
a delete, the row's affected property would be the number
| | 06:26 | of Rows that were effected by the operation.
| | 06:29 | When you are executing the Data definition
language statements such as a create table command.
| | 06:33 | The Rows affected property returns zero.
| | 06:36 | So, this is how you can find out what
happened after an SQL statement was executed.
| | 06:42 | I'll restore the size of the variables view and then
click to resume the operation and in the console view,
| | 06:49 | you'll see the message table was created.
| | 06:51 | This Database now has a single table named person.
| | 06:54 | It has the same structure as the Database that
I demonstrated earlier in this video series.
| | 07:00 | The contacts Database that was built in my SQL and in
a later video I'll talk about how to replicate the Data
| | 07:06 | from the network Database hosted in
MySQL and make copies of that data
| | 07:11 | in the local Database using simple insert statements.
| | Collapse this transcript |
| Inserting data| 00:00 | In this video, I'm going to describe, how to insert data
| | 00:03 | into a local database table using the
SQL connection and SQL statement classes.
| | 00:08 | For this demonstration, I will use an application
named InsertData.mxml from the Chapter 09BeginProject.
| | 00:16 | If you are following along with the
exercises, you can open that application now.
| | 00:21 | In this version of the application, all of the code to
open the database and then create the percent table,
| | 00:27 | if it doesn't already exist, has
been moved in to a method named init.
| | 00:32 | Then, that method in turn is being called
upon the creationComplete event handler
| | 00:37 | of the Windowed application component.
| | 00:39 | So, as the application starts up, I'm already connected
to the database and the table should already exist.
| | 00:46 | There's also an empty method named createRecord,
| | 00:49 | and a button component whose click
event handler calls that method.
| | 00:53 | Place the cursor in to the createRecord
method and add some space.
| | 00:57 | Start by creating a new SQL statement object.
| | 01:00 | I will declare a local variable named
stmt, datatyped as SQLStatement.
| | 01:06 | As before, I will instantiate it, using the
SQLStatement classes no arguments constructor.
| | 01:13 | Then, I will set the object's sqlConnection property
to my SQL connection, which I have named sqlConn.
| | 01:21 | Remember that connection object is
declared outside of any functions
| | 01:25 | and then was instantiated and opened in the init method.
| | 01:29 | I will go back to the method and continue the work.
| | 01:33 | The next step is to create the text property
of the statement object and as before,
| | 01:39 | this is the actual SQL statement that you want to execute.
| | 01:42 | I will build the statement one line at a time.
| | 01:45 | INSERT INTO person and then an opening parentheses.
| | 01:50 | Now, in flex builder, if you want to create a series
of concatenated strings, just type in the first string
| | 01:56 | and then before you put in to quote, press Enter or Return
and you will see that Flex Builder adds a closing quote
| | 02:02 | and a plus operator to the current line and then
adds an opening quote to the next line for you.
| | 02:07 | That makes a little bit easier to
build these concatenate strings.
| | 02:12 | Now, because I'm going to be inserting a new record, I
want the data base to use the auto increment property
| | 02:18 | of the primary key column Person ID to
assign the next available numeric value.
| | 02:23 | Therefore, I won't pass in the
name of the primary key column.
| | 02:27 | Instead I'm going to simply list the names of the
columns, into which I'm adding my own literal data;
| | 02:33 | these columns are, firstname, lastname, streetaddress
and again as I start reaching the end of the line,
| | 02:42 | I will just put in an extra space
at the end and then press Enter.
| | 02:46 | Then, city, state, email and phone.
| | 02:51 | I will put in a closing parentheses to indicate that that's
the end of the list of columns and then and extra space
| | 02:58 | to separate the code from the next
line and I will press Enter
| | 03:02 | and put in the key word VALUES
and again an opening parentheses.
| | 03:07 | Now, I will put in a list of literal values
that I want to insert into the table.
| | 03:12 | These will all be string values and following standard SQL
syntax, the values will each be wrapped in single quotes.
| | 03:19 | So, the first name will be Joe, the second name
will be Smith, the street address would be 123,
| | 03:27 | Main St. and again any time I want
to end that bit of literal text
| | 03:32 | and start in a new line, I will simply press enter.
| | 03:36 | Then, the city will be Seattle, the State will be
Washington, WA, the email address will be joe@crazymail.com
| | 03:49 | and the phone number will be 123-555-1111
or any other phone number you want to enter
| | 03:57 | and I will close the SQL statement
with a closing quote and a semicolon.
| | 04:02 | So, that's my SQL statement.
| | 04:04 | If you have long SQL statements like this,
| | 04:07 | you can break them up into multiple lines
consisting of multiple concatenated strings.
| | 04:12 | They are all pushed together or concatenated
into a single string and then assigned
| | 04:16 | to the text property of the SQL statement object.
| | 04:20 | Now, I will execute the statement to
actually add the data to the database.
| | 04:25 | I will call stmt.execute just as I did before.
| | 04:29 | Then, I will get the result by
declaring a variable name result,
| | 04:34 | datatyped as SQLResult then I will set the result property
by declaring a variable name result, datatyped as SQLResult
| | 04:42 | and I will get a reference to that object
from the statement object's' getResult method.
| | 04:47 | I will add a call to the trace function and I
will output a message of Data inserted and then,
| | 04:55 | I will place a break point on the last line of the
function where the trace method is being called.
| | 05:00 | I will save the changes and run
the application in debug mode.
| | 05:04 | I will click the Create Record button
and in the background you should see
| | 05:09 | that the Flex Builder prompts you to
go to the Flex Debugging perspective.
| | 05:14 | I will switch to Flex Builder.
| | 05:15 | Click yes to switch to the flex debugging perspective.
| | 05:19 | Take a look at the variables' view
and then look at the result object.
| | 05:23 | You should see that the result
object's complete property returns true.
| | 05:28 | The rows affected value should be one,
meaning that one row was inserted.
| | 05:33 | So that tell you that this was a successful operation.
| | 05:37 | Now, in the next video, I will show you how to retrieve
that data from the database table and then store it
| | 05:42 | in your Flex Air Application for use and presentation.
| | Collapse this transcript |
| Retrieving and handling data| 00:00 | In this video, I'm going to describe, how to retrieve data
| | 00:03 | from the local database using a
standard SQL Select statement.
| | 00:07 | I will show how the data is returned as an array and then
how you can wrap that array inside an array collection
| | 00:13 | for display and management in a Flex application.
| | 00:17 | For this demonstration, I will use an application in
the Chapter09BeginProject named RetrieveData.mxml.
| | 00:25 | This is the same application I was
working on in the previous video,
| | 00:28 | but this version of the application has added an
empty function named retrieveData and the button
| | 00:33 | with a label of retrieveData that calls the function.
| | 00:37 | Place the cursor inside the retrieveData method
| | 00:40 | and just as before declare a local variable
named stmt datatyped as SQLStatement.
| | 00:48 | Instantiate the object using the SQLStatement
class's no arguments constructor method.
| | 00:54 | Then plug in the Statement object and the Connection object
| | 00:57 | by setting the Statements object's
sqlConnection property to sqlConn.
| | 01:03 | As I described in previous videos, the
connection is declared outside of any functions
| | 01:10 | and then it's instantiated and
opened as the application starts up.
| | 01:14 | Going back to the retrieveData method, as before, set
the Statement object's text property to the SQLStatement
| | 01:23 | that you want to execute, this is going to be a
very simple Select statement, SELECT * FROM person.
| | 01:30 | Now, I will execute the Statement and once again
declare a variable name result, datatyped as SQLResult
| | 01:38 | and I will get the reference for the result
from the Statement object's getResult method.
| | 01:44 | Now I will set a breakpoint on the last line of the
function, that is the line that has closing brace,
| | 01:50 | save your changes and run the application in Debug mode.
| | 01:57 | Click Create Record a few times, notice in the Console
| | 02:01 | that each time you click Create Record,
you will get the message, Data inserted.
| | 02:05 | For now, you are inserting the
same data over and over again.
| | 02:10 | Now, click the Retrieve Data button.
| | 02:12 | When you hit the breakpoint, Flex Builder might
prompt you to open the Flex Debugging Perspective.
| | 02:18 | If so click Yes, then open up the Variables
view and inspect the SQLResult object.
| | 02:26 | Locate the result property and open
it in the Variables view and notice
| | 02:31 | that the data property is now data typed as an Array.
| | 02:34 | Open the array and you should see multiple data Objects.
| | 02:39 | Each of the data Objects has the same set of data.
| | 02:42 | But you will notice that each Object's personid property
representing the primary key has a different value.
| | 02:49 | Now, restore the Variables view to it's
regular size and click the Resume button.
| | 02:54 | Go down to where the breakpoint is and remove
it from code, so we can continue running,
| | 03:00 | go back to the running application, click the Create
Record button a few more times, go back to Flex Builder,
| | 03:08 | put the breakpoint back in, go back to the application
and once again retrieve the data, go back to Flex Builder
| | 03:16 | with the Breakpoints suspending the application
and inspect the data again and you will see now,
| | 03:22 | that there are many more rows of data in the application.
| | 03:26 | So that's how you retrieve the basic result.
| | 03:29 | Now terminate the Debugging session and
return to the Flex Development Perspective.
| | 03:34 | Now we know that the data comes back as
a data property of the result object.
| | 03:39 | It's an array and we would actually like to
have that data stored as an array collection.
| | 03:45 | So the next step is to wrap the data
inside an array collection like this,
| | 03:50 | go back to the top of the Script section and
declare a new Bindable variable named acContacts,
| | 04:01 | data typed as ArrayCollection.
| | 04:03 | Now move down to the retreiveData method and instantiate
acContacts like this, acContacts = new ArrayCollection
| | 04:16 | and pass the array into the ArrayCollection
constructor like this, result.data.
| | 04:24 | An ArrayCollection is a wrapper around an array
which provides dynamic access to the data at runtime.
| | 04:31 | Now go down to the DataGrid component and
add a dataProvider property and use a binding
| | 04:37 | and bind to the acContacts array collection.
| | 04:40 | Now before I continue, I'm going to check my Problems view
and see if there are any issues and in fact there is one.
| | 04:46 | I accidentally added a pair of parenthesis
when I declared the ArrayCollection.
| | 04:51 | I'm only declaring it, so I don't
need the parenthesis there.
| | 04:55 | I will save the changes, making sure that all the problems
have been cleared up and I will run the application.
| | 05:03 | Once again, I will click the Create Record button a few
times and then I will retrieve the data and I will see
| | 05:09 | that the data has been stored in the
database persistently on the local system
| | 05:13 | and that I can retrieve the data
using a standard SQL Statement.
| | 05:17 | So let's once again review the steps in retrieving data.
| | 05:20 | You create an SQLStatement object.
| | 05:24 | You set it's sqlConnection property to a connection that's
already opened, you set the Statement object's text property
| | 05:31 | to the SQL command that you want to execute.
| | 05:34 | You call the Statement object's execute method to
execute the SQLStatement, then you get the result back
| | 05:40 | from the Statement object's getResult method.
| | 05:42 | It comes back as an array and if you want to represent it as
an ArrayCollection, you wrap the array inside a new instance
| | 05:49 | of the ArrayCollection class and then you have
data that you can safely bind to visual controls.
| | Collapse this transcript |
| Using SQL statement parameters| 00:00 | In this video, I'm going to describe
how to use parameterized SQL statements,
| | 00:05 | that is SQL statements that have place
holders for values that you can then fill
| | 00:09 | in programmatically using a bit of ActionScript code.
| | 00:12 | For this demonstration, I will use an application in
the Chapter09BeginProject named UsingParameters.mxml.
| | 00:21 | If you are following along in the
exercises, you can open that application now.
| | 00:25 | In this version of the application, we are once again
creating a database in the applicationStorageDirectory
| | 00:32 | that is the directory that's unique to both
this application and to the current user
| | 00:37 | and then creating the person table,
if it doesn't already exist.
| | 00:41 | There is already a createRecord method that
inserts literal values into the person table.
| | 00:47 | Each time it's executed we are creating
a new row in the database table.
| | 00:51 | There is also a function, now named
emptyTable that executes a DELETE statement
| | 00:56 | that clears all of the data from the person table.
| | 00:59 | Use this function with some care, because it currently
doesn't have any confirmation interface to allow the user
| | 01:05 | to confirm or reject emptying the
table once they call the function.
| | 01:09 | Then there is a function named retreiveData that
executes a SELECT statement and saves the data
| | 01:15 | into a bindable ArrayCollection named acContacts.
| | 01:18 | The user interface of the application includes a DataGrid
to display the current data, this time only three columns
| | 01:25 | of the data, the firstname, the lastname and email and then
a couple of buttons labeled Retrieve Data and Empty Table.
| | 01:33 | There is also an instance of a custom
form component named PersonForm.
| | 01:38 | This component has already been completed, it's
a data entry form with input controls for each
| | 01:43 | of the non-primary key values in the database table.
| | 01:47 | When the user clicks a button to save the new data, it
creates an instance of a value object class named Person,
| | 01:54 | passes in the values from the data
entry form and then dispatches
| | 01:58 | that object inside a custom event named PersonEvent.
| | 02:02 | At the application level, we then listen
for that event using the save event handler,
| | 02:07 | that's a custom event that's a part of the form
component and we call the createRecord method.
| | 02:12 | I will run the application initially and as it starts up, it
should create a new empty database table in a new database.
| | 02:20 | I will click the Save button a few times, one, two and three
and then click the Retrieve Data button and you will see
| | 02:28 | that I'm successfully adding records with literal values.
| | 02:32 | Then I will click the Empty Table button
and I will clear the database table.
| | 02:37 | Now I'm finally ready to demonstrate
the use of parameterized statements.
| | 02:41 | Move to the createRecord function which currently
executes an INSERT statement and adds literal values.
| | 02:48 | Parameterized statements can be declared in a couple
of different ways, but here is the most common syntax.
| | 02:54 | I will remove the literal value and replace
it with a parameter that starts with a colon
| | 02:59 | and then assigns a parameter name, :firstname and I will do
that for each of the values that I'm inserting, :firstname,
| | 03:09 | :lastname and notice that I'm simply matching the
names of the columns, you don't have to do that,
| | 03:16 | you can use parameters of any name you
like, however it does make it a lot easier
| | 03:20 | if you simply match the parameter names to column names.
| | 03:27 | So, now I have seven parameters, each named for
the column into which their data will be inserted.
| | 03:34 | Notice that the order of the parameters matches
the order of the columns in the first list.
| | 03:39 | Now, before I execute the statement, I
have to assign values to each parameter.
| | 03:44 | The SQLStatement class has a property named
parameters which is a generic ActionScript object.
| | 03:52 | Each time you create a new parameter, you
do so with associative array style syntax.
| | 03:58 | Put in a pair of brackets and inside the brackets,
| | 04:01 | put in a string that matches the parameter
name that you are replacing with a value.
| | 04:06 | So, for instance to replace the firstname parameter,
the syntax is, stmt.parameters, then open bracket((),
| | 04:16 | then the name of the parameter as a string,
close bracket()) and then assign a value.
| | 04:19 | Notice that this createRecord function
is receiving an argument named person
| | 04:24 | which us data typed as the Person value object.
| | 04:27 | So, I can assign the value like this, person.firstname.
| | 04:33 | Notice that the use of the strongly typed person
value object class, makes it a lot easier to type
| | 04:38 | in the property names, autocomplete those values
and make sure that you have typed them correctly.
| | 04:44 | Now, I'm going to clone this line of code, remember,
| | 04:47 | you can clone a line of code using either
Ctrl+Alt+Down on Windows or Command+Alt+Down on Mac.
| | 04:55 | I will end up with one line of code
for each parameter I need to replace,
| | 04:59 | then I will replace them one at time, the lastname.
| | 05:08 | So, I first created the SQL statement with named
parameters where I need to plug in the values,
| | 05:14 | then I set each parameter individually, using the
parametered name, prefixed with a colon(:) as a string.
| | 05:21 | I pass that value into the parameter's object using
associative array style syntax and I assign the value.
| | 05:27 | In this case, from the value object that was passed in
as an argument, then just as before I execute the method
| | 05:34 | and this time after I have called the execute()
method, instead of retrieving a result,
| | 05:40 | I will simply call the existing retrieveData function and
that will result in displaying the new data in the DataGrid.
| | 05:46 | I will save the changes and run the application.
| | 05:50 | I will start by clicking into the
form and typing in some values.
| | 05:56 | You can type-in whatever values you want into the form, then
I will click the Save button to call the createRecord method
| | 06:09 | and you will see that the data was correctly added to the
local database, I will change some values in the form.
| | 06:20 | Once again, I will click the Save method and you will
see that I'm adding new records each time I click.
| | 06:25 | So that's how we use parameterized SQL statements
when working with a local SQL like database.
| | 06:32 | Just to review the steps one more time, the statement
itself is constructed as standard SQL statement.
| | 06:39 | You plug in parameters using the syntax, colon(:)
and then the name of the parameter you want to use.
| | 06:45 | The best practice is to use a parameter
name that matches the column name.
| | 06:49 | Then for each parameter, you replace the parameter with
a value, by setting it's value in the parameter's object
| | 06:55 | of the SQL statement, then as before you
execute the statement and the result is passing
| | 07:02 | in parameterized SQL statements without having to worry
about concatenating all of the strings together yourself.
| | 07:07 | c
| | Collapse this transcript |
| Using transactions| 00:01 | In this video, I'm going to describe how to
use transactions with the local database.
| | 00:05 | For this demonstration, I will use an
application named UsingTransactions.mxml,
| | 00:11 | that's part of the Chapter09 Project.
| | 00:14 | If you are following with the exercises,
you can open the application now.
| | 00:18 | This version of the application is
much the same as in the previous video.
| | 00:22 | The data is provided by the user through a data entry form.
| | 00:25 | This version of the application has a few
other items that have already been coded.
| | 00:30 | Down at the bottom of the Script section, there
are three empty functions named beginTransaction,
| | 00:35 | commitTransaction and rollbackTransaction.
| | 00:38 | And then, there are two additional buttons labeled
Commit and Roll Back that call two of the functions.
| | 00:44 | Go back to the function, beginTransaction.
| | 00:47 | In order to begin a transaction, you call a
method of the SQL connection class called Begin.
| | 00:53 | It looks like this, sqlConn.begin.
| | 00:57 | There are some optional arguments that you can pass in,
| | 01:01 | in particular the responder object can be
used, if you are working asynchronously.
| | 01:05 | In this demonstration though I'm working
synchronously and I don't need any options.
| | 01:09 | So I will simply call the method with no arguments.
| | 01:12 | I would also like to track from moment to
moment, whether a transaction is pending.
| | 01:17 | I will go back to the top of the script
section and I will add a new Bindable variable.
| | 01:28 | I will name the variable, transactionPending
and datatype it as Boolean value
| | 01:35 | and initialize defaults as the application starts up.
| | 01:38 | Then I will go back down to the
beginTransaction method and I will set the value
| | 01:42 | of that variable transactionPending to True.
| | 01:46 | Now I will go back down to the buttons, I would like to
set the Commit and Roll Back buttons in enabled states,
| | 01:52 | so that they can only be clicked
when there is a transactionPending.
| | 01:56 | So I will go to each of the buttons and add an enabled
property and I will set the value of the enabled property,
| | 02:02 | using a binding expression that binds to this new variable.
| | 02:06 | I will do the same thing in the Roll Back button.
| | 02:09 | Because I only want the user to be
able to click either of these buttons
| | 02:12 | if in fact, there something to Commit or Roll Back.
| | 02:14 | Now, we will go to the commitTransaction method, in order to
commit a transaction that is to save the results permanently
| | 02:23 | to the database, you call a method of
the SQL connection object named Commit.
| | 02:30 | As with the begin method, there
is an optional responder object.
| | 02:34 | If you are familiar with item respond of Design
Pattern that allows you to setup an object
| | 02:38 | that has various event handlers you can use
this feature, if you are working asynchronously.
| | 02:44 | Because I'm working synchronously, I will just call the
Commit method directly and then I will set the value
| | 02:49 | of transactionPending, back to a value of False.
| | 02:53 | In the rollbackTransaction method, I will do the same
thing, I will call the connections rollback method.
| | 02:59 | Once again, I'm working synchronously, so I don't need
the responder object and as with commitTransaction method,
| | 03:06 | I will reset the value of transactionPending to false.
| | 03:12 | Finally, I will go back to createRecord method
and place the cursor above the existing code
| | 03:18 | and I will call the beginTransaction method.
| | 03:21 | Now, each time the user tries to add a new row to the
database, I will begin the transaction and go ahead
| | 03:27 | and execute the parameterized Insert
statement to add the row to the database table.
| | 03:32 | You will see when I run the application that
the data appears immediately in the table.
| | 03:37 | But it's only saved permanently, if
explicitly commit the transaction,
| | 03:41 | but then if I rollback the transaction
that new data will be removed.
| | 03:45 | I will save the change and run the
application to demonstrate the results.
| | 03:50 | I will click into the form and type some values,
I will click the Save button and watch the Commit
| | 03:58 | and Roll Back buttons over on the
right side of the application,
| | 04:01 | because the call to the beginTransaction method,
| | 04:04 | change the value of the transactionPending
variable to true, now those button are enabled.
| | 04:10 | Now I will click the Commit button, you won't see any
change in the data, but the data has been saved permanently
| | 04:16 | to the local database and the two buttons are now disabled.
| | 04:19 | I will empty the table by clicking the Empty Table
button, then I will go back to the form and Save again.
| | 04:26 | This time I will click the Roll Back
button and then click Retrieve Data
| | 04:30 | and you will see that the database table is empty again.
| | 04:34 | This is because, when you roll back the
transaction, any statements that you executed
| | 04:38 | after you started the transaction are treated
as though, they essentially never happened.
| | 04:43 | There is a lot more to learn about
transaction behavior using the local database.
| | 04:48 | For more information, check the documentation for different
isolation levels and other tricks that you can do,
| | 04:55 | when Committing or Rolling Back transactions.
| | Collapse this transcript |
| Creating an occasionally connected application| 00:01 | In this video, I'm going to describe encode
review, a completed application that's designed
| | 00:06 | to be occasionally connected to the network.
| | 00:08 | The application is named ContactManager.mxml, and
you will find it in the Chapter 09_Begin folder
| | 00:14 | if you are working along with the exercises.
| | 00:16 | Now, for those of you, who don't have access to the
exercise files, let me precaution you that in this video,
| | 00:21 | I won't be able to show you all of the code on
the video screen because it's quite extensive.
| | 00:26 | But, I will show you the key methods and describe how
the application is running and then if you have access
| | 00:31 | to the exercise files, either through a premium membership
in the online library, or through the DVD version
| | 00:37 | of this title, you will be able to
explore the code more completely.
| | 00:40 | I will open up the application code to full screen.
| | 00:44 | This application, as you can see, declares an array
collection named acPerson that holds data in memory
| | 00:50 | and when I run the application and then click the Get
Data button, it retrieves data from a network resource.
| | 00:57 | Now, if you are following along in the exercises,
before you try to run the application in this mode,
| | 01:01 | make sure that you started up WAMP or MAMP, one of
the two server bundles that I described how to install
| | 01:07 | in the first chapter of the video series.
| | 01:10 | Also make sure that you have imported the database
table that comes with the video series exercises
| | 01:15 | and you have installed the PHP files that are
used to retrieve the data from the network.
| | 01:20 | So, this is what the application looks
like when you are connected to the network.
| | 01:24 | But, this application has been designed so
that the user wants to save the data locally,
| | 01:29 | they can do so through a single click of the button.
| | 01:32 | And then when they start up the application later
on and the network resource isn't available,
| | 01:37 | they'll be able to instead retrieve the data
from their local resource, the local database.
| | 01:41 | Let's take a look at how that works.
| | 01:43 | When the application is connected to the
network, the user is able to click a button
| | 01:48 | that calls a method named saveToLocal,
which is right down here.
| | 01:53 | The saveToLocal method sets a Busy Cursor, which means it
start an animation of a clock, whose hands are spinning.
| | 01:59 | And then it calls a method of a class
named PersonManager named saveToLocal
| | 02:05 | and passes the array collection of
data that it got from the network.
| | 02:08 | Let's take a look at that method.
| | 02:10 | In the saveToLocal method, there's an SQL Statement
| | 02:13 | that first empties a local database
and then it adds an EventListner.
| | 02:18 | Now, I should mention that all of the code
| | 02:20 | in the PersonManager class is executing
SQL Statements asynchronously.
| | 02:25 | That's because, when you move the data from the network to
the local database, there are thousand records to import,
| | 02:31 | and that's going to take more than a second.
| | 02:33 | So, by using asynchronous operations, we allow the
user to continue to interact with the application
| | 02:39 | and we don't freeze any animations such
as the Busy Cursor, the animated clock.
| | 02:43 | After the saveToLocal method, executes
the first statement, DELETE FROM person,
| | 02:48 | it then daisy-chained to the next method, emptyTableHandler.
| | 02:52 | Because of the addEventListener method, that's called
at line 74, within the emptyTableHandler method,
| | 02:58 | I'm setting a recordNumber variable which has
been declared global to the class to zero,
| | 03:03 | and then calling a method called createRecord.
| | 03:05 | In the createRecord method, I retrieve the
person at the current index of the recordNumber
| | 03:12 | and save it as a local variable named Person.
| | 03:15 | Then I create and execute a parameterized insert statement
to insert that record's data into the local database.
| | 03:24 | Before I execute the SQL Statement, I add an
EventListener to call a method called nextRecord.
| | 03:29 | Then I execute the statement and insert that row.
| | 03:32 | In the nextRecord method, which is
called upon that resultEvent occurring,
| | 03:37 | I first check to see if there are any records left.
| | 03:39 | If the current record number doesn't match the length - 1
of the NetworkData, then I increment the record number by 1
| | 03:46 | and then call the createRecord method again.
| | 03:49 | So, this code loops around for as long as
there are items in the array collection
| | 03:53 | or if I have already inserted all the data, I
dispatch an event from this class named SAVE_COMPLETE,
| | 04:00 | and this constant SAVE_COMPLETE is declared as part of
the PersonManager classes of public static constant.
| | 04:06 | They can be referred to both, within this
code and in the main application code.
| | 04:09 | Finally, back at the Contact Manager.
| | 04:11 | If you go back to the top of the application to the
init method, you will see that in the init method,
| | 04:17 | there's an addEventListener function being called on the
PersonManager object to listen for the SAVE_COMPLETE event
| | 04:23 | and then dispatch that event to saveCompleteHandler
and at that point, I remove the busy cursor
| | 04:29 | and give the user a message indicating that the data
has been copied from the network to the local database.
| | 04:35 | So, let's run that part of the application.
| | 04:38 | Wait for the monitor to indicate that the network is
available and then I will click the Get Data button.
| | 04:43 | The data comes back from the network fairly quickly.
| | 04:46 | Now, I will save the data from the
network data to the local data.
| | 04:49 | I will click the button and once
again, we see the clock cursor.
| | 04:54 | This time because of the explicit call to
the cursor, manages setBusyCursor method.
| | 04:58 | Notice that even though the SQL Statements are still
running in the background, I still see animations
| | 05:03 | and I can still interact with the application.
| | 05:06 | Now that the data has been copied from the
network data source to the local data source,
| | 05:10 | I get a message saying that the operation is complete.
| | 05:13 | Okay, so now the data has been saved locally.
| | 05:15 | Let's take a look at what happens when the user starts up
the application and they don't have the network available.
| | 05:21 | Go back to the init method of the
Contact Manager application.
| | 05:26 | Notice that in the init method, we set an event listener
for the statusHandler and once again in the statusHandler,
| | 05:32 | we're indicating and in the statusHandler method,
we determine whether we're going to get our data
| | 05:36 | from the network or from the local database.
| | 05:39 | If I'm disconnected from the network, I'll
have to get the data from the local database.
| | 05:43 | So, let's make that happen.
| | 05:44 | I'll go down to my WAMP icon in the system
tray, if you are working on Mac instead go
| | 05:49 | to the MAMP application and shut down services.
| | 05:53 | And if you are working on Windows, click on the
System Tray icon, and select Stop All Services.
| | 06:00 | Wait a moment for the services to shut
down then run the application again.
| | 06:04 | This time as the application starts up, the monitor
determines that the network is not available.
| | 06:09 | I'll click the Get Data button again but this time the
data is going to come from the local database and notice
| | 06:15 | that it appears much more quickly than
it did, when it came from the network.
| | 06:19 | Let's take a look and see how that's happening.
| | 06:22 | Go to the Contact Manager application code
again and take a look at the getData method.
| | 06:26 | Within the getData method, there is a call to
the getAll function of the PersonManager class.
| | 06:32 | They get all function, executes a
Select statement, retrieves the data
| | 06:36 | and then listens for a result event internally.
| | 06:39 | When that event happens, a getAllResultHandler method
is called internal to the class and in that method,
| | 06:45 | the data is transformed from an array of objects and
in that method, the data is transformed from the array
| | 06:51 | of generic objects that's returned from the local database
into an array collection of strongly typed value objects.
| | 06:58 | Finally, at lines 158 to 160, an instance of
a class called LocalDataEvent is dispatched.
| | 07:06 | The LocalDataEvent custom class is designed to hold
an instance of the ArrayCollection as a data object.
| | 07:12 | Back at the application level, we are listening
for that event to occur and when it occurs,
| | 07:18 | we call a method called localResultHandler as a
result of an event listener, here is the method
| | 07:23 | and in the method we remove the Busy
Cursor and save the events data object
| | 07:28 | to the global ArrayCollection and
it's displayed in the application.
| | 07:32 | So, let's run all three features one at a time.
| | 07:35 | I'll restart WAMP, wait a moment for the services to
start up, then go back and run the application again.
| | 07:43 | As soon as I get a notice that the network is available,
| | 07:45 | I'll click the Get Data button and
retrieve the data from the network.
| | 07:49 | Then I'll click the Save to Local button and it will take
four or five seconds at least to save to the local database
| | 07:55 | and how fast it happens really is depended
on the processor speed of the local system.
| | 07:59 | Once the Save to Local operation is complete, I'll see
this notification that the date has been saved locally.
| | 08:05 | Now keeping the application open, I'll clear
the data, I'll go back to my WAMP interface.
| | 08:11 | If you're working on Mac, go to MAMP, I'll stop all the
services and wait a moment for the application to detect,
| | 08:18 | as you'll see in the status bar that now
we are working with the local data source.
| | 08:22 | I'll click the Get Data button and the
data is retrieved from the local database.
| | 08:26 | So this is an occasionally connected application.
| | 08:28 | There is clearly a lot more that you could do with this,
including being able to create new data or modify data
| | 08:34 | on the client and then when you are reconnected,
automatically synchronize it back to the network database.
| | 08:39 | That's all work that you can do,
but it takes a bit of coding,
| | 08:42 | but this finished application should give you a model of
how you can integrate data that starts off on the network
| | 08:48 | and then is saved locally, so that the user can still use
the data even when they are not connected to the network.
| | Collapse this transcript |
|
|
10. Encrypting Local DataUnderstanding the EncryptedLocalStore class| 00:00 | In this chapter of the video series, I'm going to
describe how to encrypt data and store it locally,
| | 00:06 | so that is only available to AIR
applications and only available when the user
| | 00:10 | who created the data and stored
it is logging on that system.
| | 00:13 | This is a capability that's built
into the Adobe Integrated Runtime.
| | 00:17 | Each AIR application has the ability to save a small
amount of data that's encrypted and stored locally.
| | 00:23 | The data that you store is unique to
that application and to the current user.
| | 00:28 | This feature leverages capabilities of the local operating
system, an API called DPAPI on Windows and Keychain
| | 00:35 | on the Mac, so that the data is stored in the best
encryption possible for that particular operating system.
| | 00:41 | Regardless of which operating system the application is
going to run on though, you program the tasks of setting
| | 00:46 | and retrieving data using exactly the same code.
| | 00:49 | The encrypted local store function is only available
to application code that's in the application sandbox.
| | 00:55 | For example, if you were to run an AIR application that
use JavaScript code and that JavaScript code was downloaded
| | 01:01 | from the web at runtime, that code would
not have access to this capability.
| | 01:06 | The EncryptedLocalStore class is an ActionScript class
that's the part of the AIR Libraries and is available
| | 01:11 | to you always when you are working
on AIR applications in Flex.
| | 01:14 | This class has methods to set and
retrieve data from the EncryptedLocalStore.
| | 01:19 | In order to add data, it must first be stored as byte array.
| | 01:23 | In order to translate a simple string value
into a byte array, follow these steps:
| | 01:27 | Instantiate a ByteArray object using the
ByteArray classes no arguments constructor method,
| | 01:32 | then call the object writeUTFBytes
method and pass in the string value,
| | 01:36 | the ByteArray will now contain the
string value in the proper form.
| | 01:40 | Next, to save the data locally in an encrypted format
call the EncryptedLocalStore static method setItem,
| | 01:47 | pass in a key value in the first argument.
| | 01:50 | The key is a string value with which you are
associating your data, then pass in the ByteArray.
| | 01:55 | The data will now be stored and encrypted locally.
| | 01:59 | Later when you want to retrieve the data, once again use
EncryptedLocalStore class, call it static getItem method
| | 02:06 | and once again pass in that same key value.
| | 02:08 | You will get back a ByteArray, just like the one that
you passed in earlier and then you will translate it
| | 02:13 | to a simple String using the ByteArray
object's readUTFbytes method.
| | 02:18 | The numeric value that you pass into this
method is the number of bytes in the array
| | 02:22 | which you can get from its length property.
| | 02:25 | So the syntax you see on the screen, readUTFbytes
passing in storeValue.length means take the bytes,
| | 02:31 | takes this many bytes and translate those to a string.
| | 02:35 | So in the next couple of videos, I'll show
how to do this in an actual application.
| | 02:40 | Taking data and storing it locally
using the EncryptedLocalStore class
| | 02:44 | and then retrieving the data in
a different application session.
| | Collapse this transcript |
| Inserting data into the encrypted local store| 00:00 | In this video, I'm going to describe how
to add data to the encrypted local store.
| | 00:05 | If you are following along with the
exercises, you can import the Flex Project
| | 00:08 | that I'll be doing these demonstrations in.
| | 00:10 | From the Flex Builder Menu select File, Import, Flex
Project, click the Browse button next to Archive File,
| | 00:19 | navigate to the Chapter10 folder under the exercises
area and then select Chapter10BeginProject.zip,
| | 00:27 | finish importing the Project, then go to the Flex
Navigator View and open the Project Source Folder
| | 00:34 | and open an application named SetEncrypted.mxml.
| | 00:39 | This application has a simple data
entry form wrapped in a panel.
| | 00:43 | I'll run the application so we can see what it looks like,
it asks the user to type in a username and a password
| | 00:49 | and then has buttons labeled Save
Credentials and Load Credentials.
| | 00:52 | These buttons respectively call functions named
setCredentials and getCredentials, that are already created.
| | 00:59 | Place the cursor in the setCredentials
method and follow these steps.
| | 01:02 | First create a ByteArray, declare a local
variable named bytes data typed as a ByteArray
| | 01:09 | and instantiate it using the ByteArray
class's, no arguments constructor method.
| | 01:14 | Now, you'll be taking the value that the user has typed
in, in the text input control with an id of usernameInput.
| | 01:21 | Go back to the code and call this method,
bytes.writeUTFBytes and pass in the value that you want
| | 01:30 | to place into the ByteArray, usernameInput.text.
| | 01:34 | Now you are ready to save the user's
information to the EncryptedLocalStore.
| | 01:38 | Call the EncryptedLocalStore class's static
setItem method, pass in a name which is the key.
| | 01:46 | I use a key of username and then I'll pass in the bytes.
| | 01:50 | Then I'll use the Alert class, I'll type in the word
Alert then press Ctrl+Space and select the class
| | 01:56 | to cause it's import statement to be added.
| | 01:59 | Then I'll call the show() method and I'll display
a message in the pop-up window that says Data Saved
| | 02:04 | and I'll put a title on the pop-up
window of Encrypted Local Store.
| | 02:12 | I'll save the changes and run the application.
| | 02:15 | I'll click into the username text input control and type
in my name and then I'll click the Save Credentials button
| | 02:25 | and I'll get the message that the Data has been Saved.
| | 02:27 | Now there is no way to verify that, that data has been
saved other than by retrieving it from the same application.
| | 02:33 | So, in the next video, I'll show you how to retrieve that
same data by once again using the EncryptedLocalStore class.
| | Collapse this transcript |
| Retrieving data from the encrypted local store| 00:00 | In this video, I'm going to describe how to retrieve
encrypted data from the EncryptedLocalStore.
| | 00:05 | For this demonstration I'll use an application
named Getcrypted.mxml in the Chapter10BeginProject.
| | 00:12 | If you are following along with the
exercises, open the application now.
| | 00:16 | This is the same application that
I created in the previous video
| | 00:19 | that currently can save encrypted data to the local store.
| | 00:23 | Place the cursor in the getCredentials method, the
fist step in retrieving data is to declare a ByteArray.
| | 00:30 | We can reuse the variable named bytes because both
variables are declared local to the functions.
| | 00:35 | I'll data type it as a ByteArray
and then I'll fill in the ByteArray
| | 00:39 | by calling the EncryptedLocalStore's,
static method, getItem.
| | 00:43 | The I'll pass in the same key, that I used
in setting the item previously, username.
| | 00:49 | Next, I'll translate the ByteArray to a string value var
username.String typed as a string = bytes.readUTFBytes
| | 01:03 | and as I described earlier, you pass in the
length or the number of bytes in the ByteArray
| | 01:08 | by using the ByteArray's length property.
| | 01:13 | So, now the encrypted value has been
decrypted and saved back to a simple string.
| | 01:19 | I'll now save that to the usernameInput
control and I now I'll test the application.
| | 01:32 | I'll run the application, I'll click
into the username text input control
| | 01:37 | and type in a value davidG and click save credentials.
| | 01:42 | I get a message that the data has been saved, I'll
click OK and then manually clear out the username
| | 01:50 | and then click the loadCredentials() method
and you'll see that the data is retrieved.
| | 01:54 | Now the data is actually stored
persistently on the local system.
| | 01:58 | So, now I'll be able to close the application
completely and then reopen it again and this time
| | 02:04 | when the application opens I immediately click
the Load Credentials button and you'll see
| | 02:08 | that the data is still there in the local system.
| | 02:11 | So this is sort of like cookies and also very
similar to the local shared object architecture,
| | 02:16 | that's been available in the Flash Player for a long time.
| | 02:19 | But unlike these architectures, it
involves strong encryption and that means
| | 02:23 | that you can safely safe these kinds of
values on the local system and you'll know
| | 02:27 | that you are using the strongest possible encryption
that's available with the current hosting operating system.
| | Collapse this transcript |
|
|
11. Invoking an AIR ApplicationUsing command-line arguments with AIR| 00:00 | In this chapter of the video series, I'm
going to describe various aspects working
| | 00:04 | with AIR applications during the start
up phase of running the application.
| | 00:09 | I'll be talking about using Command Line Arguments,
detecting the application directory upon startup,
| | 00:15 | launching the application from the web and other
advanced approaches to working with the start up phase.
| | 00:21 | For all of the demonstrations in this chapter, I'll
be using a Flex project from the exercises area.
| | 00:27 | If you are following along in the
exercises, you can import the project.
| | 00:31 | From the Flex Builder menu select
File, Import, Flex Project.
| | 00:38 | Click the browse button next to Archive
File, go to the Chapter11 folder
| | 00:42 | in the exercises area and select Chapter11BeginProject.zip.
| | 00:49 | Import the project in the Flex Builder, then go to the Flex
Navigator View, open the project and open its source folder.
| | 00:57 | Then open the application CommandLineArgs.mxml.
| | 01:03 | This application has a simple text area control with
an ID OWOUT and a font size setting that's applied
| | 01:09 | to the global selector, setting
everything to a font of 12 pixels.
| | 01:14 | This will allow everything to be able to
little bit more visible on the screen.
| | 01:17 | Every time you start an application, no matter how it's
started, the application dispatches an event named Invoke.
| | 01:25 | This event dispatches an event object, data
typed as something called Invoke Event.
| | 01:30 | The Invoke Event class has access to
information, such as Command Line Arguments
| | 01:36 | and the current directory in which
the application is starting.
| | 01:39 | To get started, go to the WindowedApplication tag, go
to the end of the tag and add a line feed at the end
| | 01:47 | of the tag before the closing greater than symbol.
| | 01:50 | Then add an invoke event handler.
| | 01:54 | When this event is dispatched, I'll call an event
handler function named invokeHandler that I'll need
| | 01:59 | to create, and I'll pass the event object.
| | 02:04 | Now go to the Script section.
| | 02:07 | Declare private function named invokeHandler; its
event argument will be data typed as InvokeEvent.
| | 02:15 | Return void and put in a pair of braces.
| | 02:20 | Then place a break point on the last line
of the function, save the application
| | 02:25 | and then run the application in debug mode.
| | 02:27 | As the application starts up, the
invoke event is dispatched immediately.
| | 02:32 | This gives you an opportunity to
handle the event and see what's in it.
| | 02:37 | If you're prompted to open the
flex debugging prospective as I am,
| | 02:40 | click Yes and then within the Flex debugging
perspective, go to the Variables view.
| | 02:46 | Double click its tab to expand it to full screen and
then open up the event object to inspect its values.
| | 02:54 | Notice that there are two properties of
this event object that can be useful.
| | 02:58 | The Arguments property is in Array
and it will contain any values
| | 03:02 | that were passed to the application on the command line.
| | 03:05 | There is also a property named currentDirectory.
| | 03:09 | So, these are the two properties we have available.
| | 03:11 | Here is what we are going to do with them.
| | 03:14 | Double click the Variables tab to restore to its
original size and then terminate the Debugging session
| | 03:19 | and then go back to the Flex Development Perspective.
| | 03:23 | When the application starts up, you'll
add code into the invokeHandler function
| | 03:29 | to output the current command line arguments as a string.
| | 03:33 | Also we'll use the current directory property which is
returned as a File object and I'll put its native path.
| | 03:40 | Within the invokeHandler method at this code out.text
= Arguments, then add a + operator to concatenate
| | 03:55 | and add this syntax, event.arguments.toString.
| | 04:01 | This will take the array of arguments and
output it as a comment to limited list.
| | 04:06 | Also add a line feed like this, out.text += n,
that's the escaped character for a line feed
| | 04:17 | and then on the next line out.text += Current
Directory as a literal string and then concatenate
| | 04:28 | to that event.currentDirectory.nativePath, again remembering
| | 04:34 | that the current directory properties
returns as a file object.
| | 04:38 | Save your changes and run the application,
this time in normal mode.
| | 04:42 | As the application starts up you should
see that the Arguments value is blank,
| | 04:48 | whereas the Current Directories is reported
as the Flex Builder 3 installation directory.
| | 04:53 | Now to really see this behavior,
we're going to need to package
| | 04:57 | and install the application and
then run it from the Command Line.
| | 05:01 | So, close the application and then export
a released version of the application.
| | 05:07 | Go to the menu and select File, Export, Release Built.
| | 05:14 | Select the CommandLineArgs.mxml
application from the Chapter11BeginProject,
| | 05:21 | click Next and in the digital signature
screen either create a new certificate
| | 05:26 | or use one that you've already created previously.
| | 05:29 | I'm using the certificate that I created in one of the
early exercises in the video series and the password
| | 05:35 | that I have put in was simply the word password.
| | 05:37 | I'll click Next, and then Finish and that will create
my AIR file so that I can install the application.
| | 05:47 | Now go to the Flex Navigator View
and open CommandLineArgs.air
| | 05:52 | which you can do by double clicking on it.
| | 05:55 | Once the application installer opens up click Install
and then accept all of the options and click Continue.
| | 06:02 | When the application starts up, you should
see the current directory information again
| | 06:07 | but once again No Command Line Arguments.
| | 06:10 | Okay, now we're ready to see what happens
when you do pass in command line arguments.
| | 06:15 | If you are working on Windows, go to the Start
Menu and if you are Windows Vista just type in cmd.
| | 06:21 | If you are working on Windows XP, click Run
and then type cmd into the dialog that appears
| | 06:29 | and that will take to a CommandLine Window.
| | 06:31 | If you are working on the Mac, open the terminal
application which you'll find in applicationsutilities.
| | 06:39 | Now if you are working on Windows, switch to the
folder in which the application was installed.
| | 06:44 | Type cdProgram Files and working on either XP or Vista
you should be able to type in the first few characters
| | 06:53 | of the directory and then press Tab to fill it in.
| | 06:56 | Then put in a back slash and then the first few characters
of the application, CommandLineArgs, and then Tab again.
| | 07:05 | Press Enter and then type in Dir and Enter and you
should see a listing of the files that were installed.
| | 07:13 | If you are working on Mac, you don't need to change
the directory, instead as you type in the name
| | 07:19 | of the application that you want to
run, start with the slash character,
| | 07:23 | then applications, then CommandLineArgs.app.
| | 07:26 | I'll get into the details of that in a moment for the Mac.
| | 07:29 | Here is what it looks like on Windows though.
| | 07:32 | Now I'm going to type in the name of
the application, CommandLineArgs.exe,
| | 07:37 | once again I typed the first few characters and press
Tab and then Windows completed the file name for me.
| | 07:43 | Now I'll put in a space and then a few
command line arguments, arg1 arg2 and arg3.
| | 07:51 | I'll press Enter to run the application and you'll see that,
now the arguments are reported as a comment to limited list
| | 07:59 | and once again the current directory is reported as
the directory from which I launched the application.
| | 08:05 | This time I'll close the application and
change back to the root folder of the C drive.
| | 08:11 | Now to run the application, I'll use the entire path,
Program FilesCommandLineArgsCommandLineArgs.exe.
| | 08:22 | Once again I'll pass in a few arguments,
run the application and now notice
| | 08:28 | that the current directory is the
root folder from which I launched.
| | 08:32 | So, the current directory that you get in the invoke event
object is not the same thing as the application directory.
| | 08:38 | Instead, it's the directory that was considered the
current directory at the time that you started up.
| | 08:45 | Now if you are working on Mac OS X,
here is the path that you'll use.
| | 08:49 | From within terminal, type in Applications, then
CommandLineArgs.app just like in the command window
| | 09:00 | in Windows, you can type in the
first few characters of anything
| | 09:04 | and then press Tab and terminal will complete it for you.
| | 09:08 | But be aware that in terminal everything is
case sensitive, so you have to type in the names
| | 09:12 | of files using the correct case,
upper case where it's needed.
| | 09:16 | So it's applicationsCommandLineArgs.appContentMac
OS and then once again CommandLineArgs.
| | 09:29 | After that you can once again pass in
argument values and you will be able
| | 09:37 | to see the arguments displayed in
the application as it starts up.
| | Collapse this transcript |
| Opening files with AIR| 00:00 | In this video I'm going to describe how to use the
Invoke event that's dispatched whenever you start
| | 00:04 | up an AIR application, to capture
information from the command line
| | 00:08 | and determine what file you want to
open as the application starts up.
| | 00:12 | For this demonstration, I'll use an application named
OpeningFiles.mxml from the Chapter11BeginProject.
| | 00:19 | If you are following along with
the exercises, open the file now.
| | 00:23 | In this application, there is an Invoke event listener
already created in the WindowedApplication tag
| | 00:28 | and an event listener function named
invokeHandler that handles the event.
| | 00:33 | In some applications you want the user to be able to start
the application from the command line and pass in the name
| | 00:38 | of a file that they want to open immediately upon start up.
| | 00:42 | As I showed you in the previous video, the InvokeEvent
object contains information about both the arguments
| | 00:48 | and the current directories that the user is starting from.
| | 00:52 | You can use these two values in combination to figure out
what file the user wants to open and then use the File
| | 00:58 | and FileStream classes to open and read
the file into the application's memory.
| | 01:03 | Place the cursor into the invokeHandler
function, the first question you need
| | 01:07 | to ask is whether any arguments were passed in at all.
| | 01:10 | So, put in an if conditional clause that asks this question,
if (event.arguments.length) is greater than or equal to 1.
| | 01:19 | If the user hasn't passed any arguments in,
then you won't be able to open any files.
| | 01:25 | Now assuming that they have passed in at least one argument,
we're going to assume that the first argument they pass
| | 01:30 | in is the name and location of a file relative
to the current directory from which they started.
| | 01:36 | Declare a variable link filename, data typed as a String
and get it's value from event.arguments (0) as String.
| | 01:48 | So, we're taking this value as a string
and saving it into the variable filename.
| | 01:52 | Next create a File object, I'll name my File object
simply f and again data typed as a File and get the path
| | 02:00 | of this file object using the event object's
current directory property as follows,
| | 02:06 | event.currentDirectory.resolvePath and
then pass in the filename variable.
| | 02:13 | Since the user will reference the file relative to
their current directory from which they are starting up,
| | 02:18 | this should give you the accurate location
of the file they are asking you to open.
| | 02:23 | Now ask whether the file actually
exists, put in a conditional clause
| | 02:27 | and use this expression, f.exists and then a pair of braces.
| | 02:32 | If the file exists, you'll now open it and you are going
to assume that it's a next file for this demonstration
| | 02:39 | but of course in any particular application you'll read
the file according to whatever format you're expecting.
| | 02:45 | To read the contents of the file into memory, declare
a variable named fs data typed as a FileStream object
| | 02:52 | and instantiate it using the FileStream
class's no arguments constructor.
| | 02:58 | Now call the FileStream object's open method and
pass in the File object and a FileMode of Read.
| | 03:07 | Next create a variable named str data typed as a String,
| | 03:10 | get it's value from the readUTFBytes
function of the FileStream object like this.
| | 03:17 | Call the readUTFBytes function and then
pass in the number of bytes that you want
| | 03:21 | to read using the expression fs.bytesAvailable.
| | 03:26 | Now close the FileStream by calling the close method and
then output the string value that you read from the file
| | 03:32 | like this, out which is the id of the textarea
control at the bottom of the application out.text=str.
| | 03:41 | So, that's the basic code.
| | 03:42 | You check to see whether you have got the argument you
were expecting, if so you create a File object pointing
| | 03:48 | to the file that the user asked you to open.
| | 03:50 | You check to make sure the file exists and then you create
a FileStream object and use that along with the file object
| | 03:57 | to open the file and read it's contents into memory.
| | 03:59 | Now if the user types in the name of the file that
doesn't exist, you want to get them some feedback.
| | 04:04 | So, put in an else clause that's a part of the
nested if condition and in there use an Alert object,
| | 04:11 | double make sure that Flex Builder adds an import
statement for the Alert class, then call the show() method
| | 04:17 | and then use this code, "File" + f.name +
"not found" and then pass in a title of Error.
| | 04:28 | Save your changes and try running the application.
| | 04:31 | Now when you run the application from Flex
Builder, you aren't passing in any arguments,
| | 04:35 | so you won't see any feedback from the application.
| | 04:38 | To see the feedback from the application, do this.
| | 04:41 | Export the application as a Release Build.
| | 04:44 | From the Menu select File, Export, Release Build, Select
the OpeningFiles.mxml application and set the file
| | 04:53 | that you are exporting as OpeningFiles.air.
| | 04:56 | Click through to the digital signature screen and fill in
any information you need for your self sign certificate
| | 05:02 | and then click finish to package the application.
| | 05:05 | You should now have a file named
OpeningFiles.air, in your Flex Navigator View.
| | 05:10 | Open the AIR file, you can do so by double clicking
and then install the application to your system.
| | 05:17 | As the application starts up once again, no command line
arguments are being passed in, so you won't see any result.
| | 05:23 | Close the application and then go to a Command window.
| | 05:27 | Switch to the application directory, on
windows this will be ProgramsOpeningFiles.
| | 05:34 | Now on Windows, you'll notice that there is an
assets folder with two files, one named ATextfile.txt
| | 05:42 | and the other named My.customAIRFileType.
| | 05:45 | So, now try opening the application
like this, OpeningFiles.exe
| | 05:49 | and again the syntax will be different
on the Mac and then assetsATextFile.txt.
| | 05:56 | Working on Windows make sure you use a
backslash between asset and ATextFile.txt.
| | 06:02 | Run the application and you will see that
the content of the text file is opened
| | 06:07 | and displayed in the application upon startup.
| | 06:09 | Now again if you are working on Mac OS X, the
installation architecture is somewhat different.
| | 06:14 | Everything is packaged within an application package.
| | 06:17 | So to see this behavior, you might want to instead
copy the contents of the assets folder over to an area
| | 06:23 | of your Mac disk, then go to terminal and
run the application from the command line,
| | 06:28 | opening files directly from the disk and not going
through the application package to get to the text files.
| | 06:33 | Regardless as long as you pass in a correct file name, you
should see that the content is displayed in the application.
| | 06:40 | Now watch what happens if you pass
in a non existent file name.
| | 06:44 | I'll try the same application again, but I'll
change the name of the file to NoSuchFile.txt
| | 06:51 | and as the application starts up, it displays
the text file, File NoSuchFile.txt not found.
| | 06:57 | So the application is correctly determining whether the
file that's been requested exists or not and if it exists,
| | 07:03 | it's opening it and reading it into memory and if it
doesn't exist it's reporting the error to the user.
| | Collapse this transcript |
| Using custom file types| 00:00 | In this video, I'm going to describe how to create your own
custom file types and associate them with your application,
| | 00:06 | so that, when the user clicks on a file, whose
file extension is associated with your application,
| | 00:12 | it results in opening the application
directly and loading the file.
| | 00:16 | The code for this application will be
exactly the same as in the previous example.
| | 00:20 | I will be using an application named CustomFileTypes.mxml.
| | 00:24 | If you're following along with the
exercises, you can open this file now
| | 00:28 | and you will see that once again it uses an invoke event.
| | 00:31 | It calls the invoke handler method and then checks
for the file that's provided in the arguments.
| | 00:36 | It then opens the file for reading with the file
stream object and displays its contents on the screen.
| | 00:42 | You associate Air applications with custom file
tapes through the application descriptor file.
| | 00:47 | Open the file CustomFileTypes-app.xml.
| | 00:53 | Scroll down to the bottom of the file
and locate the section labeled fileTypes.
| | 00:58 | In a default application descriptive file,
all of this content is commented out.
| | 01:05 | In order to set up custom file types, remove
the comments from the following elements.
| | 01:10 | First, locate the start and end file types
element and remove the comment tokens from there.
| | 01:16 | Go to the start tag first and remove
the comments from around that tag.
| | 01:24 | Then, go to the matching end tag and do the same.
| | 01:28 | Also, remove the comments from around the fileType element.
| | 01:34 | Once again, you'll find comment tokens around
both, the beginning and the ending tag.
| | 01:43 | Now, for each file type that you define,
there are a couple of required elements
| | 01:46 | and then some optional elements that you can also use.
| | 01:49 | We will be working with a custom file type
with a file extension of customAirFileType.
| | 01:55 | There's an example of this type of file in the assets folder
and if you open this file up with a simple text editor,
| | 02:01 | you'll see that it's really just
a text file with some basic text.
| | 02:05 | Go back to the application descriptor.
| | 02:12 | Remove the comments from around the name element.
| | 02:15 | The name of the file type can be anything
you want, but it's commonly in dot format.
| | 02:20 | So, I'll use this syntax; Custom.Air.File.Type.
| | 02:27 | Now, put in the extension that you want to register.
| | 02:31 | On both, Windows and Mac OS X, any file
with this file extension, when opened,
| | 02:36 | will result in opening the application itself.
| | 02:39 | Notice, we're using the file extension CustomAirFileType.
| | 02:43 | So, put in that extension between the extension
tags and don't include a dot character.
| | 02:48 | Those are all the required settings.
| | 02:50 | You don't need a description and you don't need a MIME type,
if you're just going to be opening files from the desktop.
| | 02:56 | Save your changes and now, create a release build.
| | 02:59 | From the Menu, select File, Export, Release Build.
| | 03:04 | Select the application, CustomFileTypes.mxml
and export to a file named CustomFileTypes.air.
| | 03:12 | If you need to set up your digital
security certificate, do so and then,
| | 03:17 | export the Release Build by clicking the Finish button.
| | 03:21 | Next, install the application to the operating system.
| | 03:25 | You should now have a file called CustomFileTypes.air.
| | 03:28 | Open that file from the Flex Navigator view.
| | 03:31 | You can do this by double clicking on it.
| | 03:33 | Click the Install button and click
Continue and as the application starts up,
| | 03:38 | you'll see that the Output region is blank,
because we started it up without any arguments.
| | 03:44 | Close the application and return to the Flex navigator view.
| | 03:47 | Now, whenever you select a file that has the appropriate
file extension such as the file My.customAIRFileType,
| | 03:55 | and open that file say by double clicking it,
| | 03:57 | it's the same thing as opening the application
and passing in a command line argument.
| | 04:02 | So, I'll locate the file My.customAIRFileType
and I will open it by double clicking.
| | 04:07 | Now, it may open in Flex Builder as you see here, but
to open it with the application, right click on the file
| | 04:13 | or Control click on the Mac and
select Open with System Editor.
| | 04:19 | That should result in opening the installed application and
opening the file and displaying its contents in the screen.
| | 04:25 | So, that's how we set up custom file types
that are associated with their applications.
| | 04:30 | The work is all done in the application descriptor file.
| | 04:33 | This association can only be tested once the application
has actually been installed on your operating system.
| | 04:39 | You have a required name and a required extension and
then, other optional values such as, the description,
| | 04:45 | the MIME type and if you want, you can also associate
graphical icons with these file types, so that,
| | 04:51 | the files are displayed on the operating system
and displayed with these graphic icons associated.
| | Collapse this transcript |
|
|
12. Updating an AIR ApplicationSetting application version numbers| 00:00 | In this chapter of the video series, I'm going to
describe how to manage automatic updates for applications
| | 00:06 | that are already installed on your system.
| | 00:07 | When you build software applications and then want
| | 00:10 | to upgrade the applications, there
are a number of steps involved.
| | 00:13 | First of all, in the application descriptor
file, you control the version number.
| | 00:17 | Then, at run time, you have to download the application
installer from the website; then, compare the new version
| | 00:23 | to the old version that's running on the system,
and then finally, automatically do the update.
| | 00:27 | Throughout the demonstrations in this chapter, I will be
using a Flex project, that's a part of the Exercises area.
| | 00:33 | If you are following along with the Exercises,
| | 00:35 | you can import this project using the Flex Builder
Menu selection; File, Import, Flex Project.
| | 00:43 | Click the Browse button next to archive file,
navigate to the chapter12 folder of the Exercises area
| | 00:49 | and select the Flex Project archive
file chapter12BeginProject.zip.
| | 00:55 | Import the file, then, go to the Flex Navigator view
and open the project and then open the source folder.
| | 01:02 | You'll find that there's one very simple
application named MyAIRApplication.mxml.
| | 01:09 | Open the application and take a look at the code.
| | 01:13 | There's an import for the Alert class, three empty functions
named downloadUpdater, completeHandler and closeHandler.
| | 01:20 | The two event handler functions use event
objects, a label and a button control
| | 01:26 | and the button control's click event
calls the downloadUpdater method.
| | 01:30 | Next, open up the application descriptor file.
| | 01:35 | MyAIRApplication-app.xml.
| | 01:38 | This is a standard default Air Application
descriptor file with one minor change.
| | 01:43 | The application version which is at line 27
has its version number set to a value of 1.0.
| | 01:50 | I'm using a pure numeric value for the version numbers,
because this will help me demonstrate later on,
| | 01:55 | how you compare version numbers from
an old version to a new version.
| | 01:59 | Finally, go back to the application and run it and
you'll see that it displays a very simple background
| | 02:05 | with a label and the button labeled Download updater.
| | 02:09 | Close the application and now I'm going
to package the Application Installer.
| | 02:13 | From the Flex Builder Menu, select
File, Export, Release Build.
| | 02:20 | Select the application MyAIRApplication.mxml from
the chapter12Begin Project and change the name
| | 02:26 | of the default air file from MyAIRApplication
to MyAIRApplicationV1.air.
| | 02:33 | This will help us distinguish between the version1 installer
and the version 2 installer, which we haven't created yet.
| | 02:40 | Click through the rest of the screens.
| | 02:42 | If you need to set up a digital certificate, you
can do it from this Digital Signature screen.
| | 02:47 | I'll accept my existing certificate and then
click Finish to package the application.
| | 02:53 | In your Flex Navigator view, you should now have
an installer package; MyAIRApplicationV1.air.
| | 02:59 | Double click it to run it and then install the application,
| | 03:03 | following all of the prompts and
accepting all of the defaults.
| | 03:07 | After the application has been
installed, it should open on your screen.
| | 03:11 | Close the application and then
return to the application code.
| | 03:16 | Now, we're going to create a version2 of the application.
| | 03:21 | Save this file with a new name.
| | 03:23 | File, Save As, and name this MyAIRApplicationV2.mxml.
| | 03:30 | Make a couple of changes to the
visual output of the application.
| | 03:35 | Change the background color from aqua to red.
| | 03:39 | Go down to the label component and
change its version number to Version 2.0.
| | 03:44 | Save those changes.
| | 03:46 | Now, go back to MyAIRApplication-app.xml.
| | 03:50 | Open that and save that as MyAIRApplicationV2-app.xml.
| | 03:57 | The one thing you won't change here, is the identifier.
| | 04:00 | In order to do an automatic update, the two
versions of the application must have the same ID.
| | 04:06 | So, even this one is named MyAIRApplicationV2.mxml,
we leave the ID alone.
| | 04:15 | But, we will change the version
number, from version1 to version2.
| | 04:20 | Save the changes to the application descriptor.
| | 04:23 | Then, go back to the application
MyAIRApplicationV2.mxml and run the application.
| | 04:30 | When this version of the application opens on the
screen, you will see that it now has a red background,
| | 04:36 | so we can identify it easily and a label of version2.
| | 04:41 | Close the application, and now, package the application.
| | 04:46 | Select File, Export, Release Build.
| | 04:52 | Select MyAIRApplicationV2.mxml and change the
export file name to MyAIRApplicationV2.air.
| | 05:02 | Click through the rest of the screens,
selecting the digital certificate
| | 05:06 | and including the required files and then click Finish.
| | 05:10 | See, you now should have two copies of the application;
MyAIRApplicationV1.air and MyAIRapplicationV2.air.
| | 05:18 | They are both using the same application ID, so, if I
tried to run the air application for version2 right now,
| | 05:24 | the air installer will detect that the version numbers have
changed from version 1, the installed version to version 2.
| | 05:31 | Now, you could replace the existing application this way,
but we're more interested in this chapter in seeing how
| | 05:37 | to handle this update automatically, using
ActionScript code to download the new installer
| | 05:42 | and then inspect the version numbers and
finally, automatically do the update.
| | 05:47 | So, cancel this installation process and in the next
video, I will show you how to take the version 2 air file,
| | 05:53 | copy it to your website and then,
how to download the air file,
| | 05:57 | using ActionScript code in your version 1 application.
| | Collapse this transcript |
| Retrieving an installation package from a website| 00:00 | Before you can automatically update an AIR application,
you have to download the installer file from a website.
| | 00:06 | You can't run the installer directly from
the web, instead it has to be stored locally.
| | 00:10 | So in this video I'm going to show you how to
set up your installer on the website and then how
| | 00:15 | to write the ActionScript code to
download it and save it to the local disk.
| | 00:18 | Then in later videos, I will show you how to compare the
version numbers between the currently installed version
| | 00:23 | and the installer that you just downloaded
and then how to execute the update.
| | 00:28 | First of all, in this chapter, unlike many of the others,
you can't really step into each exercise individually,
| | 00:34 | you have to go through the whole
chapter one video at a time.
| | 00:36 | So if you didn't go through video number one in this
chapter, go back and run through those exercises first,
| | 00:42 | so that you have two AIR installers,
MyAIRApplicationV1.air and MyAIRApplicationV2.air.
| | 00:49 | You should have installed version 1 on your system already.
| | 00:52 | Now the next step you are going to follow is copying
the version 2 AIR file to a location on a website.
| | 00:58 | For this purpose I will be using WAMP, the
Windows-based application server bundle,
| | 01:03 | that includes Apache, MySQL, and PHP.
| | 01:06 | If you are working on Mac OS X, you can use MAMP instead.
| | 01:10 | Copy the AIR installer for version 2 to your clipboard.
| | 01:14 | Right click on the installer, MyAIRApplicationV2.air,
or Ctrl+click with the Mac, and select Copy.
| | 01:21 | Now, navigate to a folder under your web server root.
| | 01:25 | I will be using this folder, c:wampwww, that's the document
root if you are using WAMP with its default installation,
| | 01:37 | and under there I will go to the AIRFlex folder
that was installed earlier in this video series.
| | 01:42 | Now, I will paste the file into that folder.
| | 01:45 | If you are working with MAMP on Mac OS X, the document
root under MAMP is the, Applications/MAMP/htdocs folder.
| | 01:55 | You can also go to the AIRFlex folder
under there if you placed it there,
| | 01:59 | and then copy your AIR installer into that location.
| | 02:02 | Now your version 2 installer is ready to download.
| | 02:06 | Close whatever windows explore or find a windows
who might have open and return to Flex Builder
| | 02:11 | and then open the application file, MyAIRApplication.mxml.
| | 02:15 | This is the version 1 application we are working in.
| | 02:18 | The first step in downloading the installer
from a website is to declare a few variables.
| | 02:23 | First declare a variable named
urlString, datatyped as a String.
| | 02:29 | This will be the location of the
AIR installer as an absolute URL.
| | 02:33 | Put in this URL,
http://localhost/AIRFlex/MyAIRApplicationV2.air.
| | 02:43 | Next declare a variable datatyped as a URL request.
| | 02:51 | I will name it urlReq, datatyped as URLRequest
| | 02:56 | and instantiate this object using the URLRequest class's
constructor method and wrap it around the urlString.
| | 03:07 | You now have a URLRequest object that points to
the location of the your version 2 installer.
| | 03:12 | Next declare a variable named urlStream,
datatyped as the URLStream class.
| | 03:21 | This class is able to download binary files
from a website and then save them to local data.
| | 03:26 | Instantiate this object using the URLStream
class's no arguments constructor method.
| | 03:33 | When the URLStream class downloads the
binary file, it will be saved as a ByteArray.
| | 03:38 | Declare a variable named fileData, datatyped as a ByteArray
| | 03:42 | and then instantiate it using the ByteArray
class's no arguments constructor method.
| | 03:49 | So those were all the variables we need.
| | 03:52 | The urlString described in the location as a
String, the URLRequest wrapped around the urlString.
| | 03:57 | The URLStream which is going to do
the downloading and the ByteArray
| | 04:01 | which will receive the binary file and store it in memory.
| | 04:04 | Now go to the downloadUpdater function.
| | 04:07 | Add the following code, that first set up
an event listener for a complete effect.
| | 04:12 | When the download is complete you will
get this event and be able to react.
| | 04:17 | Call this code, urlStream.addEventListener,
listen for the Event.COMPLETE event,
| | 04:26 | and then call the completeHandler
method when the event occurs.
| | 04:29 | Now you are ready to download the file using this code,
urlStream.load, and pass in the URLRequest object urlReq.
| | 04:41 | This download will happen asynchronously and when the
download is complete, the complete event will be dispatched
| | 04:47 | and you will be ready handle and save the file to disk.
| | 04:51 | Place the cursor inside the completeHandler function.
| | 04:56 | The first task is to take the results
of the URLStream class's load method
| | 05:00 | and save the results to the predeclared ByteArray.
| | 05:03 | I will use this code, urlStream.readBytes
and then I will pass in the following values.
| | 05:12 | First the ByteArray that I want to write to, fileData, then
at beginning position, zero, and then the number of bytes
| | 05:20 | that I want to download, urlStream.bytesAvailable.
| | 05:31 | Now I will take the ByteArray and
write its contents to a file.
| | 05:36 | First I will create a file variable named f, datatyped as a
File, and I will indicate where I want to write the file to.
| | 05:43 | I'm going to put it on my desktop
directory, so I can see it easily.
| | 05:47 | I will call the desktopDirectory file's
resolvePath property and pass in the name
| | 05:52 | of the file I want to create, MyAIRApplicationV2.air.
| | 06:00 | Now I will create a FileStream.
| | 06:02 | I will name it, fs, datatyped as a FileStream object
| | 06:06 | and I will instantiate it using the
class's no arguments constructor method.
| | 06:13 | Next I will add an event listener.
| | 06:15 | I'm going to be opening this file asynchronously,
| | 06:17 | so I want to be able to react whenever the
file is being downloaded to the desktop.
| | 06:21 | So I will call it fs.addEventListener
and I will listen for a CLOSE event
| | 06:26 | and whenever the FileStream has been closed,
I will call a method named closeHandler.
| | 06:32 | Now I will open the file that I want to write to, using
this code, fs.openAsync, I will pass in the file object,
| | 06:41 | simply named f here, and then use
the constant FileMode.WRITE,
| | 06:47 | to indicate that I want to write to this new file.
| | 06:50 | Now I'll call the FileStream's writeBytes method.
| | 06:54 | I will pass in the source ByteArray named fileData, a
beginning offset of zero, and then the number of bytes
| | 07:02 | that are in the ByteArray using the syntax, fileData.length.
| | 07:10 | When the write operation is done, I will
close the FileStream like this, fs.close().
| | 07:17 | So that's the code you need for taking the binary
content that's been downloaded using the URLStream,
| | 07:23 | first reading it into a ByteArray and
then from there, writing it to disk.
| | 07:28 | Finally, go to the closeHandler method and add a bit of code
to let the user know that the file has been written to disk.
| | 07:36 | I will call this method Alert.show,
and I will pass in two literal strings,
| | 07:41 | "The AIR file has been saved locally",
and then a title of "Download complete".
| | 07:49 | I will save the changes and run the application,
and make sure that you are running WAMP or MAMP.
| | 07:56 | In this case, I'm looking at my system
tray in the lower right hand corner
| | 08:00 | and seeing that the WAMP server is ready to use.
| | 08:03 | I will make sure that it's online and ready
and you can tell from the system tray indicator
| | 08:08 | by the little needle that's all the way over to the right.
| | 08:10 | Then I will go back to the application
and click the Download Updater button,
| | 08:15 | and after a moment I get the message
that the AIR file has been saved locally.
| | 08:19 | I will close the application and take a look at the
desktop and you will see that the application installer,
| | 08:26 | MyAIRApplicationV2, has been saved
successfully to the desktop.
| | 08:30 | Now in the next video, I will show you how to
compare the version number in this installer
| | 08:34 | to the version that's already installed and
then decide intelligently whether you want
| | 08:39 | to follow through and do an update.
| | Collapse this transcript |
| Comparing application version numbers| 00:00 | In this video, I'm going to describe
how to detect the current version number
| | 00:04 | of the application that's already installed on your system.
| | 00:07 | Before you execute an automatic update you always want
to compare the currentVersion number of the application
| | 00:12 | to the version number you are expecting to install.
| | 00:15 | It's important to note that the application must already
know the version number of the target application installer
| | 00:21 | and then it can detect its own version number
that is the currentVersion number dynamically.
| | 00:25 | For this demonstration I will use the application
CompareVersions.mxml that you will find
| | 00:30 | in the Chapter12BeginFolder if you are
following along with the Exercises.
| | 00:36 | This is the same application that I created in the previous
video, but it now has a new function named compareVersions
| | 00:42 | and a button with a label of compareVersions
that calls that function.
| | 00:45 | Here are the steps for comparing the version
of the currently running application.
| | 00:49 | Click into the CompareVersions
function and then put in this code
| | 00:53 | to clear a variable named descriptor,
datatyped as an XML object.
| | 00:59 | Remember that the application descriptor is an XML file and
you can read this into memory using the following syntax;
| | 01:06 | NativeApplication.nativeApplication.applicationDescriptor.
| | 01:14 | This expression returns the actual XML object
that is the application descriptor file.
| | 01:20 | Now in order to read the application
descriptor you need a namespace,
| | 01:24 | you get this namespace using the syntax
var ns:Namespace=Descriptor.namespce.
| | 01:34 | The namespace function can handle a namespace prefix,
but if you look back at an application descriptor file,
| | 01:44 | what you see is that it does include a namespace in the
application tag, but it doesn't use a namespace prefix,
| | 01:50 | so this is what's called in XML the default
namespace and this is what we are referring to,
| | 01:56 | when we declare the namespace object using this code.
| | 01:59 | Now to clear a variable named current version
datatyped as a number and you will extract the version
| | 02:07 | from the XML file and then cast it as a number.
| | 02:10 | I can do it in this case because the version numbering that
I'm using are purely numeric values 1.0, 2.0 and so on.
| | 02:18 | So extract the value like this, start off with
a casting expression of number parenthesis,
| | 02:26 | then an E4X expression of descriptor.ns::version.
| | 02:30 | The colon, colon is namespace syntax in E4X,
we are saying start with the default namespace
| | 02:40 | and then get the version element and its text note,
return that value and cast it as a numeric value.
| | 02:47 | Finally set a variable named newVersion, once again
type as a number and set it to a literal value of two.
| | 02:55 | Now in this case I'm setting the application
version number right here in the code,
| | 02:59 | but you could just as easily download an
XML file for instance from the website
| | 03:03 | to determine what version number you are looking for.
| | 03:07 | Now you can compare the two versions, first of all put
in a trace command and output this value currentVersion
| | 03:15 | and then the currentVersion variable,
then put in a conditional clause.
| | 03:24 | If currentVersion is less than newVersion then I will put
a trace statement like this trace eligible for upgrade.
| | 03:34 | In the else clause add another trace
statement not eligible for upgrade.
| | 03:47 | Save your changes and run the application in debug mode,
click the compareVersion button and watch the console
| | 03:57 | in Flex Builder and you should see that the currentVersion
is reported as version 1 and the message is eligible
| | 04:02 | for upgrade because the currentVersion version
1 is less than the newVersion version 2.
| | 04:08 | In the next video I will show you how to complete
this process and execute the automatic upgrade.
| | Collapse this transcript |
| Performing an application update| 00:00 | In this video, I'm going to describe
how automatically Update the application
| | 00:04 | after you have already downloaded the
application installer to your local disc.
| | 00:08 | You can only perform an automatic update using an
installer that's stored on the local file system,
| | 00:13 | that's why we had to download it first and it's strongly
recommended that you only do this automatic update
| | 00:18 | after you have checked your version numbers and I
showed you how to do that in the previous video.
| | 00:22 | For this demonstration I will use an
application named ExecuteUpdate.mxml,
| | 00:27 | this is very similar to the application that I used earlier.
| | 00:30 | It has all the code to download the application from
the website and then the code to compare the version
| | 00:35 | of the currently running application
against the version that we want to install.
| | 00:39 | If we go back to the application descriptor for
this application you will see that this version
| | 00:45 | of the application is still on Version 1.0.
| | 00:48 | So here are the steps, I'm going add code to do the update
that I'm going to install this version of the application,
| | 00:55 | you can only execute an automatic update
using an application that's already installed
| | 00:59 | in the local operating system.
| | 01:00 | Then at runtime I will execute the
update first checking the version number.
| | 01:06 | Let's go back to the code.
| | 01:08 | Codes of the compareVersion's method that currently is
returning void, change its return data type from Void
| | 01:14 | to Boolean, then go to the, if then clause, that's
comparing the currentVersion to the desired newVersion.
| | 01:20 | If the currentVersion is less than the newVersion
return true, and otherwise return false.
| | 01:30 | Now we have a function that we can use to
determine dynamically whether we are eligible
| | 01:35 | for an update, go to the do upgrade method.
| | 01:38 | This method was added to this version
of the application already
| | 01:41 | and is being called upon a click
event of the button labeled doUpgrade.
| | 01:45 | Here are the steps, create a variable
named updater datatyped as updater class
| | 01:51 | and instantiate the object using the
updater class' no arguments constructor.
| | 01:56 | The next step is to create a file object, declare a new
variable named installer file datatyped as a file object
| | 02:05 | and get its location using the same syntax as we used before
when we set the location of the file that was downloaded
| | 02:11 | to the disc File.desktopDirectory.resolvePath then pass
in the name of the installer file MyAIRApplicationV2.air.
| | 02:25 | Finally do the upgrade.
| | 02:28 | Call the updater object update method, you will pass in
two arguments, the first is the file object that point
| | 02:36 | to the AIR file that you have saved
locally, I named it installer file.
| | 02:39 | The second is the literal value of the new version 2.0.
| | 02:44 | Now this value must match exactly, the version number as
described in the application installer's descriptor file
| | 02:51 | and you may remember back in the earlier
video when we created the version 2 installer,
| | 02:56 | that this is the version number that we put in 2.0.
| | 02:59 | Now wrap all these code in an if clause, you only want to
call this code if in fact you are eligible for the upgrade.
| | 03:07 | See you will call the compareVersion function
and wrap all of this code into the if clause,
| | 03:15 | so that you will only be doing the update,
if in fact you are eligible for it.
| | 03:20 | Then add an else clause and use the alert class.
| | 03:24 | Always selecting the Alert class from a list of classes to
make sure that you put in the required import statement,
| | 03:30 | then call the show method and pass in some error messages.
| | 03:35 | Application can't be upgraded and error.
| | 03:41 | Now you are ready to package and install the application.
| | 03:44 | You can't run the updating functionality from
an application that's running in debug mode,
| | 03:49 | it has to already be installed on the operating system.
| | 03:52 | So now use the Export feature to Export or Release Build.
| | 03:57 | From the Menu select file, Export, Release Build,
select ExecuteUpdate.mxml as the application
| | 04:06 | and then change your export to file value to
MyAIRApplicationV1.air, click through the screens to export
| | 04:14 | to Release Build providing a digital certificate
where necessary and then when you say that you want
| | 04:20 | to finish the export, you will be prompted
to overwrite the existing AIR file.
| | 04:25 | Click yes, then go back to the Flex navigator view
and double click to open MyAIRApplicationV1.air.
| | 04:35 | Notice that it shows you that you haven an installed
version of 1.0 and a version to be installed of 1.0.
| | 04:42 | Click the replace button and this will ensure that the
latest version of the application has been installed.
| | 04:48 | You will know for sure that you have the right
version because you will see the doUpgrade button
| | 04:53 | and if you don't see the button then you will
notice that you might have missed a step.
| | 04:56 | Now we will execute the upgrade.
| | 04:58 | Click the do upgrade button, you will see
that the application closes and then reopens
| | 05:04 | with its new look, showing that it's now in version 2.0.
| | 05:07 | So those were all the steps for managing
automatic updates to AIR applications.
| | 05:12 | Once again the old version of the application must know the
version number of the application it wants to update to.
| | 05:18 | You can provide that information either hard coded
in the application as I did in this demonstration
| | 05:23 | or you could perhaps post an XML file that the
application could download and inspect at runtime to find
| | 05:30 | out what version is available then to actually execute the
updating, you download the AIR application to the local disc
| | 05:36 | and then use the updater class to perform the update.
| | Collapse this transcript |
|
|
13. Advanced TechniquesClosing an application gracefully| 00:01 | In this chapter of the video series I'm going
to describe a couple of advanced techniques,
| | 00:05 | that allow you to control how applications
close and how they communicate with each other.
| | 00:10 | For these demonstrations I'll use a
Flex Project from the Exercises area.
| | 00:13 | If you're following along with the
Exercises, you can import this project.
| | 00:18 | Select File, Import, Flex Project, click the Browse button
next to Archive file, navigate to the Chapter13 folder
| | 00:27 | under the Exercises area, and select
Chapter13BeginProject.zip.
| | 00:33 | Import the project, then go to the Flex
Navigator view, go the source folder,
| | 00:39 | and open the application, ClosingApplication.mxml.
| | 00:43 | This application uses a Native Window as a pop-up window.
| | 00:46 | It has a common issue.
| | 00:48 | When you run the application and then click the Open
Window button, that creates a Native Window component.
| | 00:53 | If you then go back to the main application window and
close that, then native window is left open on its own,
| | 00:59 | and the application doesn't completely exit until
the user closes down the native window pop-up.
| | 01:05 | To handle this issue, I'll show you how
to listen for an event named Closing.
| | 01:09 | This event is dispatched as a native window is closing down.
| | 01:12 | It's dispatched on the application window
and also on any other pop-up windows.
| | 01:16 | It's particularly used for an application window
to detect when the application is shutting down,
| | 01:22 | to allow you to handle synchronous operation,
such as closing any other native windows.
| | 01:27 | Let's take a look at the existing code.
| | 01:29 | In the openWindow () method, there is a call to
initialize the win variable and then open it on the screen.
| | 01:35 | The closeWindow () function first calls the window's
close () method and then sets the win object
| | 01:40 | to null to release it for garbage collection.
| | 01:42 | So, when the application is shutting down, if you
would like to make sure that the native windows shut
| | 01:47 | down at the same time, you'll handle two steps.
| | 01:50 | Step number one will be to listen for the closing
event, and when it happens, you'll then explicitly close
| | 01:56 | that other native window, and then handle any
other tasks that your application might need to do,
| | 02:01 | before everything is completely shut down.
| | 02:04 | Go to the windowed application tag, and add a closing event
listener, then call a method called closingHandler ().
| | 02:12 | We'll have to create that method, it doesn't already exist.
| | 02:15 | So then go down to the Script section and add a
new private function, named closingHandler ().
| | 02:26 | Within the closingHandler () method, check
first to see if the win variable is null.
| | 02:32 | If (win != null), and then within the
conditional block, call win.close ().
| | 02:41 | This ensures that the native window pop-up
is closed down, if in fact it's open,
| | 02:46 | before you close down the rest of the application.
| | 02:49 | I'll save the changes and run the application.
| | 02:54 | I'll open the window and you'll see
the My Native Window pop-up up here.
| | 02:58 | Then I'll go back to the application window and close
down the application by clicking the close icon,
| | 03:04 | and you'll see that both the application and
the pop-up window are closed simultaneously.
| | 03:09 | You can also check to make sure
you can still run the application,
| | 03:12 | which would mean that the application
is closed down completely.
| | 03:15 | If in fact there were any invisible
window still left in the environment,
| | 03:19 | you wouldn't be able to restart
the application from Flex Builder.
| | 03:22 | Once again I'll open the pop-up
window and then once again I'll close.
| | 03:28 | It's also possible to explicitly close the
application using a command called exit,
| | 03:33 | that's a member of the Native Window
class, here's how you do it.
| | 03:36 | Create a new private function, named
exitApp (), return void from the function.
| | 03:46 | Within the function use this syntax,
NativeApplication.NativeApplication.exit ().
| | 03:54 | Call the exit method without any arguments.
| | 03:58 | Then go down to the button that
has a label of Exit Application,
| | 04:01 | listen for a click event and call the exitApp () function.
| | 04:04 | Save the changes and run the application.
| | 04:08 | After the application opens up, you should now be able
| | 04:12 | to click the Exit Application button
and the application will close.
| | 04:15 | This will also work if you open the
pop-up window first and then go back
| | 04:20 | to the application and close it programmatically.
| | 04:23 | Notice that both the application window and the
pop-up native window are closed at the same time.
| | 04:28 | This is because the closing event is dispatched,
no matter how the application starts to close,
| | 04:33 | and it doesn't matter whether it happens as a result of a
user gesture such as a mouse click or a keyboard shortcut
| | 04:39 | or whether you're closing the application
explicitly by calling the exit method.
| | Collapse this transcript |
| Communicating between AIR applications | 00:01 | In this video I'm going to describe how to use a class name
to the local connection that allows you to send messages
| | 00:06 | between AIR applications running on the same local system.
| | 00:10 | For this demonstration I'll use two AIR
applications named CommunicationSource,
| | 00:14 | and CommunicationTarget, both in the Chapter13BeginProject.
| | 00:18 | If you're following along in the Exercises,
you can open both of these applications now.
| | 00:23 | I'll start off in the source application.
| | 00:25 | The source application also sometimes known as the sending
application, needs an instance of the LocalConnection class.
| | 00:32 | You typically declare this class outside of any functions,
so that you can address it from anywhere in the application.
| | 00:38 | Place the cursor above the existing
functions inside the Script section
| | 00:43 | and declare private variable named
sendingConn datatype as LocalConnection.
| | 00:49 | At the same time, instantiate the
variable using new and then call
| | 00:56 | to the LocalConnection class's
no arguments constructor method.
| | 00:59 | Now, go down to the sendData () method.
| | 01:01 | In this application, there are two text input
controls, with IDs of fnameInput and lnameInput.
| | 01:08 | When you call the sendData () method,
there is already line of code there
| | 01:11 | to concatenate these strings together into a single string.
| | 01:15 | Now, in order to send the data from the sending
application to the receiving application,
| | 01:19 | call the Connection object's send method.
| | 01:22 | Call sendingConn.send, and the first argument
you go and pass in is a connection name.
| | 01:29 | In order to communicate effectively between two AIR
applications, the connection name should always start
| | 01:34 | with an underscore character, and then
can have descriptive name after that.
| | 01:39 | I'll name it _myConnection.
| | 01:42 | The second argument that you pass in is the name of a public
method of the target application that you want to call.
| | 01:48 | In the communication target application there
is already a pubic method named displayData (),
| | 01:53 | that's expecting a single argument, the name as a String.
| | 01:56 | So that's the method that we'll call.
| | 01:58 | You pass in the method name again as a String.
| | 02:01 | Any other arguments that you pass in after that are
considered to be arguments of the receiving method.
| | 02:07 | So, for example, the third argument that you pass
| | 02:09 | into the send method will be the first
argument received in the remote method.
| | 02:13 | I'm going to pass in the value of fullName,
the variable that's already been created.
| | 02:18 | So that's all you in the sending application.
| | 02:21 | You instantiate the LocalConnection object, and then when
you want to send the message you call the send method,
| | 02:26 | you pass in a connection name, which is
always prefixed with an underscore character,
| | 02:30 | to indicate that you're communicating between applications
with different identifiers or different domains.
| | 02:36 | Then you pass in the name of the method you want to
call, and any other arguments that you want to pass.
| | 02:41 | Now, switch over to the target application.
| | 02:44 | As with the sending application, declare
a variable outside of any functions
| | 02:48 | and datatype it as a LocalConnection object.
| | 02:51 | I'll declare a variable named receivingConn, datatyped as
LocalConnection, and as I did in the other application,
| | 03:00 | I'll immediately initialize this object using the
LocalConnection class as no arguments constructor method.
| | 03:07 | Now in the init () method, which has already being called
upon the applicationComplete event of the application,
| | 03:13 | you're going to set up the connection
to listen for messages.
| | 03:16 | There are three properties to set.
| | 03:18 | The first property is named client, and it's a reference
| | 03:22 | to the Flash-based component that's
going to receive the message.
| | 03:25 | Set that value to, this, that is the application itself.
| | 03:29 | The next item is a call to a method named allowDomain.
| | 03:33 | For AIR application communication, you should always pass
in a value of a single asterisk, this is because in order
| | 03:39 | for AIR applications to communicate with
each other over the LocalConnection class,
| | 03:43 | you have to allow interdomain communications.
| | 03:46 | If you're working with Flex applications downloaded as
web applications, the rules are a little bit different.
| | 03:51 | Now, call you Connection object's connect method, and
pass in the name of the connection you're listening.
| | 03:57 | Once again I'll use receivingConn and now I'll call the
connect method and I'll pass in the name of the connection,
| | 04:03 | which as before, starts with an underscore
character, and then is any descriptive value.
| | 04:09 | The important thing here is that connection name in the
sending and receiving applications must match exactly.
| | 04:14 | Now, the sending application is saying
I want to call the displayData method
| | 04:18 | and the receiving application's
displayData method will receive the data.
| | 04:22 | And as you can see in the code, it outputs that String
to an object labeled, out, which is a text area control.
| | 04:29 | I'll save the changes to both applications
and then run both applications.
| | 04:34 | So that's it.
| | 04:35 | I've set the client property, I have called the
allowDomain method and passed in a wild card asterisk,
| | 04:40 | meaning anything to communicate with anything,
| | 04:43 | and then I've connected using the same connection
name as I said in the sending application.
| | 04:47 | I'll save the changes and I'll check my problems
area to make sure there are no programming errors.
| | 04:53 | I'll go back to the source application and run it.
| | 04:56 | Then I'll go to the target application and run it as well.
| | 04:59 | Then I'll arrange the applications on the
screen, so I can see both at the same time.
| | 05:04 | I'll type values into first name and last name, and click
the Send button, and in the target or receiving application,
| | 05:13 | you should see that the data is correctly received.
| | 05:16 | It's also possible to send more complex
data, using the LocalConnection class.
| | 05:21 | I'm going to make a couple of changes
to the code in both applications.
| | 05:25 | In the Source application I'm going
to modify the behavior so that instead
| | 05:29 | of sending the full name, I'll send a complex object.
| | 05:32 | I'll put in braces to indicate that I'm
creating a new ActionScript object on the fly,
| | 05:38 | and then I'll pass the two values individually.
| | 05:41 | The first item will be named firstname
and will come from fnameInput.text
| | 05:46 | and the second item will be called
lastname and will come from lnameInput.text.
| | 05:54 | I'll reformat the codes, we can see
it all on the screen at the same time.
| | 05:58 | So now instead of sending a simple String,
I'm now actually sending a complex object.
| | 06:03 | Now I'll go to the Target or receiving
application and re-factor that as well.
| | 06:08 | In the displayData function, I'll change the fullname's
datatype from a String to an Object, and then,
| | 06:15 | I'll set out.text to fullname.firstname,
plus a space, plus fullname.lastname.
| | 06:26 | I'll save the changes to both applications
and run them once again.
| | 06:30 | Once again I'll arrange the applications
on the screen so I can see them both.
| | 06:34 | I'll click into the Sending Data
application and type in a name,
| | 06:38 | click the Send Data button, and
you'll see that it's received again.
| | 06:43 | So you can send either simple values or complex
values, using the LocalConnection class.
| | 06:48 | There is one more subject to know about with
the LocalConnection class that's important.
| | 06:53 | Whenever you send information from the
connection class, you'll get a StatusEvent
| | 06:58 | and this event includes a level property that
will tell you whether a thing succeeded or not.
| | 07:03 | Go back to the sending application and place the cursor
above the call to the send method and add an event listener
| | 07:10 | to the sending connection object, and listen for the
StatusEvent represented by the constant StatusEvent.STATUS.
| | 07:18 | Then, call the existing statusHandler method
that's already been created in this application.
| | 07:24 | Now go down to the statusHandler method and put in the
following conditional code, if (event.level == "status")
| | 07:36 | and if that conditional evaluation
is true, add in a trace method
| | 07:40 | that outputs a message to the console that says, Success.
| | 07:46 | Add in else clause and make a call to the
trace method that outputs the string, Failure.
| | 07:52 | Now go back to the Target application and run it in
standard mode and then go back to the Source application
| | 07:59 | and run that application in debug mode,
so that we see the trace statements
| | 08:03 | from the Source application but not from the Target.
| | 08:06 | Now, click into the Source application and
type in a name, and click the Send Data button,
| | 08:14 | and you should see in addition to the data appearing
in the Target application, the trace output, Success.
| | 08:20 | Now, close the Target application,
and try sending the data again,
| | 08:25 | and this time you should see the trace message, Failure.
| | 08:28 | So the StatusEvent will let you find
out from within the sending application,
| | 08:33 | whether the receiving application was there, ready,
and whether it received the message successfully.
| | Collapse this transcript |
|
|
ConclusionGoodbye| 00:00 | Hi! David Gassner here again. Thanks for sitting with me through
this video series on building and deploying desktop applications
| | 00:06 | with Flex 3.0 and AIR.
| | 00:08 | In this series I showed how you can use your
existing Flex application development skills
| | 00:13 | to create native applications that
run equally well on Windows and the Mac.
| | 00:18 | I hope you found the answers to your questions
about working with the local file system,
| | 00:22 | creating and maintaining local databases, and other
powerful features of the Adobe Integrated Runtime.
| | 00:28 | lynda.com has other video series about
using these advanced features of AIR,
| | 00:32 | programming in Flash and Ajax. Whichever architecture and
development tools you select, happy desktop application programming!
| | Collapse this transcript |
|
|