Digital archives contain as usually understood by professional archivists and historians.
From the Bramble Hill Farm Website:
The Farm shares a border with The Hitchcock Center (an Environmental Education Center) and the Common School ( a private K – 6 elementary school with a curriculum based on “in-depth studies and experiential learning”). Amherst College maintains several hundred acres of pasture land across Rt. 116 from the Farm, and the Town Conservation Commission maintains land along another Border. In 2004 the Larch Hill Collaborative was formed, with Bramble Hill Farm at the center, to bring these entities together into a working group around shared concerns for the sustainability of the land and the ecosystems which form the core of all of our individual work. The Farm welcomes projects and classes from The Hitchcock Center, The Common School, and other groups interested in learning about and creating from its’ diverse resources.
Back in December, the Android Dev Phone 1 (ADP1) went on sale, giving developers access to unlocked hardware for their work. A few weeks ago, consumers with retail devices received an over the air update with the 1.1 release of Android. I know that many developers will be pleased to hear that today, our colleagues at HTC have released a 1.1 version of Android for the Android Dev Phone which you can install on your device. If you have questions about the process of updating your device, you can ask the mailing list we've set up for such questions.
This new system image is fully compatible with Android 1.1. To see a list of everything that's new, you can review the notes from the 1.1_r1 SDK. This update also includes support for searching by voice, and priced apps in the Android Market.
Some developers have asked about the support for copy-protected apps on developer devices, and indeed there is a limitation you should be aware of. Many developers are concerned about the unauthorized redistribution of their applications, so they make use of the copy-protection feature (known as "forward locking") which prevents applications from being copied off devices. However, developer phones like the ADP1 allow for unrestricted access to the device's contents, making it impossible to enforce copy protection. As a result, the Market application on such devices is not able to access copy protected apps, whether they are free or paid. If you choose to add copy protection when you upload your application to the Android Market, then you won't be able to test it on the ADP1's Android Market client. Your application will always be accessible to users who have standard configurations though, and if your application (whether it is free or paid) is not copy-protected it will appear on all devices, including developer configurations.
If you own an Android Developer Phone, I definitely suggest you take advantage of this update. There's lots of good stuff in there, and the new software is backward compatible with Android 1.0, too. The original 1.0 system image is also now available, you need to downgrade for any reason. Happy coding!
Some Android applications require to squeeze every bit of performance out of the UI toolkit and there are many ways to do so. In this article, you will discover how to speed up the drawing and the perceived startup time of your activities. Both these techniques rely on a single feature, the window's background drawable.
The term window background is a bit misleading however. When you setup your user interface by calling setContentView()
on an Activity, Android adds your views to the Activity
's window. The window however does not contain only your views, but a few others created for you. The most important one is, in the current implementation used on the T-Mobile G1, the DecorView
, highlighted in the view hierarchy below:
The DecorView
is the view that actually holds the window's background drawable. Calling getWindow().setBackgroundDrawable() from your Activity
changes the background of the window by changing the DecorView
's background drawable. As mentioned before, this setup is very specific to the current implementation of Android and can change in a future version or even on another device.
If you are using the standard Android themes, a default background drawable is set on your activities. The standard theme currently used on the T-Mobile G1 uses for instance a ColorDrawable. For most applications, this background drawable works just fine and can be left alone. It can however impacts your application's drawing performance. Let's take the example of an application that always draws a full screen opaque picture:
You can see on this screenshot that the window's background is invisible, entirely covered by an ImageView
. This application is setup to redraw as fast as it can and draws at about 44 frames per second, or 22 milliseconds per frame (note: the number of frames per second used in this article were obtained on a T-Mobile G1 with my finger on the screen so as to reduce the drawing speed which would otherwise be capped at 60 fps.) An easy way to make such an application draw faster is to remove the background drawable. Since the user interface is entirely opaque, drawing the background is simply wasteful. Removing the background improves the performance quite nicely:
In this new version of the application, the drawing speed went up to 51 frames per second, or 19 milliseconds per frame. The difference of 3 milliseconds per is easily explained by the speed of the memory bus on the T-Mobile G1: it is exactly the time it takes to move the equivalent of a screenful of pixels on the bus. The difference could be even greater if the default background was using a more expensive drawable.
Removing the window's background can be achieved very easily by using a custom theme. To do so, first create a file called res/values/theme.xml
containing the following:
<resources>
<style name="Theme.NoBackground" parent="android:Theme">
<item name="android:windowBackground">@null</item>
</style>
</resources>
You then need to apply the theme to your activity by adding the attribute android:theme="@style/Theme.NoBackground"
to your <activity />
or <application />
tag. This trick comes in very handy for any app that uses a MapView
, a WebView
or any other full screen opaque view.
Opaque views and Android: this optimization is currently necessary because the Android UI toolkit is not smart enough to prevent the drawing of views hidden by opaque children. The main reason why this optimization was not implemented is simply because there are usually very few opaque views in Android applications. This is however something that I definitely plan on implementing as soon as possible and I can only apologize for not having been able to do this earlier.
Using a theme to change the window's background is also a fantastic way to improve the perceived startup performance of some of your activities. This particular trick can only be applied to activities that use a custom background, like a texture or a logo. The Shelves application is a good example:
If this application simply set the wooden background in the XML layout or in onCreate()
the user would see the application startup with the default theme and its dark background. The wooden texture would only appear after the inflation of the content view and the first layout/drawing pass. This causes a jarring effect and gives the user the impression that the application takes time to load (which can actually be the case.) Instead, the application defines the wooden background in a theme, picked up by the system as soon as the application starts. The user never sees the default theme and gets the impression that the application is up and running right away. To limit the memory and disk usage, the background is a tiled texture defined in res/drawable/background_shelf.xml
:
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@drawable/shelf_panel"
android:tileMode="repeat" />
This drawable is simply referenced by the theme:
<resources>
<style name="Theme.Shelves" parent="android:Theme">
<item name="android:windowBackground">@drawable/background_shelf</item>
<item name="android:windowNoTitle">true</item>
</style>
</resources>
The same exact trick is used in the Google Maps application that ships with the T-Mobile G1. When the application is launched, the user immediately sees the loading tiles of MapView
. This is only a trick, the theme is simply using a tiled background that looks exactly like the loading tiles of MapView
.
Sometimes the best tricks are also the simplest so the next time you create an activity with an opaque UI or a custom background, remember to change the window's background.
In the previous installment of Android Layout Tricks, I showed you how to use the <include />
tag in XML layout to reuse and share your layout code. I also mentioned the <merge />
and it's now time to learn how to use it.
The <merge />
was created for the purpose of optimizing Android layouts by reducing the number of levels in view trees. It's easier to understand the problem this tag solves by looking at an example. The following XML layout declares a layout that shows an image with its title on top of it. The structure is fairly simple; a FrameLayout is used to stack a TextView on top of an ImageView:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ImageView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scaleType="center"
android:src="@drawable/golden_gate" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="20dip"
android:layout_gravity="center_horizontal|bottom"
android:padding="12dip"
android:background="#AA000000"
android:textColor="#ffffffff"
android:text="Golden Gate" />
</FrameLayout>
This layout renders nicely as we expected and nothing seems wrong with this layout:
Things get more interesting when you inspect the result with HierarchyViewer. If you look closely at the resulting tree you will notice that the FrameLayout
defined in our XML file (highlighted in blue below) is the sole child of another FrameLayout
:
Since our FrameLayout
has the same dimension as its parent, by the virtue of using the fill_parent
constraints, and does not define any background, extra padding or a gravity, it is totally useless. We only made the UI more complex for no good reason. But how could we get rid of this FrameLayout
? After all, XML documents require a root tag and tags in XML layouts always represent view instances.
That's where the <merge />
tag comes in handy. When the LayoutInflater encounters this tag, it skips it and adds the <merge />
children to the <merge />
parent. Confused? Let's rewrite our previous XML layout by replacing the FrameLayout
with <merge />
:
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<ImageView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scaleType="center"
android:src="@drawable/golden_gate" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="20dip"
android:layout_gravity="center_horizontal|bottom"
android:padding="12dip"
android:background="#AA000000"
android:textColor="#ffffffff"
android:text="Golden Gate" />
</merge>
With this new version, both the TextView
and the ImageView
will be added directly to the top-level FrameLayout
. The result will be visually the same but the view hierarchy is simpler:
Obviously, using <merge />
works in this case because the parent of an activity's content view is always a FrameLayout
. You could not apply this trick if your layout was using a LinearLayout
as its root tag for instance. The <merge />
can be useful in other situations though. For instance, it works perfectly when combined with the <include />
tag. You can also use <merge />
when you create a custom composite view. Let's see how we can use this tag to create a new view called OkCancelBar
which simply shows two buttons with customizable labels. You can also download the complete source code of this example. Here is the XML used to display this custom view on top of an image:
<merge
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:okCancelBar="http://schemas.android.com/apk/res/com.example.android.merge">
<ImageView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scaleType="center"
android:src="@drawable/golden_gate" />
<com.example.android.merge.OkCancelBar
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:paddingTop="8dip"
android:gravity="center_horizontal"
android:background="#AA000000"
okCancelBar:okLabel="Save"
okCancelBar:cancelLabel="Don't save" />
</merge>
This new layout produces the following result on a device:
The source code of OkCancelBar
is very simple because the two buttons are defined in an external XML file, loaded using a LayoutInflate
. As you can see in the following snippet, the XML layout R.layout.okcancelbar
is inflated with the OkCancelBar
as the parent:
public class OkCancelBar extends LinearLayout {
public OkCancelBar(Context context, AttributeSet attrs) {
super(context, attrs);
setOrientation(HORIZONTAL);
setGravity(Gravity.CENTER);
setWeightSum(1.0f);
LayoutInflater.from(context).inflate(R.layout.okcancelbar, this, true);
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.OkCancelBar, 0, 0);
String text = array.getString(R.styleable.OkCancelBar_okLabel);
if (text == null) text = "Ok";
((Button) findViewById(R.id.okcancelbar_ok)).setText(text);
text = array.getString(R.styleable.OkCancelBar_cancelLabel);
if (text == null) text = "Cancel";
((Button) findViewById(R.id.okcancelbar_cancel)).setText(text);
array.recycle();
}
}
The two buttons are defined in the following XML layout. As you can see, we use the <merge />
tag to add the two buttons directly to the OkCancelBar
. Each button is included from the same external XML layout file to make them easier to maintain; we simply override their id:
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<include
layout="@layout/okcancelbar_button"
android:id="@+id/okcancelbar_ok" />
<include
layout="@layout/okcancelbar_button"
android:id="@+id/okcancelbar_cancel" />
</merge>
We have created a flexible and easy to maintain custom view that generates an efficient view hierarchy:
The <merge />
tag is extremely useful and can do wonders in your code. However, it suffers from a couple of limitation:
<merge />
can only be used as the root tag of an XML layout<merge />
, you must specify a parent ViewGroup
and you must set attachToRoot
to true
(see the documentation of the inflate() method)In the next installment of Android Layout Tricks you will learn about ViewStub
, a powerful variation of <include />
that can help you further optimize your layouts without sacrificing features.