What if Android emulator fails to start

Today I launched the AVD manager, selected my Android virtual device, clicked on  “Start” and… nothing !

OK, why don’t you want to start, you son of your father ?

Launching it from the command line showed the error message:


C:\Program Files (x86)\Android\android-sdk-r16\tools>emulator.exe -avd AVD_for_403

C:\Program Files (x86)\Android\android-sdk-r16\tools>Failed to allocate memory: 8

This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.

I had previously increased the virtual device memory from 256 to 1024, but for some reason the emulator was not happy with it. Lowering it to 512 solved my issue:

What I don’t understand is that I have 16GB of RAM on my laptop… if someone knows why I cannot allocate 1025MB , I’m interested !

Laurent KUBASKI

Better conditional statements

I don’t know if you are like me, but I really have a hard time reading complex ‘if’ statements with boolean expressions.

For example:

if ("male".equals(person.getGender()) && person.getAge()>=18 && !"french".equals(person.getNationality()) ||
 "female".equals(person.getGender()) && person.getAge()<18 && !"german".equals(person.getNationality()) {
 // do something
 }

If you are like me, my recommendation is to give explicit names to each expression, like this:

boolean isNonFrenchMaleAdult = "male".equals(person.getGender()) && person.getAge()>=18 && !"french".equals(person.getNationality());
boolean isNonGermanFemaleChild = "female".equals(person.getGender()) && person.getAge()<18 && !"german".equals(person.getNationality());

 if (isNonFrenchMaleAdult || isNonGermanFemaleChild) {
 // do something
 }

From there, it might also be interesting to make the conditional expressions part of the Person class to end up with:

if (person.isNonFrenchMaleAdult() || person.isNonGermanFemaleChild()) {
 // do something
 }

You can even go further and combine the 2 methods in a single one:

if (person.isEligibleToDoSomethingVeryInteresting()) {
 // do something
 }

Finally, why not completely move all the logic inside the Person class ?

person.doIt();

Note that in practice, you may not want to move all the logic inside the Person class.

For example, if the ‘if’ statement persists the Person instance in a database, you may not want to put the data access logic in the domain object.

Laurent KUBASKI

Button at bottom of dialog with MigLayout

MigLayout is a powerfull Swing layout manager.

However, when you are used to the standard J2SE layout managers, it can take a while to understand how to do something using MigLayout.

For example, I needed to create this UI:

As you can see, the idea is to leave the OK button at the button of the dialog, even when the dialog is resized.

My initial attempt was to use a fake panel as the third row:

public class TestResize extends JDialog {
protected JPanel contentPane;
public TestResize() {
   super((Dialog) null, "Test resize", true);
   setupUI();
   setContentPane(contentPane);
}
private void setupUI() {
   contentPane = new JPanel(new MigLayout());
   // first row
   contentPane.add(new JLabel("Enter size"), "");
   contentPane.add(new JTextField(""), "grow, pushx, wrap");
   // second row
   contentPane.add(new JLabel("Enter weight"), "");
   contentPane.add(new JTextField(""), "grow, pushx, wrap");
   // third row = fake panel that is allowed to grow
   contentPane.add(new JPanel(), "span 2, grow, pushy, wrap");
   // fourth row = panel with centered button
   JPanel buttonPanel = new JPanel(new MigLayout("", "[center, grow]"));
   buttonPanel.add(new JButton("Ok"), "");
   contentPane.add(buttonPanel, "dock south");
}
public static void main(String[] args) {
   TestResize dialog = new TestResize();
   dialog.pack();
   dialog.setVisible(true);
}
}

This works… but it’s not the correct way to do it using MigLayout: you need to use  the “push” constraint.

public class TestResize extends JDialog {
protected JPanel contentPane;
public TestResize() {
   super((Dialog) null, "Test resize", true);
   setupUI();
   setContentPane(contentPane);
}
private void setupUI() {
   // Layout is constructed with "push" constraint
   contentPane = new JPanel(new MigLayout("", "", "[][]push[]"));
   // first row
   contentPane.add(new JLabel("Enter size:"), "");
   contentPane.add(new JTextField(""), "grow, pushx, wrap");
   // second row
   contentPane.add(new JLabel("Enter weight"), "");
   contentPane.add(new JTextField(""), "grow, pushx, wrap");
   // third row = panel with centered button
   JPanel buttonPanel = new JPanel(new MigLayout("", "[center, grow]"));
   buttonPanel.add(new JButton("Ok"), "");
   contentPane.add(buttonPanel, "dock south");
}
public static void main(String[] args) {
TestResize dialog = new TestResize();
dialog.pack();
dialog.setVisible(true);
}
}

That’s it: no more crappy fake panel ! 🙂

Laurent KUBASKI

getResourceAsStream

You think that java.lang.Class.getResource(String name) is the same as java.lang.ClassLoader.getResource(String name) ? Think again…

The javadoc for java.lang.Class.getResource(String name) states that:

Before delegation, an absolute resource name is constructed from the given resource name using this algorithm:

  • If the name begins with a '/' ('\u002f'), then the absolute name of the resource is the portion of the name following the '/'.
  • Otherwise, the absolute name is of the following form: modified_package_name/name where the modified_package_name is the package name of this object with '/' substituted for '.' ('\u002e').

Now compare this with the javadoc for java.lang.ClassLoader.getResource(String name) :

The name of a resource is a ‘/‘-separated path name that identifies the resource

Yes, this means that when using ClassLoader.getResource(String name), the path must NOT start with a ‘/’, and in the end, these 2 statements are similar:

this.getClass().getResource("/sub/file1.properties");

// note that there is no '/':

this.getClass().getClassLoader().getResource("sub/file2.properties");

Laurent KUBASKI

Searching a class in jar files

OK, you need to import a class named “Logger” and you know that it can be found in ones of these 15752 jar files that you have on your hard drive… but which one ?

There are lots of IDE plugins, or even standalone utilities that can help you find the jar that you need, but nothing is faster than using Agent Ransack.

This is the most rapid search software I’ve ever seen. To search for classes in jar files, simple enter “*.jar” as the file name and your class name in the “containing text” field:

Laurent KUBASKI

JTable tips

Here are 2 common requirements when working with Swing’s JTable:

  • validating the editing of a cell without having to hit the “enter” key
  • preventing a JTable to intercept the “enter key” (so that the default button of your dialog is correctly activated)
Here is a little code sample that illustrates these 2 points:
public class TestTable extends JDialog {
  private JTable table;

  public TestTable() {
  super((Frame) null, "The dialog", true);
  setupUI();
  }

  private void setupUI() {
  table = new JTable();
  DefaultTableModel model = (DefaultTableModel) table.getModel();
  model.setColumnIdentifiers(new Object[]{"myColumn"});
  model.addRow(new String[]{"Row 1 (edit me)"});
  model.addRow(new String[]{"Row 2"});
  getContentPane().add(new JScrollPane(table), BorderLayout.CENTER);
  JButton defaultButton = new JButton("default button");
  defaultButton.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
    JOptionPane.showMessageDialog(TestTable.this, table.getValueAt(0, 0));
    }
  });
  getRootPane().setDefaultButton(defaultButton);
  getContentPane().add(defaultButton, BorderLayout.SOUTH);
  }

  public static void main(String[] args) {
    TestTable dialog = new TestTable();
    dialog.pack();
    dialog.setVisible(true);
    System.exit(0);
  }
}

Here is the output:


Now if you click on the first row and if you hit the “enter” key, the focus switches to the next row in the JTable (although you defined the “default button” button to be the default button of your dialog):



Now if you start editing the first cell (replacing “edit me” by “edit ME”) and click on the button, this is what happens:



Damn… why does the message box display the old value ? Well, this is because to validate the edition of a cell in a JTable, you are supposed to hit the “enter” key on your keyboard.
Both problems can be solved by calling this method inside the constructor:
private void changeTableProperties() {
  // now hitting "enter" will trigger the "default button" action:
  // (see source code of JTable.CellEditorRemover.propertyChange() method for more information)
  table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
       .put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "none");
  // now you can click on the button without having to hit "enter" to finish editing the row:
  // see http://download.oracle.com/javase/tutorial/uiswing/misc/keybinding.html for more information
  table.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
  }


From there, hitting the “enter” key will correctly trigger the default button action:



And when editing the cell, you’ll be able to directly click on the button to have your input taken into account (without the need to hit the “enter” key:


Laurent KUBASKI