More nice Android bits

April 14, 2011, 6:59 am

I am going to talk about Android dev tonight at at GTUG, so I thought I thought I would write down a few other things about Android that are nice.

Slipstream releases

This is the obvious one. It is great not having the pressure when you submit an update, that you will have to agonised about re-submitting for every bug you find in the next fortnight. There is never a time I am not waiting for an app to be approved. I am waiting right now.

Notifications

One of the rare bits of UI on Android where the experience is far better than the iPhone equivalent. True for the user and true for developers adding notifications to their apps.

You have to deal with a bunch of cases when adding push/local notifications to an iPhone app (in the app, background, suspended, local, push) and your UI is pretty inconsistant. On Android you declare yourself a BroadcastReceiver in the manifest and have a single point to handle 'cloud to device' messages. You have complete control over your UI, but I recommend using the NotificationManager to get the standard pull down message UI:

NotificationManager nm = (NotificationManager) m_context.getSystemService(Context.NOTIFICATION_SERVICE); String text = "Stuff in the notification; Notification n = new Notification(R.drawable.notification, text, System.currentTimeMillis()); n.setLatestEventInfo(m_context.getApplicationContext(), "Message Title", text, getIntentForNotificationTap()); nm.notify(YOUR_NOTIFICATION_ID, n);

Testing GPS

Testing GPS updates in the simulator for iPhone is pretty limited. If you want to send location updates to your app, you are basically reduced to hacking into the simulator binaries and hooking the appropriate libraries, so ... not so much. I spent a lot of time on trains testing my location stuff on the iPhone. On Android you can telnet to the emulator and set it's location on the command line (there has to be something nice about that thing):

$ telnet localhost 5554 geo fix <longitude> <latitude>

Permalink - Comments - Tags: Development,Android,Google

Showing Android resources some love

April 13, 2011, 12:42 pm

I have ranted at length on some of the shortfalls I have found with Android development, particularly when compared with my iPhone exploits. However, there are some things about Android dev that I love, so I thought it was time I talked about them.

If you have done much iPhone development you will be pretty familiar with laying out UI in Interface Builder, or if you are one of those ''XIBs are the work of Satan'' guys, then laying out your UI in code. Either way it can get pretty hairy, pretty quickly. In IB you struggle with entering layout through the UI and in code you end up with your UI metrics spread across multiple source files.

Android has a much better solution to UI definition. If you are a web developer, you will find the XML layout definition language pretty familiar. All your UI is nicely contained in source control friendly, well structured XML files.

Let''s say I want to arrange a couple of text views and a custom button view vertically down the page:

<LinearLayout android:layout_width="1px" android:layout_weight="1" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:text="Some bold heading type text" android:layout_weight="1" android:layout_width="fill_parent" android:layout_height="wrap_content" android:padding="10dp" android:textSize="16sp" android:textStyle="bold" android:textColor="@android:color/black"/> <TextView android:text="Some regular text" android:id="@+id/detail" android:layout_weight="1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="10dp" android:textSize="14sp" android:textColor="@android:color/black"/> <Button style="@style/Button" android:id="@+id/something_funky_button" android:text="Ow! Too Funky!" android:layout_height="88dp"> </Button> </LinearLayout>

A couple of things to notice about this snippet:

  • Define ids on your views so you can get to them from your code with View.findViewById. All the properties you can define here can be played with from the View subclass. So you have complete control over how things are laid out at design and runtime.
  • Padding, layout widths, heights, etc work predictably and intuitively. This makes scaling your app for various devices work out of the box most of the time.
  • The style attribute on the Button element refers to a separate style resource, so you can define commonly used UI elements in a single XML file and use it in all your layouts:
<style name="Button"> <item name="android:textSize">18sp</item> <item name="android:textColor">@color/button_text</item> <item name="android:textStyle">bold</item> <item name="android:padding">5sp</item> <item name="android:background">@drawable/button</item> <item name="android:layout_width">fill_parent</item> <item name="android:layout_height">wrap_content</item> </style>

I have just scratched the surface of what you can do here in your Android project''s resource directory, but it is all pretty awesome stuff.

Permalink - Comments - Tags: Development,Android,Google

What's wrong with Google Maps development on Android - Part Three

April 13, 2011, 7:37 am

Update 5th December 2012 - Android Maps v2

Another sentence from the MapActivity documentation that causes developer pain:

"Only one MapActivity is supported per process. Multiple MapActivities running simultaneously are likely to interfere in unexpected and undesired ways."

This means one MapActivity subclass per Android process and therefore, only one MapView onscreen at any one time. This might not seem like a big deal, but there are times when you would like to have two maps on view at a time. A good example is my WW2 Daily app which lets you swipe locations (and their associated maps) on screen in a scrollview:

To implement this on Android I am going to have to layout image views around my map view and, as the user swipes, replace the adjacent images with a screenshot of the map view, then swap the image view and the map view in the hierarchy. So this is do-able, but compared to keeping multiple map views, a massive pain.

Based on the some of the questions on StackOverflow, this is not a unique gripe with the API (check out the this truly horrible workaround for the issue. Sticking your second map activity in a separate process? ouch!).

This rant continues:

Permalink - Comments - Tags: Development,Android,Google

What's wrong with Google Maps development on Android - Part Two

April 13, 2011, 7:05 am

Update 5th December 2012 - Android Maps v2

A smaller issue with the Android maps library, but worth mentioning

When I started doing web development with the Google Maps API six years ago, it required an API key. You associated it with your domain and prevented naughty people from doing bad things with the API.

Times have changed. With version three, the key went away. The API was infinitely more awesome than the old one, and this was one tiny part of that. The old key was a little irritating if you had to move code between domains, so not having to worry about it made things that much easier for developers.

"The android:apiKey attribute holds the Maps API Key for your application, which proves your application and signer certificate has been registered with the Maps service. This is required in order to receive the map data, even while you are developing.

So you grab your Maps API key by taking an md5 hash of your signing certificate and submitting it to Google to get your key. There are a couple of things that make this annoying for developers:

  • When you are debugging your application you use the SDK debug certificate, so you will need a different Google Maps key for your dev build.
  • If you are building multiple applications from the same source code, then you are going to have to make sure you have an API key for each one and conditionally compile them in.

Admittedly these are pretty minor irritations, but when you consider that neither the iPhone MapKit or the web API require a key (and I realise there are technical differences here), it seems like an unnecessary one.

This rant continues:

Permalink - Comments - Tags: Development,Android,Google

What's wrong with Google Maps development on Android - Part One

April 12, 2011, 12:23 pm

Update 5th December 2012 - Android Maps v2

This rant is coming from an unabashed Google fanboy. I have always loved Google as a company and the maps API in particular. I write this in the hope that it will help Android become a better place for developers like me.

Also, all the hard work for this post was done by Nick Maher. He blazed the Android development trail for me and most of the insights in this post are his. Some of the hoops that he has jumped through makes Tripview for Android even more impressive.

This fairly inocuous sentence in the Hello MapView tutorial hides a nasty underlying problem with the Google Maps library:

This is a special sub-class of Activity, provided by the Maps library, which provides important map capabilities.

Basically it means if you want to display a google map inside an activity in Android, you need to derive from the MapActivity class. So this isn't so bad right? Well maybe not.

What if you have an activity, GenericToolboxActivity, that does a bunch of different things, one of which involves displaying a map? Forcing GenericToolboxActivity to derive from MapActivity seems kinda dumb.

You can get around that problem by sticking your MapActivity in a LocalActivityManager. The LocalActivityManager is basically a sandbox for your activity. You stick your MapActivity subclass, let's call her JealousSpouseMapActivity, in your LocalActivityManager and gently prod her until she gives up that MapView object that you so desire:

// set up the LAM m_lam = new LocalActivityManager(this, true); // stick the map activity in the LAM Intent intent = new Intent(this, JealousSpouseMapActivity.class); m_lam.dispatchCreate(null); m_lam.dispatchResume(); m_lam.startActivity("map", intent); m_mapActivity = (JealousSpouseMapActivity)m_lam.getActivity("map"); // the view please? return m_mapActivity.getWindow().getDecorView(); // Once I am finished with the view, clean it up m_lam.dispatchPause(true); m_lam.dispatchDestroy(true);

You are essentially lulling your JealousSpouseMapActivity into a false sense of security:

Dear JealousSpouseMapActivity, I would never re-parent any of your stuff. That would be wrong. Put your feet up and relax, i'll just need a pointer to your MapView before I pop off and get you breakfast in bed.

Once you have the MapView you can stick it in your view heirachy for your generic activity and JealousSpouseMapActivity is none the wiser. So why can't this stuff just be done in a MapView class instead? According to the MapActivity documentation its responsibilities include:

  • Activity lifecycle managment - So presumably most activities need to manage their lifecycle, so I wonder how much map specific stuff is done here.
  • Setup and teardown of services behind a MapView - Hrm. If we can have a WebView object that does requests in the background, fairly complex rendering and all sorts of other magical things, I wonder why we can't have a MapView that does the same. What is so "special" about a map that makes it impossible to implement as a view subclass.

In fact thinking about WebView brings up another argument against implementing the map this way. What if our helpful and friendly WebView had some kind of mental break and turned into AngryExGirlfriendWebActivity? What if we had to derive activies that show web content from AngryExGirlfriendWebActivity? If we want to show web and map content at the same time, basically we are screwed, we can't derive from them both. I guess we could try and stick both AngryExGirlfriendWebActivity and JealousSpouseMapActivity into a LocalActivityManager and then gently ask them to give up their respective view goodness, but I can't imagine that is going to end well.

Ok, Perhaps I have taken this analogy a little too far, but you get the idea.

This rant continues:

Permalink - Comments - Tags: Development,Android,Google