Android has a range of built-in dialogs that allow apps to interact with users. They can be used to display things like spinners and progress bars, and can be used to prompt the user for some kind of input, like a date or string.
All of the methods for creating dialogs live in SL4A's UI Facade, along with most of the methods you'll ever need for managing them. The UI Facade also hosts methods for creating webviews and for working with the experimental FullScreenUI stuff.
SL4A and Native Dialogs
The normal flow when using dialogs is to first create the appropriate dialog object, then set any additional features you want it to have, then render it to the user. It takes a few calls, but it's easy to do. Once it's displayed, there are methods for getting results from a dialog and for dismissing it. You can also update progress dialogs while they're being rendered.
Creating Android Dialogs
You create a new dialog using one of the
dialogCreate* calls. The standard dialogs are
For example, to create and render a date picker dialog, you'd do something like...
from android import Android
droid = Android()
Note that all interaction with the dialog is done by calling methods of
droid. This is just a consequence of the way SL4A interfaces with the Android API; the
droid object is a 'god object', so everything is a method of
droid. For simplicity's sake, there is only ever one instance of a dialog, so any
dialogCreate* call will cause any existing dialog to be destroyed.
You set any additional features of a dialog with the
dialogSet* calls. What you can customise will depend on what kind of dialog you've created.
For example, you could set the positive button text on an alert dialog using
dialogSetPositiveButtonText, and there's matching methods for setting neutral and negative button texts. You can use any combination of the three on an alert dialog.
You display a dialog using
dialogShow, and you can then dismiss the dialog with
Getting the Input
You can normally get any results using
dialogGetResponse, which blocks until the user responds to the dialog. However, for certain types of dialogs, you may instead have to use the
eventPoll method of the Events Facade to wait for a dialog event. Some dialogs, such as menus, are persistent features of an application, potentially generating multiple events over time, so they must be managed through the Events Facade.
If you create single-choice dialogs (radio buttons) or multi-choice dialogs (checklists), you must pass in a list of choices for the user to select from. You can find out which choices were selected using the
dialogGetSelectedItems method. This method returns a list of integers, which map to the indices of the selected items in the list of choices you passed in. Obviously, for a single-choice dialog, there will only be one.
Say That Again in Python...
Let's imagine we need to ask the user if they want to install a bunch of packages, then, assuming they do, we want to create a progress bar that shows how that installation process is doing. Let's also say say we have 5 packages to install.
# Create the droid object
from android import Android
droid = Android()
# Create an alert, setting a title and message
'You may want to use WiFi for this.'
# Set up a couple of buttons
# Now render the dialog to the user
# Get the result and dismiss the dialog
response = droid.dialogGetResponse().result
# Check to see if the user has pressed a button, as users can dismiss
# dialogs, and check if it was the positive one, otherwise we're done
if not 'which' in response or response['which'] != 'positive': sys.exit()
# Now the checks are done, create and render the new progress bar dialog,
# setting a title, message and a maximum progress of 5
'This should just take a moment.',
# Render the dialog
# Now do the installation, updating the progress bar along the way...
# Import a couple of parsimonyms
import some_package_installing_function as install
import some_list_of_packages as packages
# Install each of the packages, incrementing the progress bar on each
progress = 0
for package in packages:
progress += 1
# Tidy up and exit
The screenshots to the right show the confirmation dialog and the progress dialog. The actual look and feel will be slightly different from device to device of course.
Note that, if you only want to ask the user for some text input, like Python's `input` function would, or a password, you can use the `dialogGetInput` and `dialogGetPassword` methods, which are just convenient wrappers, allowing you to get these inputs in a single call.
Event Based Dialogs
The above example pretty much covered all the basics of using dialogs with SL4A, and the API Reference covers all the finer details. The only real exception to the normal way of doing dialogs (create-customise-render-read-dismiss) is when using menu items. As mentioned before, menu items are added to the native menus of applications; generally they're always available to the user and may be clicked at any point, any number of times, so they are managed a bit differently.
For example, you can use
addOptionsMenuItem to add an item to your application's options menu. The method requires two arguments, a string that sets the text to display on the item, and a string that sets a name for the events that are produced whenever the item is clicked. You can optionally set the data that is passed with the events, and set an icon to be displayed on the menu item. Again, see the API docs for all the details.
If you've used the Events Facade before, this will already will make perfect sense. Either way, it's not difficult to get started with. The following example will block, so it'd need another thread or something to be much use; this example just covers the SL4A API.
# addOptionsMenuItem takes two to four arguments:
# item_label, event_name, [event_data], [icon_name]
# The following calls add three items to the options menu...
droid.addOptionsMenuItem('Do A', 'a_event', 'Some event data.')
droid.addOptionsMenuItem('Do B', 'b_event', 'Some other data.')
droid.addOptionsMenuItem('Quit', 'kill', None, 'ic_menu_revert')
# Block until an event happens, then grab the result
res = droid.eventWait().result
# If it's a kill event, exit the event loop
if res['name'] == 'kill':
# Otherwise, print the event data