May 30th, 2009 - Connor Garvey
* I stand corrected. A commenter, Kiran Gunda, says it’s possible to mock f inal methods with JMockIt. I may have set the mock up incorrectly. If I try again, I’ll update this post. Until then, an updated post describes how I used Android test classes to run my code. Matt also pointed out that JMock can mock final methods using JDave’s unfinalizer.
* Updated July 11, 2009 to remove some incorrect information
So that you don’t have to read this whole post, I’ll sumarize what I discovered. If you’re thinking about using a mocking library to mock Android classes, don’t. Android uses interfaces sparsely. That makes a clean API with lots of reusable code, but makes mocking difficult. The real problem, though, is caused by Android’s generous use of final methods. I don’t know of any mocking library that can mock final methods, so you just can’t do it. Instead of writing mocks, look into the android.test and android.test.mock packages.
I developed GreenMileage so that I could learn about the Android OS. Now that I have an understanding of it, I decided to go back and write test cases so that I could continue development using TDD. I started by writing tests for utility classes. That wasn’t a problem. After finishing that, I moved to some simple UI cases. The first was TextViewCallbackListener. I just had to mock TextView.setText(String).
First, I spent hours just trying to get the JMock jars into the project. For some reason, the compiler would not put JMock into the APK. I didn’t get any error message or notification. It just wasn’t there.
I decided to use Android’s test mocks to run my code. Click here to see a simple example.
April 27th, 2009 - Connor Garvey
Green Mileage is now an open source application at Google Code. You can find the full source for most of the Android posts on this site in it at http://code.google.com/p/greenmileage/. Just click the Source tab, then the Browse link.
The code needs a lot of cleanup, but is still probably worth a look if you’re new to Android.
March 21st, 2009 - Connor Garvey
Scroll down for the full source. Today, to execute code asynchronously in JavaFX, the background code must be written in Java. Ideally, your Java code will return JavaFX data types, keeping your FX code clean and helping you be prepared for the day when you won’t need Java.
This is how you can create and return JavaFX sequences from your Java code.
Set the return type of your method to com.sun.javafx.runtime.sequence.Sequence. Many of the com.sun.javafx classes seem to have been created for use in Java code.
@Override
public Sequence<String> call() throws Exception {
In your code, use any type of collection class you like. It’s easiest to use List classes, though, because they can be directly converted.
List<String> names = Arrays.asList("Arthur", "Trillian", "Zaphod");
Then, convert the list to a sequence using com.sun.javafx.runtime.sequence.Sequences and return it.
return Sequences.make(TypeInfo.getTypeInfo(String.class), names);
Here it is all together for impatient people like me.
@Override
public Sequence<String> call() {
List names = Arrays.asList("Arthur", "Trillian", "Zaphod");
return Sequences.make(TypeInfo.getTypeInfo(String.class), names);
}
March 14th, 2009 - Connor Garvey
I’ve been working on a demonstration JavaFX application. It was originaly written for the prerelease candidate. I just updated it to work with JavaFX version 1.1 and thought I’d share it. This is a simple spinner that can be stopped and started. Here’s the full source. A description of how it works is below.
package org.mediabrowser;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.scene.CustomNode;
import javafx.scene.Group;
import javafx.scene.image.ImageView;
import javafx.scene.image.Image;
import javafx.scene.Node;
import javafx.scene.shape.Rectangle;
import javafx.scene.transform.Rotate;
/**
* A spinning icon, indicating the application is working
* @author Connor Garvey
* @created Oct 22, 2008, 8:12:48 PM
* @version 0.0.2
* @since 0.0.1
*/
public class Spinner extends CustomNode {
var rotation: Number = 0;
var timeline: Timeline = Timeline {
repeatCount: Timeline.INDEFINITE;
keyFrames: [
KeyFrame {
time: 50ms
action: tick
}
]
};
public override function create(): Node {
return Group {
content: [
ImageView {
image: Image {
url: "{__DIR__}resources/color_wheel.png"
}
transforms: Rotate {
pivotX: 8
pivotY: 8
angle: bind this.rotation
}
translateX: 3
translateY: 3
},
Rectangle {
width: 22
height: 22
}
]
};
}
public function start() {
this.timeline.play();
}
public function stop() {
this.timeline.stop();
}
function tick() {
this.rotation += 20;
if (this.rotation == 360) {
this.rotation = 0;
}
}
}
- First, the spinner extends CustomNode. That way, it can be placed anywhere in a UI.
- The timeline is used to rotate the spinner
- Since the application will be starting and stopping the spinner, set it to run forever, Timeline.INDEFINITE
- The spinner only does one thing, turn, so it only needs one key frame. It’s set to turn 20 degrees every 50ms.
- JavaFX will call create() to create instances of the spinner
- The __DIR__ makes the spinner image relative to the current class
- Since the image is 16×16, set the rotation pivot point to 8×8, the center of the image
- The angle of rotation is bound to a property of the class so that it can be easily modified
- When an image starts to rotate, it appears to shake because it’s not round. To smooth the rotation out, it’s transformed down and to the right and placed inside of a rectangle.
February 11th, 2009 - Connor Garvey
Spring’s architecture isn’t very friendly to static classes and methods. It doesn’t have any way of injecting static properties of classes because it doesn’t have any way to discover them. Spring’s designers have acknowledged that it’s a shortcoming of the framework and suggest the use of this solution.
- Create the static property of the class without any annotations
- Mark the class to have static properties injected with @Component so that the properties will be injected on Spring startup
- Create a non-static setter method that sets the static property
- Mark the setter method with @Autowired(required = true)
@Component
public class UserUtils
{
private static UserAccessor userAccessor;
/**
* Sets the user DAO. This method should never be called except by Spring
* @param userAccessor The user accessor to set
*/
@Autowired(required = true)
public void setUserAccessor(userAccessor UserAccessor) {
UserUtils.userAccessor = userAccessor;
}
}
Using this technique, you can have all of the advantages of Spring injection without the headaches of Spring injection! Avoid using this technique whenever possible. It should only be used to support legacy applications. With a lot of statically stored values, your application will not scale well.
January 31st, 2009 - Connor Garvey
Assigning an icon to your Android application just takes a minute. Actually creating the icon may take a bit longer. 😛
- Create a 48×48 PNG and drop it into /res/drawable. The name of this file is usually “icon.png”.
- Open your AndroidManifest.xml.
- Right under the root “manifest” node of the XML, you should see the “application” node. Add this attribute to “application”. (The “icon” in “@drawable/icon” refers to the file name of the icon.)
android:icon="@drawable/icon"
Your app is now iconned.
To support multiple resolutions, you can create icons of different resolutions and place them in the correct folders.
- Low density
- res/drawable-ldpi
- 36×36 resolution
- Medium density
- res/drawable-mdpi
- 48×48 resolution
- High density
- res/drawable-hdpi
- 72×72 resolution
- Extra high density
- res/drawable-xhdpi
- 96×96 resolution
January 31st, 2009 - Connor Garvey
A lot of people have found this site by searching for an Android button tutorial, so here it is.
- This tutorial assumes that you already have an activity and are using an XML layout.
- Open the layout XML and add the button element. Assign an ID with the “@+id” operator. The + tells Android to generate an ID for this element so that you can reference it in your Java files.
- This is an example. Your layout and text elements will probably be very different. In this example case, the ID of the button is “close”.
<Button android:id="@+id/close"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:text="@string/title_close" />
- Open the activity class. Add a class property to hold a reference to the button.
- If you haven’t already, override the onCreate method.
@Override
protected void onCreate(Bundle savedInstanceState) {
}
- For this example, we don’t need the saved instance state, so ignore it.
- Now, in the onCreate method, attach a listener to the click event for the button. This example will call “finish()” on the activity, the Android analog of clicking the close button on a window.
protected void onCreate(Bundle savedInstanceState) {
this.setContentView(R.layout.layoutxml);
this.closeButton = (Button)this.findViewById(R.id.close);
this.closeButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
}
- Here’s a short description of what’s happening.
- First, get the button ID. The ID created earlier in the layout, “close”, is compiled by Android and assigned a unique integer ID which is available to the application through the “R” class, which I assume is short for “Resources”.
- Request a reference to the button from the activity by calling “findViewById”. The button has to be retrieved from the activity because while an ID is unique in an activity, it is not unique among all activities.
- Assign the retrieved button to an instance variable so that if you need it later, you can easily find it without having to query for it again.
- Create a class implementing “OnClickListener” and set it as the on click listener for the button.
As UI elements go, buttons are some of the simplest. Later, I’ll write about menus and dialogs, which aren’t so easy.
January 30th, 2009 - Connor Garvey
While working on a project that uses Hibernate, my team was getting a little frustrated while trying to interrogate a tree structure in our data model since all collections are mapped as java.util.HashSets. We wanted a simple function that could print the tree to the log, so I took a free hour and wrote this. It was a little more complicated than I anticipated because it had to handle situations like these.
root
|
|- child
|
|- child
root
|
|- child
|
|- child
and the infamous (to me) …
root
|
|- child
| |
| |- child
| |
| |- child
|
|- child
There’s a subtle difference. Notice that in the middle one, the line for the first child stops because there aren’t any more children, but in the last one, the line continues? I could have created some kind of 2D text buffer and gone back to draw the line, but that would be boring. Here’s what I came up with. I don’t know whether it’s pretty, but it works!
/**
* Creates a tree representation of the node
* @param node The node, which may not be null
* @return A string containing the formatted tree
*/
public static String toStringTree(Node node) {
final StringBuilder buffer = new StringBuilder();
return toStringTreeHelper(node, buffer, new LinkedList<Iterator<Node>>()).toString();
}
private static void toStringTreeDrawLines(List<Iterator<Node>> parentIterators, boolean amLast) {
StringBuilder result = new StringBuilder();
Iterator<Iterator<Node>> it = parentIterators.iterator();
while (it.hasNext()) {
Iterator<Node> anIt = it.next();
if (anIt.hasNext() || (!it.hasNext() && amLast)) {
result.append(" |");
}
else {
result.append(" ");
}
}
return result.toString();
}
private static StringBuilder toStringTreeHelper(Node node, StringBuilder buffer, List<Iterator<Node>>
parentIterators) {
if (!parentIterators.isEmpty()) {
boolean amLast = !parentIterators.get(parentIterators.size() - 1).hasNext();
buffer.append("\n");
String lines = toStringTreeDrawLines(parentIterators, amLast);
buffer.append(lines);
buffer.append("\n");
buffer.append(lines);
buffer.append("- ");
}
buffer.append(node.toString());
if (node.hasChildren()) {
Iterator<Node> it = node.getChildNodes().iterator();
parentIterators.add(it);
while (it.hasNext()) {
Node child = it.next();
toStringTreeHelper(child, buffer, parentIterators);
}
parentIterators.remove(it);
}
return buffer;
}
January 27th, 2009 - Connor Garvey
I just started using Terracotta for the first time. This is how I put it in my project and configured Ant tasks to start and stop the server. The client is using Windows, so the Ant tasks work in Windows.
- Create tc-config.xml in the root of the project.
<?xml version="1.0" encoding="UTF-8"?>
<con:tc-config xmlns:con="http://www.terracotta.org/config">
<servers>
<server host="%i" name="localhost">
<dso-port>9510</dso-port>
<jmx-port>9520</jmx-port>
<data>bin/terracotta/server-data</data>
<logs>bin/terracotta/server-logs</logs>
<statistics>bin/terracotta/cluster-statistics</statistics>
</server>
<update-check>
<enabled>true</enabled>
</update-check>
</servers>
<clients>
<logs>bin/terracotta/client-logs</logs>
<statistics>bin/terracotta/client-statistics/%D</statistics>
<modules>
<module name="tim-hibernate-3.2.5" version="1.2.2"/>
<module name="tim-ehcache-1.3" version="1.2.2"/>
<module name="tim-cglib-2.1.3" version="1.2.2"/>
<module name="tim-ehcache-commons" version="1.2.2"/>
</modules>
</clients>
</con:tc-config>
- Put Terracotta into your library directory. You’ll need bin, docs, lib and schema directories and the license files.
- You don’t need the licenses for the software to work, but it’s always a good idea to include them, especially if your app is not open source 😛
- Create the Ant targets.
<target name="start.terracotta.windows">
<exec executable="cmd">
<arg value="/c"/>
<arg value="lib\terracotta-2.7.2\bin\start-tc-server.bat"/>
</exec>
</target>
<target name="stop.terracotta.windows">
<exec executable="cmd">
<arg value="/c"/>
<arg value="lib\terracotta-2.7.2\bin\stop-tc-server.bat"/>
</exec>
</target>
- Notice the backslashes there. Normally, Ant will convert forward slashes to backslashes in Windows. Since this is a command line argument, though, it doesn’t. If you’re running on both *nix and Windows, you’ll have to have two versions of the paths, one with forward and one with back slashes.
- That’s it. Run the start task to start and the stop task to stop.
January 25th, 2009 - Connor Garvey
This is part 2 of this tutorial. Click here to see part 1.
- You should have two shapes in Inkscape.
- Now, you have to get these into the GIMP. The easiest way is to take a screen shot. To do that, in GIMP, go to File -> Acquire -> Screen Shot. Take two shots. Crop one to the shadowed image and the other to the black and white.
- Pick the shadowed image and add an opaque layer mask. View the Layers dialog. Right click the “Background” layer and click Add Layer Mask…
- Pick the black and white image. Select the entire image and copy it.
- Pick the shadowed image and in the layers dialog, click on the mask, to the right of the image.
- Pick the shadowed image and paste. You should see something like the image below. Pick the move tool and drag the mask around until it exactly matches the shadowed arrow.
- Now, crop the image to the arrow shape.
- Right click on the floating layer and anchor it.
- Right click on the mask layer and apply it.
- Now, just save it! Remember to save it as a PNG so that the empty parts are transparent.
I hope this helps anyone else who needs more than the standard Android icons.
More updates:
Will S. created a wireless icon.
Great tutorial, and very easy to follow, thanks.
I made a wifi icon, which can be found here:
http://digitalsquid.co.uk/files/2009/08/wifiicon.png
(you can use it if you want)