20.8. Background TasksJobs APILong-running operations should be executed in the background so that the UI stays responsive. One solution is to fork a lower-priority thread to perform the operation rather than performing the operation in the UI thread. But, how do you keep the user informed as to the progress of the background operation? Eclipse provides a Jobs API for creating, managing, and displaying background operations. In the Favorites product, you want to periodically check for the availability of a newer version. Rather than interrupt the user, you want to have this check performed in the background and provide the user with nonintrusive progress information as the operation proceeds. To accomplish this, create NewVersionCheckJob. The goal is to exercise the Jobs API, not Internet access, so NewVersionCheckJob only simulates a version check. package com.qualityeclipse.favorites.jobs; import ... public class NewVersionCheckJob extends Job { private NewVersionCheckJob(String name) { super(name); } protected IStatus run(IProgressMonitor monitor) { // Simulate check for new version. monitor.beginTask("check for new version", 20); for (int i = 20; i > 0; --i) { monitor.subTask("seconds left = " + i); try { Thread.sleep(1000); } catch (InterruptedException e) { // Ignored. } monitor.worked(1); } monitor.done(); // Reschedule job to execute in 2 minutes. schedule(120000); return Status.OK_STATUS; } } The user will control this operation via a new checkbox on the Favorites preference page, so first add a new constant to the PreferenceConstants (see Section 12.2.4, Favorites preference page, on page 461). public static final String FAVORITES_NEW_VERSION_CHECK_PREF = "favorites.newVersionCheck"; Next, expose this new preference on the Favorites preference page by adding a new checkbox. This entails a new field plus additional code at the end of the createFieldEditors() method (see Section 12.2.4, Favorites preference page, on page 461). private BooleanFieldEditor newVersionCheckEditor; public void createFieldEditors() { ... original code here ... newVersionCheckEditor = new BooleanFieldEditor( PreferenceConstants.FAVORITES_NEW_VERSION_CHECK_PREF, "Periodically check for new version" + " of Favorites product (simulated)", getFieldEditorParent()); addField(newVersionCheckEditor); } Now you want to tie the new version check job to this preference by adding a preference listener to NewVersionCheckJob. The preference listener either schedules or cancels the job depending on the preference setting as specified by the user. private static final String JOB_NAME = "Favorites check for new version"; private static NewVersionCheckJob job = null; public boolean shouldSchedule() { return equals(job); } private static final Preferences preferences = FavoritesPlugin.getDefault().getPluginPreferences(); private static final Preferences.IPropertyChangeListener propertyListener = new Preferences.IPropertyChangeListener() { public void propertyChange(PropertyChangeEvent event) { update(); } }; private static void update() { if (preferences.getBoolean( PreferenceConstants.FAVORITES_NEW_VERSION_CHECK_PREF)) { if (job == null) { job = new NewVersionCheckJob(JOB_NAME); job.schedule(); } } else { if (job != null) { job.cancel(); job = null; } } } Next, create additional methods that are called by FavoritesPlugin when the plug-in starts up and shuts down. public static void startup() { preferences.addPropertyChangeListener(propertyListener); update(); } public static void shutdown() { preferences.removePropertyChangeListener(propertyListener); } When all this is in place, selecting the Periodically check for new version of Favorites product (simulated) checkbox on the Favorites preference page will cause the new version check operation to be performed periodically. Feedback to the user is automatically provided as part of the Jobs API through the Progress view (see Figure 20-5). The "% done" shown in the Progress view is based on the total work specified in the beginTask() method and the number of units worked is based on calls to the worked() method. The "seconds left = n" is specified by calling the subTask() method (see Section 9.4.1, IProgressMonitor, on page 383). Figure 20-5. Progress view for a background operation.
Typically, jobs are executed in the background, but the IProgressService provides the showInDialog() method for executing them in the foreground (see Section 9.4.4, IProgressService, on page 386). In addition, if setUser(true) is called after the job is instantiated but before it is scheduled, and if the user has the General > Always run in background preference unchecked, then it will execute in the foreground. job = new NewVersionCheckJob(JOB_NAME); job.setUser(true); job.schedule(); |