Brain Flush

August 15, 2008

Handling Long Running Operations In Google Android

Filed under: Mobile Devices, Software Development & Programming — Tags: , , — Matthias @ 12:27 pm

User interface responsiveness is a crucial thing for all applications that require user interaction, but maybe even more so when programming for mobile handsets. Google’s Android programming environment unfortunately does not provide any mechanism for handling operations that may require a fair amount of time to complete, but which in itself are not meant to be implemented as Android Services. An example for this would be network I/O in an Activity, such as posting data to (or retrieving data from) a remote Web server. Because the Android runtime will terminate any Activity that does not respond within a couple of seconds, it is impossible (and simply a bad idea anyway) to perform such tasks from within the UI main thread.

That being said, I have come up with a generic class that handles long running operations by spawning a separate thread and passing back any result or error data to the main thread using a callback mechanism. An animated progress dialog will be displayed while the operation is running. That way the user is kept informed about any program activity that may take some time to complete.

The class can be used as follows:

public class MyActivity implements LongRunningActionCallback<Void> {

    private LongRunningActionDispatcher<Void> dispatcher;

    private void startLongRunningOperation() {
        // the first argument is a reference to the current Context, in this
        // case the current Activity. The second argument is a reference to
        // the object implementing the callback method.
        this.dispatcher = new LongRunningActionDispatcher<Void>(this, this);
        dispatcher.startLongRunningAction(new Callable<Void>() {
            public Void call() throws Exception {
                // perform your actions that take a long time
                return null;
            }
        }, "Dialog Title", "Dialog message");
    }

    // the callback
    public void onLongRunningActionFinished(Void result, Exception error) {
        if (error != null) {
            // handle error
        } else {
            // success, work with the result, if any
        }
    }
}

This will spawn a progress dialog (not indicating any actual progress in percentage, it’s just a “busy” dialog) with the given title and message. If an exception occurred in the Callable you provided, it will be passed as the error argument to the callback, so you should always check whether it’s non-null.

Below are the source codes for both LongRunningActionDispatcher and LongRunningActionCallback.

import java.util.concurrent.Callable;

import android.app.ProgressDialog;
import android.content.Context;
import android.os.Handler;
import android.util.Log;

/**
 * Use this class if you need to dispatch expensive (long running) operations
 * from your Activity. The long running operation is provided to
 * {@link startLongRunningAction} as a {@link Callable}. The result of the
 * operation and any potential exception that occurred during the call are
 * passed to {@link LongRunningActionCallback.onLongRunningActionFinished},
 * which will be called on successful or unsuccessful completion of the
 * Callable.
 *
 * LICENSE STATEMENT (DO NOT REMOVE):
 * This code is in the public domain. You may use, alter, and redistribute it
 * free of any charges or obligations, with the following exceptions:
 * 1. You are not allowed to remove the statement naming the original author.
 * 2. You are not allowed to remove this license statement.
 *
 * @author Matthias Kaeppler
 */
public final class LongRunningActionDispatcher<ResultType> {

    private Context context;

    private LongRunningActionCallback<ResultType> callback;

    /**
     * A progress dialog shown during long-lasting operations
     */
    private ProgressDialog progressDialog;

    private Handler finishedHandler = new Handler();

    public LongRunningActionDispatcher(Context context,
            LongRunningActionCallback<ResultType> callback) {
        this.context = context;
        this.callback = callback;
    }

    /**
     * Invoke this method to start long running operations which may block your
     * activity and therefore the main UI thread. A progress dialog will be
     * shown while the operation is executing.
     *
     * @param callable
     *            The callable
     * @param progressDialogTitle
     *            The progress dialog title
     * @param progressDialogMessage
     *            The progress dialog message
     */
    public void startLongRunningAction(final Callable<ResultType> callable,
            String progressDialogTitle, String progressDialogMessage) {

        progressDialog = ProgressDialog.show(context, progressDialogTitle,
                progressDialogMessage, true, false);

        new Thread(new Runnable() {

            public void run() {
                ResultType result = null;
                Exception error = null;
                try {
                    result = callable.call();
                } catch (Exception e) {
                    Log.e("ERROR", e.getMessage());
                    error = e;
                }

                final ResultType finalResult = result;
                final Exception finalError = error;
                finishedHandler.post(new Runnable() {

                    public void run() {
                        onLongRunningActionFinished(finalResult, finalError);
                    }
                });
            }
        }).start();
    }

    private void onLongRunningActionFinished(ResultType result, Exception error) {
        progressDialog.dismiss();
        callback.onLongRunningActionFinished(result, error);
    }
}
/**
 * LICENSE STATEMENT (DO NOT REMOVE):
 * This code is in the public domain. You may use, alter, and redistribute it
 * free of any charges or obligations, with the following exceptions:
 * 1. You are not allowed to remove the statement naming the original author.
 * 2. You are not allowed to remove this license statement.
 *
 * @author Matthias Kaeppler
 */
public interface LongRunningActionCallback<ResultType> {

    /**
     * Called when the callable provided to
     * {@link LongRunningActionDispatcher.startLongRunningAction} completes.
     *
     * @param <ResultType>
     *            The result type of callable.call()
     * @param result
     *            Whatever the callable returns if it completes successfully, or
     *            null if an exception was thrown
     * @param error
     *            Whatever the callable throws if it executes in error, or null
     *            if it completed successfully
     */
    void onLongRunningActionFinished(ResultType result, Exception error);
}

February 13, 2008

LotusScript – Obscure Features Primer For Beginners

Filed under: Software Development & Programming — Tags: , , — Matthias @ 3:50 am

I am currently programming for Lotus Notes, version 7 and I am struggling with the LotusScript language which is the language of choice for Lotus Notes agent programming. I am coming from the Java camp and although I have been coding in various scripting languages like JavaScript, Python and Perl, LotusScript is a completely different beast, as it’s a BASIC dialect. I don’t consider BASIC to be a well designed language already, but LotusScript actually makes things worse because it misses some language constructs people are used to from VisualBasic and introduces some new subtleties making programming LotusScript even less intuitive. Here is a list of some of the more obscure language characteristics which may irritate people new to LotusScript.

To Dim or not to Dim

For a reason I can’t quite put my hands on, in LotusScript variables are not declared using a unified syntax. Sometimes you have to use the Dim keyword, and sometimes you don’t. I think Dim actually means “declare a variable with local scope”, which means, local to the body of a procedure (a procedure in LS is a function, a sub or a method) or local to a module. But then again, you do not use Dim to declare member variables of classes, although they are local to that class. So just remember: No Dim in class bodies, but in modules and procedures. You do not use Dim for constants by the way, just for variables. For constants, use the Const keyword.

Implicit declarations

This is one of the language “features” I simply consider bad design. Unlike e.g. JavaScript, in LS you can bring a variable to life merely by referencing it. No declaration or definition required at all. In JavaScript, referring to a variable without it being declared results in a runtime error. The LS runtime however will happily accept that code using a best effort strategy and simply treat everything it doesn’t know as a variable of type Variant. Get this:

Sub foo
    messagebox bar
End Sub

Merely by referencing the undefined symbol “bar”, LS will treat it as a Variant with value Nothing instead of issuing an error. This can lead to bugs which are very difficult to track down, because a typo in an identifier will still make your code run; it just won’t do what you expect. As I cannot think of any situation where one would want to access a variable without defining it first to actually carry some value, I can only flag this behavior flawed design. As user Papa pointed out in the comments section, you can fortunately force the compiler to reject references to undefined symbols by putting “Option Explicit” somewhere in your declarations section. I strongly suggest doing so when setting up a new project.

Calling procedures

Even after programming for several weeks, I still can’t get used to the completely awkward and inconsistent rules for how you call procedures. For example, you may call subs using the Call keyword. If you do that, you can decide whether you want to omit the parentheses when the sub does not take any arguments. However, without Call, it is forbidden to use parentheses if the sub doesn’t take any arguments! Moreover, Call cannot be used for assigning a function’s return value to some variable, so you will have to use the “normal” syntax in these cases. BUT! Of course there is an exception, namely that when assigning from the sub, you now may use empty parentheses when the function takes no arguments (just don’t you dare to use Call!) So why use Call at all? I don’t know! It’s completely useless. Find below the Call insanity summarized in all its glory:

Call f2
Call f2()
f2
f2() 'illegal!
x = f2
x = f2()
x = Call f2 'illegal!
x = Call f2() 'illegal!

Nice huh? There is another catch related to how arguments are passed to procedures. LotusScript provides two semantically different ways: Passing by value and passing by reference. Get this:

Dim x as new SomeClass
foo(x)

This code won’t compile, because it very likely does NOT do what you think it does. Here we declare a variable x pointing to an object of class SomeClass. Next, we pass it as an argument to procedure foo, but we pass it by value, which is illegal for objects. The catch in this example is that you have to read the parentheses around x as being part of the argument to foo, and not (as you probably expected) as part of the call syntax. Parentheses around a single argument is simply LotusScript’s way to explicitly say: “Pass this argument by value”. However, be careful: There is another catch. When using the Call keyword instead to invoke the function above, the parentheses are in fact now part of the call statement itself, which means, x will be passed by reference, which is fine. So in order to produce the same error when using Call, you would have to alter the code to look like this:

Dim x as new SomeClass
Call foo((x))

Gotcha!

NULL Is Not NOTHING

In Java, if you do not assign an object reference to an object, its value is intially NULL. In LS, it’s not. If you do not define an object reference to point to some object, its value is NOTHING instead (this is similar to JavaScript’s undefined, just that NOTHING is a keyword which you can use in your code). This means, checking object references for NULL always returns false. Okay, this wouldn’t be that bad, if the inconsistencies wouldn’t start here, because: Variants can be NULL. However, Variants are variant, hence their name, which especially means they can point to objects. Which for the isNull() argument in turn means (taken from the LS reference manual):

Any expression except an object reference or a Variant that contains an object reference.

Which, of course, you may not even know in advance, otherwise you wouldn’t have used a Variant, no? (Okay, except for the case where the language forces you to use them, see below!)

Using Arrays

Working with arrays in LS is the most tedious and irritating thing I have seen so far. In LS, there are two kinds of arrays: Fixed and dynamic ones. With the exception that the latter aren’t really dynamic: Their only “dynamics” are that you can omit the dimensionality when declaring them. As soon as you work with them however, you have to Redim them for the correct dimensionality you need. No array.push(). What’s even weirder is that you cannot assign something to a variable declared as an array — only to its components. For example, it is perfectly fine to do this:

Dim arr(5) as Integer
arr(0) = 1

However, you can’t do this:

Dim arr() as Integer
arr = functionReturningArray() 'illegal
arr() = functionReturningArray() 'illegal, works in VB
Set arr = functionReturningArray() 'illegal
Set arr() = functionReturningArray() 'illegal

So how you assign an array you ask? You have to declare the array as Variant, in both the function returning it and the variable receiving it:

Dim arr as Variant
arr = functionReturningArrayDeclaredAsVariant()

User defined types

Functions in LS may return a reference to a class instance, but not to a user defined type. Why? I don’t know. The practical implication is that no one uses user defined types but simply abuses the class concept to create data structures. So just remember, don’t use UDTs if you plan to use them as return values from functions; use classes instead.

Lists are no lists

You also wondered about the List type? Me too, mainly because it’s not a list type. It’s actually an associative array (a “map” in Java terminology) so don’t get too confused.

The bottom line

Okay, this is it so far; my revised version of what initially started as a rant about LotusScript… I hope it helps those people who are new to LotusScript programming (and who maybe come from more popular languages like Java) to cope with some of the not-so-intuitive things about the LotusScript language.

Happy coding!

Create a free website or blog at WordPress.com.