You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pivot.apache.org by gb...@apache.org on 2009/10/09 17:53:54 UTC

svn commit: r823598 - /incubator/pivot/trunk/tutorials/www/background_tasks.html

Author: gbrown
Date: Fri Oct  9 15:53:54 2009
New Revision: 823598

URL: http://svn.apache.org/viewvc?rev=823598&view=rev
Log:
Add background task tutorial documentation.

Modified:
    incubator/pivot/trunk/tutorials/www/background_tasks.html

Modified: incubator/pivot/trunk/tutorials/www/background_tasks.html
URL: http://svn.apache.org/viewvc/incubator/pivot/trunk/tutorials/www/background_tasks.html?rev=823598&r1=823597&r2=823598&view=diff
==============================================================================
--- incubator/pivot/trunk/tutorials/www/background_tasks.html (original)
+++ incubator/pivot/trunk/tutorials/www/background_tasks.html Fri Oct  9 15:53:54 2009
@@ -33,7 +33,205 @@
 </head>
 <body>
 <h1>Background Tasks</h1>
-<p>This section is not yet complete.</p>
+
+<p>Often, an application will need to perform a long-running task (such as loading a large file or executing a computationally-intensive operation). Executing such code on the UI thread will cause the application to stop responding to repaints while the operation is running, giving the appearance that it is "hung".</p>
+
+<p>Pivot includes the <tt>org.apache.pivot.util.concurrent.Task</tt> class to help resolve this problem. A <tt>Task</tt> represents an instance of an operation that may be performed by a background thread. It is an abstract class, whose <tt>execute()</tt> method is overridden by an application to perform the actual task, optionally returning a value when it is complete.</p>
+
+<p>Though callers can invoke the <tt>execute()</tt> method directly, this would have the same effect as simply executing the code inline: the UI will appear to hang until <tt>execute()</tt> returns. However, <tt>Task</tt> provides an additional version of the <tt>execute()</tt> method that takes an instance of <tt>org.apache.pivot.util.concurrent.TaskListener</tt>. When this version of the method is invoked, the <tt>Task</tt> class creates (or obtains) an instance of a background thread and calls the abstract version of the method on this thread instead of the UI thread. When the abstract <tt>execute()</tt> returns, the task notifies the caller by invoking one of the methods defined by the listener interface:</p>
+
+<pre class="snippet">
+public void taskExecuted(Task<V> task);
+public void executeFailed(Task<V> task);
+</pre>
+
+<p>If the <tt>execute()</tt> method returns successfully, the <tt>taskExecuted()</tt> method is called, and the result of the operation can be obtained by calling the <tt>getResult()</tt> method of the task object. However, if the <tt>execute()</tt> call fails (by throwing an exception), the <tt>executeFailed()</tt> listener method is called, and the exception that was thrown can be obtained via the <tt>getFault()</tt> method of the task object.</p>
+
+<p>The following application demonstrates the behavior of an application when a task is executed synchronously vs. asynchronously. It uses a simple "sleep task" to simulate an operation that runs for five seconds:</p>
+
+<script src="version.js"></script>
+<script>
+var attributes = {code:"org.apache.pivot.wtk.BrowserApplicationContext$HostApplet",
+    archive:"lib/pivot-core-" + version + ".jar"
+        + ",lib/pivot-wtk-" + version + ".jar"
+        + ",lib/pivot-wtk-" + version + ".terra.jar"
+        + ",lib/pivot-tutorials-" + version + ".jar",
+    width:240,
+    height:240
+};
+var parameters = {application_class_name:"org.apache.pivot.tutorials.backgroundtasks.BackgroundTasks",
+    codebase_lookup:false,
+    java_arguments:"-Dsun.awt.noerasebackground=true -Dsun.awt.erasebackgroundonresize=true"
+};
+deployJava.writeAppletTag(attributes, parameters);
+</script>
+
+<p>Pressing the "Execute Synchronously" button activates an activity indicator component and calls the synchronous version of the <tt>execute()</tt> method of the sleep task. Though the task runs and returns correctly, the activity indicator is never shown, because the UI thread has been unable to respond to repaints while the task was running. However, when the "Execute Asynchronously" button is pressed, the activity indicator appears correctly and runs for five seconds until the task is complete.</p>
+
+<p>The WTKX for this example is shown below:</p>
+
+<pre class="brush:xml">
+&lt;Window title="Background Tasks" maximized="true"
+    xmlns:wtkx="http://pivot.apache.org/wtkx"
+    xmlns="org.apache.pivot.wtk"&gt;
+    &lt;content&gt;
+        &lt;BoxPane orientation="vertical"
+            styles="{horizontalAlignment:'center', verticalAlignment:'center'}"&gt;
+            &lt;Border&gt;
+                &lt;content&gt;
+                    &lt;ActivityIndicator wtkx:id="activityIndicator"/&gt;
+                &lt;/content&gt;
+            &lt;/Border&gt;
+
+            &lt;PushButton wtkx:id="executeSynchronousButton" buttonData="Execute Synchronously"/&gt;
+            &lt;PushButton wtkx:id="executeAsynchronousButton" buttonData="Execute Asynchronously"/&gt;
+        &lt;/BoxPane&gt;
+    &lt;/content&gt;
+&lt;/Window&gt;
+</pre>
+
+<p>The Java source for <tt>SleepTask</tt> is as follows. It simply sleeps for 5000 milliseconds and then returns a simulated result value:</p>
+
+<pre class="brush:java">
+package org.apache.pivot.tutorials.backgroundtasks;
+
+import org.apache.pivot.util.concurrent.Task;
+import org.apache.pivot.util.concurrent.TaskExecutionException;
+
+public class SleepTask extends Task&lt;String&gt; {
+    @Override
+    public String execute() throws TaskExecutionException {
+        // Simulate a long-running activity (5s)
+        try {
+            Thread.sleep(5000);
+        } catch (InterruptedException exception) {
+            throw new TaskExecutionException(exception);
+        }
+
+        // Return a simulated result value
+        return "Done sleeping!";
+    }
+}
+</pre>
+
+<p>The Java source for the application is shown below:</p>
+
+<pre class="brush:java">
+package org.apache.pivot.tutorials.backgroundtasks;
+
+import org.apache.pivot.collections.Map;
+import org.apache.pivot.util.concurrent.Task;
+import org.apache.pivot.util.concurrent.TaskExecutionException;
+import org.apache.pivot.util.concurrent.TaskListener;
+import org.apache.pivot.wtk.ActivityIndicator;
+import org.apache.pivot.wtk.Application;
+import org.apache.pivot.wtk.Button;
+import org.apache.pivot.wtk.ButtonPressListener;
+import org.apache.pivot.wtk.DesktopApplicationContext;
+import org.apache.pivot.wtk.Display;
+import org.apache.pivot.wtk.PushButton;
+import org.apache.pivot.wtk.TaskAdapter;
+import org.apache.pivot.wtk.Window;
+import org.apache.pivot.wtkx.WTKXSerializer;
+
+public class BackgroundTasks implements Application {
+    private Window window = null;
+
+    private ActivityIndicator activityIndicator = null;
+    private PushButton executeSynchronousButton = null;
+    private PushButton executeAsynchronousButton = null;
+
+    @Override
+    public void startup(Display display, Map&lt;String, String&gt; properties) throws Exception {
+        WTKXSerializer wtkxSerializer = new WTKXSerializer();
+        window = (Window)wtkxSerializer.readObject(this, "background_tasks.wtkx");
+
+        activityIndicator = (ActivityIndicator)wtkxSerializer.get("activityIndicator");
+
+        executeSynchronousButton = (PushButton)wtkxSerializer.get("executeSynchronousButton");
+        executeSynchronousButton.getButtonPressListeners().add(new ButtonPressListener() {
+            @Override
+            public void buttonPressed(Button button) {
+                activityIndicator.setActive(true);
+
+                System.out.println("Starting synchronous task execution.");
+
+                SleepTask sleepTask = new SleepTask();
+
+                String result = null;
+                try {
+                    result = sleepTask.execute();
+                } catch (TaskExecutionException exception) {
+                    System.err.println(exception);
+                }
+
+                System.out.println("Synchronous task execution complete: \"" + result + "\"");
+
+                activityIndicator.setActive(false);
+            }
+        });
+
+        executeAsynchronousButton = (PushButton)wtkxSerializer.get("executeAsynchronousButton");
+        executeAsynchronousButton.getButtonPressListeners().add(new ButtonPressListener() {
+            @Override
+            public void buttonPressed(Button button) {
+                activityIndicator.setActive(true);
+                window.setEnabled(false);
+
+                System.out.println("Starting asynchronous task execution.");
+
+                SleepTask sleepTask = new SleepTask();
+                TaskListener&lt;String&gt; taskListener = new TaskListener&lt;String&gt;() {
+                    @Override
+                    public void taskExecuted(Task&lt;String&gt; task) {
+                        activityIndicator.setActive(false);
+                        window.setEnabled(true);
+
+                        System.out.println("Synchronous task execution complete: \""
+                            + task.getResult() + "\"");
+                    }
+
+                    @Override
+                    public void executeFailed(Task&lt;String&gt; task) {
+                        activityIndicator.setActive(false);
+                        window.setEnabled(true);
+
+                        System.err.println(task.getFault());
+                    }
+                };
+
+                sleepTask.execute(new TaskAdapter&lt;String&gt;(taskListener));
+            }
+        });
+
+        window.open(display);
+    }
+
+    @Override
+    public boolean shutdown(boolean optional) {
+        if (window != null) {
+            window.close();
+        }
+
+        return false;
+    }
+
+    @Override
+    public void suspend() {
+    }
+
+    @Override
+    public void resume() {
+    }
+
+    public static void main(String[] args) {
+        DesktopApplicationContext.main(BackgroundTasks.class, args);
+    }
+}
+</pre>
+
+<p>Note that the button press listener for the "Execute Asynchronously" button wraps the actual task listener in an instance of <tt>org.apache.pivot.wtk.TaskAdapter</tt>. This is because, like most UI toolkits, Pivot user interfaces are single-threaded: all UI operations must occur on the same thread (which AWT calls the "event dispatch thread"). Wrapping the task listener in a <tt>TaskAdapter</tt> ensures that the result listener will be called on the UI thread, rather than the background thread, which is what would occur if the listener was not wrapped in the adapter.</p>
+
 <p>Next: <a href="web_queries.html">Web Queries</a></p>
 </body>
 </html>