We have a View that we want centered on the screen, but that must scroll when there isn't enough room to show the view fully (for example, when the keyboard is up).
Our first attempt:
<ScrollView
android:layout_width=...
android:layout_width=...
>
<View
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
/>
</ScrollView>
We spent some time trying to figure out why some html content would not load in our app's WebView. We found trivial html can be loaded into a WebView using the loadData(String, String, String) method. Rendering complex pages with Javascript is a problem. It turns out the loadData() method requires the html to be URI escaped (RTFM? Bah!). There are additional characters that need to be escaped too, requiring some nasty boilerplate.
The simpler solution (workaround?) is to use loadDataWithBaseURL(String, String, String, String, String). Calls to this method do not require escaping. Pass along a garbage base url (or null), and an empty or null history url for success and profit.
webView.loadDataWithBaseURL("blarg://ignored", getData(), "text/html", "utf-8", "");
We have been doing quite a bit of Android development over the last year and a half at Pivotal Labs. Over time we have compiled a set of go-to tools, and libraries, and configuration settings that help make our development process as productive as possible. We are excited to publish two open source projects, each with the goal of helping new Android development projects hit the ground running: Android IntelliJ Starter and Android CI.
Using a VideoView to play streaming videos is quite easy on Android, and the class provides handy callbacks to manage your UI too. For example:
// set the Uri of the video
videoView.setVideoURI(Uri.parse(videoUriString));
// start streaming/playing the video
videoView.start();
videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
// about to start playing
}
});
videoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
// reached the end of the video
}
});
VideoViews can be embedded into your layouts and sized any way that you'd like. However, there is one serious limitation.
According to Romain Guy, SurfaceViews (such as VideoView, etc.) inside ScrollViews (or ListView, etc.) are not supported by Android.
For example, playing a video using a VideoView inside of a row of a ListView seems to work at first, until the user tries to scroll the list. As soon as the list starts to scroll, the video turns black. It keeps playing in the background but you can't see it anymore because it renders the rest of the video as a black box.
As another example, when the VideoView is scrolled so that it is partially off-screen at the time that the video starts playing, the VideoView does not render the video in the correct location on screen, causing the video to appear mostly black.
So be careful where you decide to put your VideoViews. At first it seems that they can go anywhere, but they cannot.
Sure, you can launch your Android app in IntelliJ's debugger, but that's slow. IntelliJ allows you to dynamically attach the debugger to a running device using the "Attach debugger to Android process" button. That's fast!


Pivotal Android Tabs
We have published a simple Android project that illustrates how to use tabs in an Android app: TabActivity, TabHost, TabWidget, and android:divider. Thank you Pivot Ryan, the original author, for taking the time to write and open source this. Check it out, fork it, and enjoy -- https://github.com/pivotal/Pivotal-Android-Tabs


See Hex'd Colors
IntelliJ trick: in a colors.xml file, place your cursor on a hex value and hold down Shift. You'll see a large preview of the color.

Colors and States
(Repost from the 6/22/2011 Standup blog): You can use a selector drawable to set Android text color for the various states (focused, selected, etc.) using a drawable xml file. IntelliJ will complain and say this is invalid syntax but the application will use the file as you would expect. This only seems to work for the android:textColor attribute in TextViews.
Android ListView#addHeaderView and ListView#addFooterView methods are strange: you have to add the header and footer Views before you set the ListView's adapter so the ListView can take the headers and footers into consideration -- you get an exception otherwise. Here we add a ProgressBar (spinner) as the headerView:
// spinner is a ProgressBar
listView.addHeaderView(spinner);
We'd like to be able to show and hide that spinner at will, but removing it outright is dangerous because we'd never be able to add it again without destroying the ListView -- remember, we can't addHeaderView after we've it's adapter:
listView.removeHeaderView(spinner); //dangerous!
So let's hide it! Turns out that's hard, too. Just hiding the spinner view itself results in an empty, but still visible, header area.
C2DM Unregister Issues
It turns out when you follow the client-side C2DM unregistration process, this does not guarantee that those registration tokens are permanently unregistered for that device.
If we unregister as specified above and then send a push notification to that registration_id, the server receives an Error=NotRegistered as expected.
But, unexpectedly, when that device re-register with C2DM (and getting a new registration_id), the old registration_id is reactivated as well and can receive push notifications and does not result in a server-side Error=NotRegistered.
The end result: we implemented our server-side API to take both the new and old registration_ids when the Android client successfully registers with C2DM, allowing us to manually delete the old registration_id.
Drawable XML Files
Prefixing the name of a drawable xml file with "active_" seems to prevent android from using that drawable at all.
Web development spoiled me. Set the src tag on an img tag and away you go. For the most part, browsers just do the right thing and cache these requests. Disappointingly, Android does not come with out of the box support for caching content downloaded from the network. Server apis often require SSL, request headers, support for different HTTP methods, multipart post bodies, etc. requiring the use of the apache http client libraries. These libraries are powerful, but are a bear to work with. As far as I can tell there is no support for caching http responses built into the apache libraries, requiring that you roll your own caching scheme. Images often do not have all these complicated HTTP requirements. They're usually simple HTTP GET calls. This makes the java.net.* libraries appealing. The java.net libraries come with some handy classes that makes caching a breeze.
During a typical day of Android development we compile Android applications (.apk files) dozens of times, deploying to emulators and devices simply by pressing the Run button in IntelliJ. This is great for our in-office developers, but it's more difficult for our remote-pairing developers to install those same .apks on their own emulators and phones. As a remote developer, I wanted seamless, instant access to all .apks we build during development. Using Dropbox and some IntelliJ configuration changes I now have all .apks we build available for me to install on my local emulators and phones just seconds after we build them on our development machines, 2500 miles away.
