Java SE Application Design With MVC (with images)

This post is not from me, but since the original one from Oracle’s website (which was written 5 years ago) doesn’t display the images any more, I decided to replicate the post here… including all images.

Original post is from Robert Eckstein, March 2007

What Is Model-View-Controller (MVC)?

If you’ve programmed with graphical user interface (GUI) libraries in the past 10 years or so, you have likely come across the model-view-controller (MVC) design. MVC was first introduced by Trygve Reenskaug, a Smalltalk developer at the Xerox Palo Alto Research Center in 1979, and helps to decouple data access and business logic from the manner in which it is displayed to the user. More precisely, MVC can be broken down into three elements:

  • Model – The model represents data and the rules that govern access to and updates of this data. In enterprise software, a model often serves as a software approximation of a real-world process.
  • View – The view renders the contents of a model. It specifies exactly how the model data should be presented. If the model data changes, the view must update its presentation as needed. This can be achieved by using a push model, in which the view registers itself with the model for change notifications, or a pull model, in which the view is responsible for calling the model when it needs to retrieve the most current data.
  • Controller – The controller translates the user’s interactions with the view into actions that the model will perform. In a stand-alone GUI client, user interactions could be button clicks or menu selections, whereas in an enterprise web application, they appear as GET and POST HTTP requests. Depending on the context, a controller may also select a new view — for example, a web page of results — to present back to the user.

MVC1

Figure1. A Common MVC Implementation

Interaction Between MVC Components

This section will take a closer look at one way to implement Figure 1 in the context of an application in the Java Platform, Standard Edition 6 (Java SE 6). Once the model, view, and controller objects are instantiated, the following occurs:

  1. The view registers as a listener on the model. Any changes to the underlying data of the model immediately result in a broadcast change notification, which the view receives. This is an example of the push model described earlier. Note that the model is not aware of the view or the controller — it simply broadcasts change notifications to all interested listeners.
  2. The controller is bound to the view. This typically means that any user actions that are performed on the view will invoke a registered listener method in the controller class.
  3. The controller is given a reference to the underlying model.

Once a user interacts with the view, the following actions occur:

  1. The view recognizes that a GUI action — for example, pushing a button or dragging a scroll bar — has occurred, using a listener method that is registered to be called when such an action occurs.
  2. The view calls the appropriate method on the controller.
  3. The controller accesses the model, possibly updating it in a way appropriate to the user’s action.
  4. If the model has been altered, it notifies interested listeners, such as the view, of the change. In some architectures, the controller may also be responsible for updating the view. This is common in Java technology-based enterprise applications.

Figure 2 shows this interaction in more detail.

MVC2

Figure 2. A Java SE Application Using MVC

As this article mentioned earlier, the model does not carry a reference to the view but instead uses an event-notification model to notify interested parties of a change. One of the consequences of this powerful design is that the many views can have the same underlying model. When a change in the data model occurs, each view is notified by a property change event and can update itself accordingly. For example, Figure 3 shows two views that use the same data model.

MVC3

Figure 3. Multiple Views Using the Same Model

Modifying the MVC Design

 A more recent implementation of the MVC design places the controller between the model and the view. This design, which is common in the Apple Cocoa framework, is shown in Figure 4.

MVC4

Figure 4. An MVC Design Placing the Controller Between the Model and the View

The primary difference between this design and the more traditional version of MVC is that the notifications of state changes in model objects are communicated to the view through the controller. Hence, the controller mediates the flow of data between model and view objects in both directions. View objects, as always, use the controller to translate user actions into property updates on the model. In addition, changes in model state are communicated to view objects through an application’s controller objects.

Thus, when all three components are instantiated, the view and the model will both register with the controller. Once a user interacts with the view, the events are nearly identical:

  1. The view recognizes that a GUI action — for example, pushing a button or dragging a scroll bar — has occurred, using a listener method that is registered to be called when such an action occurs.
  2. The view calls the appropriate method on the controller.
  3. The controller accesses the model, possibly updating it in a way appropriate to the user’s action.
  4. If the model has been altered, it notifies interested listeners of the change. However, in this case, the change is sent to the controller.

Why adopt this design? Using this modified MVC helps to more completely decouple the model from the view. In this case, the controller can dictate the model properties that it expects to find in one or more models registered with the controller. In addition, it can also provide the methods that effect the model’s property changes for one or more views that are registered with it.

Using the Modified MVC

 This section of the article shows you how to put this design into practice, starting with the model. Suppose that you want to paint some text using a simple display model with five properties. Code Sample 1 shows a simple component that you can use to create such a model.

Code Sample 1

public class TextElementModel extends AbstractModel
{

    private String text;
    private Font font;
    private Integer x;
    private Integer y;
    private Integer opacity;
    private Integer rotation;

    /**
     * Provides the means to set or reset the model to
     * a default state
     */
    public void initDefault() {

        setOpacity(89);
        setRotation(0);
        setText("Sample Text");
        setFont(new Font("Arial", Font.BOLD, 24));
        setX(50);
        setY(50);

    }

    //  Accessors

    public String getText() {
        return text;
    }

    public void setText(String text) {

        String oldText = this.text;
        this.text = text;

        firePropertyChange(
            DefaultController.ELEMENT_TEXT_PROPERTY,
            oldText, text);
    }

    public Font getFont() {
        return font;
    }

    public void setFont(Font font) {

        Font oldFont = this.font;
        this.font = font;

        firePropertyChange(
            DefaultController.ELEMENT_FONT_PROPERTY,
            oldFont, font);
    }

    //  The remaining accessors for properties are omitted.

}

Note that the rest of the accessors follow the standard JavaBeans model, although they are omitted in Code Sample 1. For reference, Code Sample 2 shows the underlying AbstractModel class, which simply uses the javax.beans.PropertyChangeSupport class to register, deregister, and notify interested listeners of changes to the model.

Code Sample 2

public abstract class AbstractModel
{

    protected PropertyChangeSupport propertyChangeSupport;

    public AbstractModel()
    {
        propertyChangeSupport = new PropertyChangeSupport(this);
    }

    public void addPropertyChangeListener(PropertyChangeListener listener) {
        propertyChangeSupport.addPropertyChangeListener(listener);
    }

    public void removePropertyChangeListener(PropertyChangeListener listener) {
        propertyChangeSupport.removePropertyChangeListener(listener);
    }

    protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
        propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue);
    }

}

The Controller

Between the model and view lies the controller. First, take a look at the code for the abstract controller superclass, as shown in Code Sample 3.

Code Sample 3


public abstract class AbstractController implements PropertyChangeListener {

    private ArrayList<abstractviewpanel> registeredViews;
    private ArrayList<abstractmodel> registeredModels;

    public AbstractController() {
        registeredViews = new ArrayList<abstractviewpanel>();
        registeredModels = new ArrayList<abstractmodel>();
    }

    public void addModel(AbstractModel model) {
        registeredModels.add(model);
        model.addPropertyChangeListener(this);
    }

    public void removeModel(AbstractModel model) {
        registeredModels.remove(model);
        model.removePropertyChangeListener(this);
    }

    public void addView(AbstractViewPanel view) {
        registeredViews.add(view);
    }

    public void removeView(AbstractViewPanel view) {
        registeredViews.remove(view);
    }

    //  Use this to observe property changes from registered models
    //  and propagate them on to all the views.

    public void propertyChange(PropertyChangeEvent evt) {

        for (AbstractViewPanel view: registeredViews) {
            view.modelPropertyChange(evt);
        }
    }

    /**
     * This is a convenience method that subclasses can call upon
     * to fire property changes back to the models. This method
     * uses reflection to inspect each of the model classes
     * to determine whether it is the owner of the property
     * in question. If it isn't, a NoSuchMethodException is thrown,
     * which the method ignores.
     *
     * @param propertyName = The name of the property.
     * @param newValue = An object that represents the new value
     * of the property.
     */
    protected void setModelProperty(String propertyName, Object newValue) {

        for (AbstractModel model: registeredModels) {
            try {

                Method method = model.getClass().
                    getMethod("set"+propertyName, new Class[] {
                                                      newValue.getClass()
                                                  }

                             );
                method.invoke(model, newValue);

            } catch (Exception ex) {
                //  Handle exception.
            }
        }
    }

}

The AbstractController class contains two ArrayList objects, which are used to keep track of the models and views that are registered. Note that whenever a model is registered, the controller also registers itself as a property change listener on the model. This way, whenever a model changes its state, the propertyChange() method is called and the controller will pass this event on to the appropriate views.

The final method, setModelProperty(), employs some magic to get its work done. In order to keep the models completely decoupled from the controller, the code samples in this article have employed the Java Reflection API. In this case, when this method is called with the desired property name, you hunt through the registered models to determine which one contains the appropriate method. Once you find it, you invoke the method using the new value. If the method is not called, thegetMethod() will throw a NoSuchMethodException, which the exception handler ignores, allowing the for- loop to continue.

Code Sample 4 shows the source code for the default controller class. This class consists of only property constants and methods called by the GUI event listeners of the view.

Code Sample 4

public class DefaultController extends AbstractController
{

    public static final String ELEMENT_TEXT_PROPERTY = "Text";
    public static final String ELEMENT_FONT_PROPERTY = "Font";
    public static final String ELEMENT_X_PROPERTY = "X";
    public static final String ELEMENT_Y_PROPERTY = "Y";
    public static final String ELEMENT_OPACITY_PROPERTY = "Opacity";
    public static final String ELEMENT_ROTATION_PROPERTY = "Rotation";

    //  Code omitted

    public void changeElementText(String newText) {
        setModelProperty(ELEMENT_TEXT_PROPERTY, newText);
    }

    public void changeElementFont(Font newFont) {
        setModelProperty(ELEMENT_FONT_PROPERTY, newFont);
    }

    public void changeElementXPosition(int newX) {
        setModelProperty(ELEMENT_X_PROPERTY, newX);
    }

    public void changeElementYPosition(int newY) {
        setModelProperty(ELEMENT_Y_PROPERTY, newY);
    }

    public void changeElementOpacity(int newOpacity) {
        setModelProperty(ELEMENT_OPACITY_PROPERTY, newOpacity);
    }

    public void changeElementRotation(int newRotation) {
        setModelProperty(ELEMENT_ROTATION_PROPERTY, newRotation);
    }

}

The View

This example will have two views displaying the data from the model: a property-editor view and a graphical page view. Both of these are implementations of a JPanel, inserted into either a JDialogor JFrame. The dialog box allows the user to update the values of the model, and the frame panel simply reflects the changes as the final textual display. The author of this article built this example using the NetBeans Swing GUI Builder, formerly referred to as Project Matisse, to design the GUI forms.

Code Sample 5 shows the source code for the property-editor view, the more interesting of the two. The first section is simply devoted to initialization of the components, which for the most part was automatically generated by the NetBeans integrated development environment (IDE) in theinitComponents() method. All of this section is omitted but is present in the downloadable code. Any other initialization that you need to perform — in this case, creating custom models for JSpinnerand JSlider objects or adding DocumentListeners to the JTextField components — is handled in the localInitialization() method.

Code Sample 5

public PropertiesViewPanel(DefaultController controller) {

this.controller = controller;

initComponents();
localInitialization();

}

// ‹editor-fold defaultstate="collapsed" desc=" Local Initialization "›

/**
* Used to provide local initialization of Swing components
* outside of the NetBeans automatic code generator
*/
public void localInitialization() {

opacitySpinner.setModel(new SpinnerNumberModel(100, 0, 100, 1));
opacitySlider.setModel(new DefaultBoundedRangeModel(100, 0, 0, 100));

rotationSpinner.setModel(new SpinnerNumberModel(0, -180, 180, 1));
rotationSlider.setModel(new DefaultBoundedRangeModel(0, 0, -180, 180));

text.getDocument().addDocumentListener(new DocumentListener() {

public void insertUpdate(DocumentEvent e) {
textDocumentChanged(e);
}

public void removeUpdate(DocumentEvent e) {
textDocumentChanged(e);
}

public void changedUpdate(DocumentEvent e) {
textDocumentChanged(e);
}

});

}

// ‹/editor-fold›

Note that the automatically generated NetBeans IDE code folds in the source code so that the developer can collapse each of these sections when it is not needed:


// ‹editor-fold defaultstate="collapsed" desc=" Local Initialization "›
// ‹/editor-fold›

If you’re using the NetBeans IDE, this practice is highly recommended.

The second section of the PropertiesViewPanel class deals exclusively with the model. In Code Sample 6, a modelPropertyChange() method is called by the controller whenever the model reports a state change.

Code Sample 6


// ‹editor-fold defaultstate="collapsed" desc=" Model Event Handling Code "›

    public void modelPropertyChange(final PropertyChangeEvent evt) {

        if (evt.getPropertyName().equals(
                   DefaultController.ELEMENT_X_PROPERTY)) {
            String newStringValue = evt.getNewValue().toString();
            xPositionTextField.setText(newStringValue);
        } else if
           (evt.getPropertyName().equals(
                   DefaultController.ELEMENT_Y_PROPERTY)) {
            String newStringValue = evt.getNewValue().toString();
            yPositionTextField.setText(newStringValue);
        } else if
           (evt.getPropertyName().equals(
                   DefaultController.ELEMENT_OPACITY_PROPERTY)) {
            int newIntegerValue = (Integer)evt.getNewValue();
            opacitySpinner.setValue(newIntegerValue);
            opacitySlider.setValue(newIntegerValue);
        } else if
            (evt.getPropertyName().equals(
                   DefaultController.ELEMENT_ROTATION_PROPERTY)) {
            int newIntegerValue = (Integer)evt.getNewValue();
            rotationSpinner.setValue(newIntegerValue);
            rotationSlider.setValue(newIntegerValue);
        } else if
           (evt.getPropertyName().equals(
                   DefaultController.ELEMENT_TEXT_PROPERTY)) {
            String newStringValue = evt.getNewValue().toString();
            text.setText(newStringValue);
        } else if
           (evt.getPropertyName().equals(
                   DefaultController.ELEMENT_FONT_PROPERTY)) {
            Font f = (Font)evt.getNewValue();
            String fontString = f.getFontName() + " " + f.getSize();
            font.setText(fontString);
            currentFont = f;
        }

        //  Remainder of the code omitted

    }

    // ‹/editor-fold›

Again, this code sample omits portions of the code that are similar to the sections shown.

The final portion consists of the GUI event listeners. Code Sample 7 contains listeners that are called whenever GUI events occur, such as pushing the Change Font button or the Opacityspinner buttons, or resetting the text in any of the text fields. These are largely event listeners that most Swing developers are already familiar with. If you’re using the NetBeans IDE, you’ll see that the IDE can automatically generate many of these using the GUI developer.

Code Sample 7

// ‹editor-fold defaultstate="collapsed" desc=" GUI Event Handling Code "›

    //  Code omitted

    private void yPositionTextFieldFocusLost(java.awt.event.FocusEvent evt) {
        try {
            controller.changeElementYPosition(
                Integer.parseInt(yPositionTextField.getText()));
        } catch (Exception e) {
            //  Handle exception.
        }
    }

    private void yPositionTextFieldActionPerformed(java.awt.event.ActionEvent evt) {
        try {
            controller.changeElementYPosition(
                Integer.parseInt(yPositionTextField.getText()));
        } catch (Exception e) {
            //  Handle exception.
        }
    }

    //  Code omitted -- code for xPosition
    //  is nearly the same as for yPosition.

    private void changeFontButtonActionPerformed(java.awt.event.ActionEvent evt) {

        JFontChooserDialog fontChooser = new
            JFontChooserDialog((Dialog)this.getTopLevelAncestor());
        fontChooser.setSelectedFont(currentFont);
        fontChooser.setVisible(true);

        Font returnedFont = fontChooser.getSelectedFont();
        if (returnedFont != null) {
            controller.changeElementFont(returnedFont);
        }
    }

    private void opacitySliderStateChanged(javax.swing.event.ChangeEvent evt) {
        controller.changeElementOpacity((int)opacitySlider.getValue());
    }

    private void rotationSliderStateChanged(javax.swing.event.ChangeEvent evt) {
        controller.changeElementRotation((int)rotationSlider.getValue());
    }

    private void opacitySpinnerStateChanged(javax.swing.event.ChangeEvent evt) {
        controller.changeElementOpacity((Integer)opacitySpinner.getValue());
    }

    private void rotationSpinnerStateChanged(javax.swing.event.ChangeEvent evt) {
        controller.changeElementRotation((Integer)rotationSpinner.getValue());
    }

    private void textDocumentChanged(DocumentEvent evt) {

        Document document = evt.getDocument();
        try {
            controller.changeElementText(document.getText(0,
            document.getLength()));
        } catch (BadLocationException ex) {
            //  Handle exception.
        }
    }

    // ‹/editor-fold›

Issues With Application Design
Once the application is up and running, you immediately run into a problem. Consider the following chain of events:

  1. One of the Swing components in the view receives a change, presumably from the user action.
  2. The appropriate controller method is called.
  3. The model is updated. It notifies the controller of its property change.
  4. The view receives a change event from the controller and attempts to reset the value of the appropriate Swing components.
  5. The appropriate controller method is called, and the model is updated again.

At this point, any of three different scenarios can occur, depending on what Swing component you use and how robust your model is.

  • The Swing component that prompted the initial change refuses to update itself the second time, noting that its property state cannot be updated again while it is in the process of notifying listeners of the initial state change. This primarily occurs when you use Swing text components.
  • The model notes that the value of the second update matches that of the first, its current value, and refuses to send a change notification. This is always a safe programming practice, and it automatically occurs if you use the PropertyChangeSupport class provided in the java.beans package. However, it does not keep the model from receiving a redundant update.
  • No safeguards are in place on either the model or the Swing component, and the program enters an infinite loop.

This issue occurs because the Swing components are autonomous. For example, what happens if the user presses the up arrow of the JSpinner component in PropertiesViewPanel, incrementing the spinner’s value by one? After the value is updated, a GUI event listener method that is listening for value changes is called, opacitySpinnerStateChanged(), which in turn calls the controller and then updates the appropriate property in the model.

With a traditional MVC design, the view would still contain the previous value, and the change in the model would update the view to the current value. However, there is no need to update the Swing component because it has already reset itself to the correct value — it did so before it even passed an event to the controller.

How do you get around this? One way is to write a mechanism that tells the model or the controller not to propagate a change notification under these circumstances, but this is not a good idea. Remember that more than one view may be listening for changes on the model. If you shut down the change notification for the model, no other listeners, including other views, will be notified of the change. In addition, other components in the same view may rely on the property change notification, with a slider and spinner combination, for example.

Ideally, each Swing component would be aware of its current value and the value that the view is trying to set it to. If they match, no change notifications will be sent. However, some Swing components include this logic, and others do not. One possible solution is to check the incoming changed value of the model against the current value stored in the Swing component. If they are identical, there is no need to reset the value of the Swing component.

Code Sample 8 shows an update of the modelPropertyChange() method to demonstrate this approach.

Code Sample 8

public void modelPropertyChange(final PropertyChangeEvent evt) {

        if (evt.getPropertyName().equals(DefaultController.ELEMENT_X_PROPERTY)) {

            String newStringValue = evt.getNewValue().toString();
            if (!xPositionTextField.getText().equals(newStringValue))
                xPositionTextField.setText(newStringValue);

        }

        //  Remaining code omitted

    }

The final example, which uses two delegate views, is shown in Figure 5. The second delegate makes use of the Java 2D libraries to display the text, which is beyond the scope of this article. However, the source code is relatively easy to follow and is included in the downloadable source code.

Conclusion

MVC is one of the staples of any GUI programmer’s toolkit. This article has shown how to implement a variation of the MVC design using Java SE and the Swing libraries. In addition, it has demonstrated some common issues that programmers may face when using MVC, as well as listed common Swing component events that any Java platform programmer can use when creating a view.

For More Information

Laurent KUBASKI  (originally from Robert Eckstein)

Changing the color of the background menu in Android

The menu icons of my application where not displayed on my real Android device, so I ended up changing the menu background color, before coming up with a better approach.

Note: this post is only about changing the menu background color. If you want to change other things like the text color, check this stackoverflow post.

in [PROJECT_HOME]/res/values/styles.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
   <style name="MyTheme" parent="android:Theme">
      <item name="android:panelFullBackground">@android:color/darker_gray</item>
   </style>
</resources>

In AndroidManifest.xlm:

<application
   android:label="@string/app_name"
   android:icon="@drawable/ic_launcher"
   android:theme="@style/MyTheme">

Laurent KUBASKI

How to make sure that your Android menu icon is displayed whatever the background color is

Wow, that’s a long title 😉

The problem with background colors

Today I downloaded the Action Bar Icon Pack from the official Android develop site and I used one of the icons (“2_action_help.png”) in the menu of one of my applications.

In the icon pack, each icon comes in 2 different colors: one for the “holo dark” theme and one for the “holo light” theme. I chosed the one from the “holo dark” theme, with this menu.xml:


<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
   <item
      android:id="@+id/about_menu_2"
      android:icon="@drawable/action_help_holo_dark"
      android:title="About"/>
</menu>

…and ended up with this result in the Android emulator:

about_emulator

So far so good. Then I deployed my application on a real device (same Android version as the emulator) and ended up with this:

about_real

What the f… ?

Yes indeed: on my real device, the menu has a white background, which means that the icon cannot be seen (white on white). Using the “holo light” icon instead fixes the problem, but in that case the icon is not displayed on the emulator (where the menu has a black background).

What actually happens is that the real device manufacturer (SAMSUNG for me), can choose to customize the Android default theme and in that case, it will be different from the one used by your emulator.

How to solve this issue

It turns out that this is a common problem and there are lots of blog posts to talk about this. 4 solutions are usually suggested:

  1. Use a set of icons that will work with all background colors as suggested here.
  2. Embeds different icons in your application and dynamically select the one that will best match the background color.
  3. Customize the menu by specifying your own background/text color as suggested here.
  4. Use the builtin icons

Let’s talk about option #4: using the Android builtin icons

Using Android built-in icons

Android comes with a bunch of built-in drawables that are available in “android.R.drawable”.

Jeremy Logan created a great website that displays all the built-in drawables for all Android version, check out androiddrawables.com.

So basically, if I want to use the built-in “help” icon, I need to do this:


<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
   <item
      android:id="@+id/about_menu_1"
      android:icon="@android:drawable/ic_menu_help"
      android:title="About"/>
</menu>

Result on the emulator:

about_emulator_2

Result on the real device:

about_real_2

Why does it work ? Because if the real device manufacturer decides to change the default Android theme… then he also needs to change the built-in icons !

Some people will tell you that referencing these built-in icons is a bad idea and that you should copy them in your local drawable folders. In fact, the official Android documentation states that:

Warning: Because these resources can change between platform versions, you should not reference these icons using the Android platform resource IDs (i.e. menu icons under android.R.drawable). If you want to use any icons or other internal drawable resources, you should store a local copy of those icons or drawables in your application resources, then reference the local copy from your application code. In that way, you can maintain control over the appearance of your icons, even if the system’s copy changes.

The problem with this “recommanded” approach is that we end up with the initial problem ! Anyway, in case you want to do this, the png files for the built-in icons are here: [ANDROID_SDK_HOME]/platforms/android-[VERSION]/data/res

Creating your own drawables

As an added bonus, Google provides a cool online icon generator tool, you may want to check it out: Android Asset Studio.

How to know which activities are running in Android

An Android process does not correspond to an Android activity, which means that even if there is a running process corresponding to your application (I’m talking about the processed listed by the “ps” command), you cannot use this information to know how many of your activities are still alive.

OK, so if you cannot use “ps” command, how can you know which activities are running ?

Well, you need to use the “dumpsys activity” command.

To demonstrate this, I’m going to use a sample application:

  • the package name in the AndroidManifest.xml is fr.lk.notes (i.e: package=”fr.lk.notes”)
  • the main activity is named fr.lk.notes.activity.ViewNotes
  • there is a second activity named fr.lk.notes.activity.CreateOrEditNote

Exercice #1: we launch the application and then exit it by clicking on the BACK button

This will invoke ViewNotes.onDestroy(), which means that the main activity will be killed.

Yet, the “ps” command shows that the application process is still running:


C:\android-sdk\platform-tools>adb shell ps
USER PID PPID VSIZE RSS WCHAN PC NAME
root 1 0 404 280 c0274189 08054b16 S /init
[SNIP]
u0_a43 1635 793 216720 31232 ffffffff b802c157 S fr.lk.notes
[SNIP]

Now if we launch the “dumpsys activity” command, and if we look at the “Running activities” section, we can see that there is no reference to any of our activites, which means that they have all been destroyed:


C:\android-sdk\platform-tools>adb shell dumpsys activity
[SNIP]

Running activities (most recent first):

TaskRecord{b3e1dc08 #2 A com.android.launcher U 0}
 Run #0: ActivityRecord{b3e04590 com.android.launcher/com.android.launcher2.Launcher}

[SNIP]

Exercice #2: we launch the application

This puts the main “ViewNotes” activity in a running state and we can see it in the dumpsys output:


[SNIP]

Running activities (most recent first):

TaskRecord{b3eb03a8 #6 A fr.lk.notes U 0}
 Run #1: ActivityRecord{b3c1f2d8 fr.lk.notes/.activity.ViewNotes}
 TaskRecord{b3e1dc08 #2 A com.android.launcher U 0}Run #0: ActivityRecord{b3e04590 com.android.launcher/com.android.launcher2.Launcher

[SNIP]

Exercice #3: we launch the application and navigate to the second activity

This leaves the main activity in a “stopped” state and dumpsys shows both activities:


[SNIP]

Running activities (most recent first):

TaskRecord{b3eb03a8 #6 A fr.lk.notes U 0}
 Run #2: ActivityRecord{b3ee1ce0 fr.lk.notes/.activity.CreateOrEditNote}
 Run #1: ActivityRecord{b3c1f2d8 fr.lk.notes/.activity.ViewNotes}
 TaskRecord{b3e1dc08 #2 A com.android.launcher U 0}Run #0: ActivityRecord{b3e04590 com.android.launcher/com.android.launcher2.Launcher}

[SNIP]

Laurent KUBASKI

Why Activity.onDestroy() and Activity.onRestoreInstanceState() are not always invoked

First, the facts:

  1. Activity.onStop() is not always followed by Activity.onDestroy() since Android can decide to kill your application just after invoking Activity.onStop()
  2. Activity.onSaveInstanceState() is not always followed by Activity.onRestoreInstanceState()

1. When is Activity.onDestroy() invoked ?

First, check the Android activity lifecycle: as you can see, Android can kill your application without invoking onDestroy() if “an app with higher priority needs memory“.

In fact, the javadoc for onDestroy() also states that “There are situations where the system will simply kill the activity’s hosting process without calling this method (or any others) in it, so it should not be used to do things that are intended to remain around after the process goes away“.

I wrote a simple application containing only one (main) activity and used a couple of scenarios to have a better understanding of when onDestroy() was called:

Scenario #1-1: HOME key is hit while the activity is running

  • Android invokes onSaveInstanceState() -> onPause() -> onStop()
  • You are now back on the HOME screen
  • When the application is relaunched, Android invokes onCreate() -> onStart() -> onResume()

Note: onCreate() may actually not be invoked when the application is started again because it’s up to the Android OS to decide whether or not to kill your activity just after invoking onStop(). So if onCreate() is not invoked, this simply means that your activity was still in the background in a “stopped” state.

Scenario #1-2: BACK key is hit while the activity is running

  • Android invokes onPause() -> onStop() -> onDestroy()
  • You go back to the screen you were before launching the application
  • When the application is relaunched, Android invokes onCreate() -> onStart() -> onResume()

Note: this time, onCreate() is always invoked because hitting the BACK key destroys your activity.

Scenario #1-3: screen orientation changes while the activity is running (CTRL-F12 in the Android emulator)

  • Android invokes onSaveInstanceState() -> onPause() -> onStop() -> onDestroy()
  • It then invokes: onCreate() -> onStart() -> onRestoreInstanceState() -> onResume()

Scenario #1-4: another application is launched while the activity is running (click on the phone button in the Android emulator)

  • Android invokes onSaveInstanceState() -> onPause() -> onStop()
  • If you now hit BACK to come back to your application: onStart() -> onResume()

 

2. When is Activity.onRestoreInstanceState() invoked ?

If you check again the various scenarios above, you will see that onSaveInstanceState() is indeed not always followed by onRestoreInstanceState().

Why ?

Because there are only 2 scenarios where onSaveInstanceState() is followed by onRestoreInstanceState():

  1. The screen orientation changes (see scenario #1-3)
  2. Another activity gets the focus and then Android decides to kill the previous one (possibly because the device is low on resources)

To test#2 using the Android emulator, you need to do this:

  • Launch your application so that your activity is running and has the focus
  • Launch another application (for ex: click on the phone button in the Android emulator to launch the dialer application)
  • Launch an ADB shell and use the “ps” command to kill your application
  • From the dialer application, hit the BACK button
  • Android will invoke onCreate() -> onStart() -> onRestoreInstanceState -> onResume()

 

Laurent KUBASKI

Running Android unit tests in Intellij

It turns out that running Android unit tests in Intellij is not as easy as creating a unit test in the [ANDROID_MODULE_HOME]/src folder.

You instead need to create a new “Android test module” inside your main module and run your tests from there:

If you choose the default options, your new test module (“myAndroidTestProject”) will be created inside the main module (“myAndroidProject”):

This test module has a dependency on the main module:

And the nice thing is that Intellij automatically creates an Android unit test configuration that automatically executes all the unit tests in this new test module:

From there, you can create your unit tests in this new module. Here is a simple one:


public class MyAndroidTestCase extends AndroidTestCase {

public void test1() throws IOException, JSONException {
 Log.d(this.getClass().toString(), (">> test1"));
 Context ctx = getContext();
 FileOutputStream fos = ctx.openFileOutput("test.dat", Context.MODE_PRIVATE);
 fos.write("hello the world".getBytes());
 fos.close();
 assertTrue(Arrays.equals(new String[]{"test.dat"}, ctx.fileList()));
 ctx.deleteFile("test.dat");
 Log.d(this.getClass().toString(), ("<< test1"));
 }
}

Note that Android unit tests cannot be directly ran from Intellij: you need to run them from the emulator (or from a real device):

About the Android toolbox binary

1. What is Android toolbox ?

While browsing the filesystem of my Android emulator, I was surprised to discover that most of the items in the /system/bin folder are actually symlinks to the toolbox binary:


C:\android-sdk\platform-tools>adb shell
# ls -l /system/bin
ls -l /system/bin
[SNIP]
lrwxr-xr-x root shell 2012-08-23 07:01 cat -> toolbox
-rwxr-xr-x root shell 129416 2012-08-23 07:00 check_prereq
lrwxr-xr-x root shell 2012-08-23 07:01 chmod -> toolbox
lrwxr-xr-x root shell 2012-08-23 07:01 chown -> toolbox
[SNIP]
-rwxr-xr-x root shell 181002 2012-08-23 07:01 toolbox
[SNIP]
#

So… what is this toolbox binary ?

Toolbox is like a “swiss army knife”: it allows you to run multiple commands from a single binary. So instead of having different binaries for each standard Unix command (like ls or rm), you can have a single binary (toolbox) that can execute all these commands.

To use it, simply execute “toolbox XX” instead of “XX”. So to list the content of the “/system/bin” folder, I could have used “toolbox ls -l /system/bin”:


# toolbox ls -l /system/bin
toolbox ls -l /system/bin
[SNIP]
lrwxr-xr-x root shell 2012-08-23 07:01 cat -> toolbox
-rwxr-xr-x root shell 129416 2012-08-23 07:00 check_prereq
lrwxr-xr-x root shell 2012-08-23 07:01 chmod -> toolbox
lrwxr-xr-x root shell 2012-08-23 07:01 chown -> toolbox
[SNIP]
-rwxr-xr-x root shell 181002 2012-08-23 07:01 toolbox
[SNIP]
#

Check the toolbox git repository to see which commands can be used.

A popular alternative to toolbox is BusyBox, which provides even more functionnalities.

2. How do toolbox symlinks work ?

As explained above, the “ls” command is actually a symlink that references toolbox:


# ls -l /system/bin/ls
ls -l /system/bin/ls
lrwxr-xr-x root shell 2012-08-23 07:01 ls -> toolbox

The question is: since we have dozens of symlinks that reference toolbox…how does toolbox know which symlink was originally executed ?

It turns out that is actually easy to know, and I’m going to write a Linux bash script showing how you can reproduce this behavior.

First, I have a “script.sh” script and 2 symlinks (named “cmd1” and “cmd2”) that reference this script:


[laurent@localhost toolbox_example]$ ll
total 4
lrwxrwxrwx. 1 laurent laurent 9 Nov 22 11:18 cmd1 -> script.sh
lrwxrwxrwx. 1 laurent laurent 9 Nov 22 11:18 cmd2 -> script.sh
-rwxrwxr-x. 1 laurent laurent 211 Nov 22 11:22 script.sh

And here is the content of my script:


[laurent@localhost toolbox_example]$ cat script.sh
#!/usr/bin/bash
command=`basename $0`
case "$command" in
cmd1) echo "executing cmd1 with args=[$*]"
 ;;
cmd2) echo "executing cmd2 with args=[$*]"
 ;;
*) echo "Invalid option"
 ;;
esac

Let’s see this in action:


[laurent@localhost toolbox_example]$ ./cmd1 arg1
executing cmd1 with args=[arg1]
[laurent@localhost toolbox_example]$ ./cmd2 arg2
executing cmd2 with args=[arg2]

Of course, this concept can be easily ported to C/C++.

Any questions ?

Laurent KUBASKI

Adding LXDE taskbar shortcuts

OK, so after creating new menu entries & desktop shortcuts and after creating new menu sections, let’s see how to create taskbar shortcuts.

On my LXDE taskbar (which is actually called lxpanel in LXDE), you can see that I have a shortcut for leafpad and one for gedit:

To accomplish that, right click on the taskbar and choose the “Add/Remove Panel items” option. This brings up the “Panel Preference” dialog. From there, go to the “Panel Applets” tab which displays the different elements of your taskbar:

 

The “Spacer” plugin is just a way to add a separation between the different plugins. On the screenshot above, you can see that my second spacer is “stretched”, which means that all plugins that comes after it (System Tray + Digital Clock in my case) will end up on the right side.

OK, so to add application shortcuts, you need to add the “Application launch bar” plugin to your taskbar. To do this, just click on the “Add” button, select “Application launch bar” in the list of available plugins and put it in the 4th position:

 

Now select it, click on the “Edit button”: this will display the launch bar configuration dialog. The right side of the dialog displays the applications that are part of your start menu: simply add the ones that you want to the left side of the dialog.

 

And… that’s it !

Now if you don’t want to use graphical tools, here is the lxpanel configuration file that controls everything: ~/.config/lxpanel/LXDE/panels

Adding LXDE start menu sections (or “sub-menus”)

This is a follow-up to my previous post about adding LXDE start menu entries.

So you are now an expert in the .desktop file format and you know how to create one and how to “link” it to one of the existing LXDE start menu sections (Accessories, Graphics, Internet, Office, Other, Sound & Video, System Tools).

But what if you want to create a new section ? Or what if you want to add a sub-section to an existing section ? Well: easy as pie !

OK, I’m lying: you will need to create and edit some XML files, but isn’t this even more funny than clicking on a  “create section” button in a UI ? 😉

How the LXDE main menu is configured

The default LXDE start menu layout is configured here: /etc/xdg/menus/lxde-applications.menu

It’an XML file that contains a bunch of <Menu> tags describing the menu layout. On my Fedora box, the “Accessories” section is described like this:

<Menu>
   <Name>Accessories</Name>
   <Directory>lxde-utility.directory</Directory>
   <Include>
      <And>
         <Category>Utility</Category>
         <Not><Category>System</Category></Not>
      </And>
   </Include>
</Menu>

This translates to “the ‘Accessories’ section is described in the lxde-utility.directory file and a .desktop file will appear in this section if its category is ‘Utility’“. Said differently: “if you want your program shortcut it to be displayed in the ‘Accessories’ section, then create a .desktop file containing “Categories=Utility”“.

If you are looking for the directory that contains the .directory files, it’s here: usr/share/desktop-directories.

How to customize the main menu

To customize your start menu, you will NOT modify the global  /etc/xdg/menus/lxde-applications.menu file, but you will instead create a file that will contain your own extensions. This means that each user will be able to get its own customized menu:

  • Custom main menu extensions must be configured in ~/.config/menus/lxde-applications.menu
  • Custom .directory files must be created in ~/.local/share/desktop-directories

Exercise #1: creating a new section in the main menu

First, create this file: ~/.config/menus/lxde-applications.menu file:

<!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd">
<Menu>
   <Name>My Menu Extension</Name>
   <MergeFile type="parent">/etc/xdg/menus/lxde-applications.menu</MergeFile>
   <Menu>
      <Name>CustomMenu</Name>
      <Directory>custom_menu.directory</Directory>
      <Include>
         <And><Category>CustomMenuCategory</Category></And>
      </Include>
   </Menu>
</Menu>
  • The <MergeFile> tag says that we are going to extend the existing /etc/xdg/menus/lxde-applications.menu configuration file.
  • Our new custom section is configured in the ~/.local/share/desktop-directories/custom_menu.directory file.
  • Each .desktop file containing “Categories=CustomMenuCategory” will belong to this new section.

Next, create ~/.local/share/desktop-directories/custom_menu.directory:

[laurent@localhost desktop-directories]$ cat ~/.local/share/desktop-directories/custom_menu.directory
[Desktop Entry]
Encoding=UTF-8
Name=The Custom Menu Name

Then, create ~/.local/share/applications/custom_menu_entry.desktop (because the new section will not appear if there is no item inside):

[laurent@localhost applications]$ cat ~/.local/share/applications/custom_menu_entry.desktop
[Desktop Entry]
Name=custom menu entry
Exec=/usr/bin/foo
Comment=
Icon=
NoDisplay=false
Categories=CustomMenuCategory;
Type=Application

Finally, reload the menu by executing “lxpanelctl restart” and there you are:

Exercise #2: creating a sub-section in an existing main menu section

OK, we are now going to add a sub-section in the “Accessories” section.

First, the updated ~/.config/menus/lxde-applications.menu

<!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd">
<Menu>
   <Name>My Menu Extension</Name>
   <MergeFile type="parent">/etc/xdg/menus/lxde-applications.menu</MergeFile>
   <Menu>
      <!-- parent section name: -->
      <Name>Accessories</Name>
      <Menu>
        !-- our new sub-section name: -->
        <Name>SubMenu</Name>
        <Directory>sub_menu.directory</Directory>
        <Include>
           <And><Category>SubMenuCategory</Category></And>
        </Include>
     </Menu>
   </Menu>
</Menu>

So what’s happening here ? Well, we are nesting our new SubMenu under the existing Accessories menu.
In order for this to work, your must make sure that the parent section name (“Accessories” in this example), is spelled exactly as in /etc/xdg/menus/lxde-applications.menu

Then, ~/.local/share/desktop-directories/sub_menu.directory:

[Desktop Entry]
Encoding=UTF-8
Name=The Sub Menu Name

Then, ~/.local/share/applications/sub_menu_entry.desktop:

[Desktop Entry]
Name=sub menu entry
Exec=hellotheworld
Comment=
Icon=
NoDisplay=false
Categories=SubMenuCategory;
Type=Application

Finally, “lxpanelctl restart” and there you are:

Exercise #3: conditional fun

If you look at your existing /etc/xdg/menus/lxde-applications.menu file, you will see that you can use conditional expressions to define how your .desktop files are going to be linked to your menu sections.

For example, this section definition:

<Menu>
   <Name>Administration</Name>
   <Directory>lxde-settings-system.directory</Directory>
   <Include>
      <And>
         <Category>Settings</Category>
         <Category>System</Category>
      </And>
   </Include>
</Menu>

Means that a .desktop file will be linked to the “Administration” section if its categories are “Settings” and “System” (Categories=Settings;System)

And this section definition:

<Menu>
   <Name>Accessories</Name>
   <Directory>lxde-utility.directory</Directory>
   <Include>
      <And>
         <Category>Utility</Category>
         <Not><Category>System</Category></Not>
      </And>
   </Include>
</Menu>

Means that a .desktop file will be linked to the “Accessories” section if its categories are “Utility” and not “System”. So “Categories=Utility;Foo” will link the .desktop file to the Accessories section, and “Categories=Utility;System” will link it to the “System Tools” section.

You can also use the <Xor> tag, but I guess that you can easily understand how it works.

Laurent KUBASKI

Restarting LXDE when it freezes/hangs

This is going to be of interest to no-one except me, but here it is:

  • Hit CTRL-ALT-F2 to switch to console mode (CTRL-ALT-F1 will bring you back to LXDE)
  • Kill the /usr/bin/X process
  • That’s it !