Beginning Android for iOS Developers; or, How to Build a Real-World Android App

Comparison

That's my baby, Brocabulary. She was my first, way back in 2009. Yeah, I know, she's a little silly, but she's not that complicated:
  • Display a list of items loaded from the filesystem
  • Display a list of downloaded items
  • Display a list of favorited items
  • Show a detail display when an item is tapped
  • Upload a new item

Pretty much the bread and butter of CRUD apps. And guess what? I'm going to show you how to make it.

Table of Contents

Part 1: Overview

Part 2: Tools; or, get up on my API Level

Part 3: Activities; or, getting your Vibrams Five Fingers wet

Part 4: ListActivities; or, "Why are table view chapters always so long?"

Part 5: Files and Objects; or, I prefer JSON Bateman's early work

Part 6: HTTP Requests; or, "Oh, you have to download that? Put it on my Tab."

Part 7: HTTP Requests Part Deux; or, "It's my Intent to be POSTed up right here"

Part 8: Files and Objects Part Deux; or, I prefer my breakfast with Serial

Part 9: Preparing for the Market; or, "Wow, this is actually really easy"

Appendix: Source on Github

NOTE: It was my original intention for these to be a series of articles targeted at iOS developers who wanted to start porting their apps to Android; however, it became apparent that these tutorials are actually useful for anyone wanting to get started making Android apps. There's still a lot of useful information for iOS developers (I name drop a lot of UIKit classes and expain their counterparts in the Android SDK), but I'm confident that anyone can pick up these articles and making something awesome.

With that in mind:

Click to continue to Part 1: Overview

Beginning Android for iOS Developers - Part 1: Overview

(NOTE: while a lot of my bad jokes prose is targeted at iOS developers, other mortals will find these equally as useful. On with the show...)

You've just built an iOS app. You bit the bullet and downloaded the SDK, paid Apple its $99 developer fee, learned Cocoa and Objective-C, made some provisioning profiles, and out came an App that Apple now holds for a week or so with many others somewhere in Cupertino before being released into the Conradian jungle that is the App Store. You wonder...is this it? 

The answer is no Julian Casablancas, this isn't it. There are, in fact, several other mobile operating systems you can wine and dine, and they are diverse as they are numerous (see: moderately). 

Yet, you already know that don't you? Like any Michael Bay movie, let's cut to the chase: moving on to Android. It's the talk of the town, the belle of the ball, the little engine that could, I can go on for minutes. If you're going to write Apps on something besides iOS devices, you should probably start with Android.

Sadly, I've been trying to do this for far too long. I kept putting learning Android off because no one had written a resource for us iOS developers on how to start swinging both ways. Well, I finally got some time to sit down, shut up, and get to it. Here are the results:

Comparison
That's my baby, Brocabulary. She was my first, way back in 2009. Yeah, I know, she's got a little bit of crazy, but she's really not that complicated:
  • Display a list of items loaded from the filesystem
  • Display a list of downloaded items
  • Display a list of favorited items
  • Show a detail display when an item is tapped
  • Upload a new item

Pretty much the bread and butter of CRUD apps. I figure it's a pretty good starting point for 80% of whatever you're looking for, so why not just write about how I made it? Sound good?

Click to continue to Part 2: Tools; or, get up on my API Level

Beginning Android for iOS Developers - Part 2: Tools; or, get up on my API Level

Now that you know where we're going, let's...get there? You're going to need to download some things:

1. Android SDK - http://developer.android.com/sdk/index.html

Unzip it and store it somewhere meaningful, like /Developer. Right now it isn't awfully big because there aren't actually any source files in there, but that's where they'll go when we download them. What you actually downloaded was the just tools needed to download and manage the various SDK APIs, so you're not quite ready to develop just yet.

2. Something with which to develop

This is up to you. Many developers opt to use Eclipse, for which Google supplies a nifty plugin, but you're just as fine developing with emacs and using the command line tools provided with Android (which I won't cover in these tutorials). You might also want to consider the TextMate bundle by One Bit Increment, if you're into that kind of thing. Not that there's anything wrong with that.

Now that you're set up, let's download something useful. We do this using the "Android SDK and AVD Manager", a GUI tool Google provides with the SDK download. You can either launch this by going to Window -> Android SDK... in Eclipse or running the "android" executable in /<your SDK Path>/tools.

Androidmanager
This is what you use to manage your SDK packages and virtual devices (more on that in one hot minute), so you best get familiar with it.

Go to "Available Packages". There will probably be two branches: "Android Repository" and "Third party Add-ons." The former is the main branch of the Android SDK, where all of the core API levels are kept. These are the minimum things you need to get to make an app. Third party add-ons are where non-required APIs, such as Google's add-ons (primarily for Maps) or device-specific libraries, are kept.

Expand the main Android repository to browse all of the available packages. Android Platforms are organized into "API Levels" corresponding to each OS version (OS 1.5 == Level 3, OS 1.6 == Level 4, etc). For each API level you'll see not only the actual SDK but also samples and documentation. You'll also see revisions of the SDK Tools and Platform-tools...I'm really not sure about the difference between the two but you'll need those as well.

Androidmanager2
You might as well go and download everything, but if you're trying to save time like Marty McFly then I'd suggest SDKs levels 3 to 7. I'll be using SDK level 7 in these tutorials (Android 2.1). It might ask you to restart the Manager a few times, that's normal, but it'll also cut off your in-progress downloads so make sure you resume those when it restarts.

Let's also set up some emulators while we're here. You know how the iOS Simulator lets you use different hardware and OS versions, but they're all enclosed in the same program? Well...Android works quite a bit differently. You have to create different "virtual devices" for different kinds of devices, and there are all kinds of properties you can add or remove: internet connection, SD card slot, pixel density, resolution, etc etc. So, congratulations: your first encounter with Android fragmentation!

Go to "Virtual Devices" and hit "New". Call it what you like, but I would suggest adding the OS version somewhere in the name for future readability. Target it for API Level 7. Add a New hardware type and keep all the default settings. Feel free to examine all of the possible options if you want to momentarily feel bewildered.

Androidmanager3
*WHEW* That was pretty fun, right? Right? Regardless, good hustle. We'll Mark Pilgrim into proper Android development in the next portion.

 

Beginning Android for iOS Developers - Part 3: Activities; or, getting your Vibrams Five Fingers wet

You've got the tools set up, so let's start some actual code. Somehow, create a new Android project. In Eclipse, do this by using the default Android Project template. You can name it whatever you want, select Android 2.1 as the target SDK, and give it whatever application and package names you want. The package naming scheme is the same as the iOS bundle naming scheme, so something relevant like com.clayallsopp.isawesome. 

The Eclipse wizard will also let you create the main Activity (one hot minute and I'll explain); go ahead and name it OfflineListActivity. If you're not using Eclipse, you want to create a file called OfflineListActivity.java in the /src/<package path> folder of your Android project.

Finish whatever wizard you use and BAZINGA! Your first Android app :) Except...holy crap, what did you create? There are...so many folders and XML files. Well, let's throw caution to the wind and drop some code before I give a big long list of files and folders. 

If you go into your /src folder, you should see OfflineListActivity.java. It should look something like this:

Our OfflineListActivity extends (subclasses) Activity, which is the equivalent of a UIViewController in Android-land; accordingly, onCreate is effectually the same as viewDidLoad. We call the superclass's implementation and then do something a bit magical: setContentView(R.layout.main).

You can probably figure out what setContentView means, but what the hell is R.layout.main? Well, whenever you build your Android project, a file called R.java is built (you can find it in your /gen folder). It stores variables which allow you to access resources included with your project. So instead of traversing the bundle or doing a [UIImage imageNamed:], you use the variables created in R.java. Savvy? 

Resources in R.java are in a hierarchy that is directly correlated to their structure in your project file system; thus, R.layout.main refers to the resource "main" in the folder "layout" inside your resources folder, which is /res. These are actually integers, so when you go looking around the documentation it may not be immediately obvious that a function takes a resource! Also note that R.java does not take into account the extension of the file, so don't go putting clayisawesome.png and clayisawesome.jpeg in the same folder.

SO *deep breath* setContentView(R.layout.main) sets our Activity's contentView to the view defined in R.layout.main, aka /res/layout/main.*. Well then, what exactly is this enigmatic main.*?

Android uses XML files to define views (hereafter referred to as layouts), similar to how you can use .xibs to load interface elements in iOS...except there is no included tool that is as pleasant to use as Interface Builder. Yup, you'll be coding this XML layouts by hand. There are several third party resources, such as DroidDraw and the included Eclipse editor, but we won't be using them here. Thus, R.layout.main refers to main.xml, which defines our layout. We, obviously, need to go deeper.

Open up /res/layout/main.xml. It should look like this:

THE HORROR MR. KURTZ, THE HORROR. I'll be plain: writing layouts is my biggest beef with Android development, especially when compared to the alternative in iOS development.

Our parent element in the layout is a LinearLayout, which is an invisible element (very much like a <div>, if you're familiar with HTML) that defines how its children are layed out. There are several other kinds of parent layouts: RelativeLayout, AbsoluteLayout, TableLayout...the list goes on. For the purposes of these articles, we'll get to them when we get to them. Just know that they exist. 

What a LinearLayout does is display each of it's children one after the other (linearly) in the orientation specified. So if you have two text views in a vertical orientation, they are displayed one after the other like a list. It's the simplest of all the layouts, so that's what it's the default. 

Inside our LinearLayout is a TextView, which is exactly what it sounds like. It's text is assigned to "@string/hello"...but that's not literally what it will display. When you start an XML assignment with @, you're referring to another resource. This is used for strings (for localization purposes, mainly) and referring to other interface elements (we'll get there!). @string in particular refers to /res/values/strings.xml, which collects various strings used throughout our project and app.

If you open strings.xml, you'll see <string name="hello">Hello World, OfflineListActivity!</string>. For good measure, replace that with something like...oh I don't know, <string name="hello">Clay is cool jklolwut</string> :). But really, howabout <string name="hello">I feel pretty...oh so pretty!</string>

You'll also see that all of the layout elements in main.xml have a layout_width and layout_height. These can take all kinds of values, including pixels, percentages, etc, but it's best to try and define non-absolute terms since you can't count on knowing the exact dimensions of every Android device. Alas, such is Android fragmentation.

So go ahead and launch your app! In Eclipse, it's as easy as hitting the Build button. Since we've already set up our virtual device in Part 2, there shouldn't be any more busy work. 

If the simulator wasn't already open, it'll take a minute to...boot up. Yknow, like a real device. The novelty wears off fast. Also, it won't automatically unlock the device for you, so remember to do that by hand.

You'll be greeted by a pretty this:

Part3screen
Didn't work? Check your AndroidManifest.XML and make sure it looks like this:

So what did we learn?
  • Activities == UIViewControllers
  • onCreate == viewDidLoad
  • Use R.java to refer to project resources in code (R.layouts.main)
  • Uses XML files to describe layouts (main.xml)
  • Use special parent layout elements to really define how your layouts look (LinearLayout)
  • Use the strings.xml file for strings

That's actually quite a lot of ground. Not a lot of code, I know, but you have to understand how everything fits together first.

Click to continue to Part 4: ListActivities; or, "Why are table view chapters always so long?"

Beginning Android for iOS Developers - Part 4: ListActivities; or, "Why are table view chapters always so long?"

Ask any iOS developer what the best UIKit component is and odds are it'll be UITableView. It's the backbone of nearly every non-game App out there, in one way or another. It's an efficient, highly customizable element that is a natural fit for the form factor, as opposed to the sprawling, one-dimensional interfaces we see on Desktops. In fact, whenever I start developing for a new mobile OS, I almost always look at how tables are handled because it will probably be the 75% of my app. So, how does lovely Android stack up?

The droid you're looking for is ListActivity. If you haven't picked up on it by now, we're going to make OfflineListActivity from Part 3 such an Activity. Go ahead and import android.app.ListActivity in OfflineListActivity.java and change OfflineListActivity so it extends ListActivity, not Activity. Should now looking something like:

EDIT: Shoutout to Cyril Mottier, who corrected me on this bit: "When using a ListActivity, Android will automatically creates a ListView that fills the screen."

We also need to edit our main.xml, replacing our beloved TextView with a ListView:

Should be pretty easy to see what's going on here. Note that we haven't told Android anything about how the list rows themselves should look, only that we have one that fills up the parent layout. Now that we've updated our layout, let's get back to fun land. Pay special attention to this next part!

Unlike UITableViews, we don't need to add any new methods to implement list indexing. The Android SDK actually provides a mechanism by which this happens automagically: ArrayAdapters. These are sort of like NSArrayControllers, if you're familiar with OS X development. Basically, you assign a ListActivity an ArrayAdapter and it'll use the contents of an ArrayList in that ArrayAdapter to populate the ListView automagically. Wow, that's a lot of camel case.

Import android.widget.ArrayAdapter, java.util.ArrayList, and (optionally) java.util.Arrays. Depending on your memory of Java, you can create an ArrayList however you want, but I'm going to create it with a String array. At the least, create an ArrayList as an instance variable of our OfflineListActivity. Here's my use:

Watch as we only have to add *one line* to get our ListView to kick in:

In this use, the ArrayAdapter takes a Context (a parent object, essentially), resource, and List as arguments. The resource is android.R.layout.simple_list_item_1, a default view that works well for single-line list items. We use *android*.R in order to differentiate between OUR R.java and the default R.java. Savvy?

Hit the build and install button to see our creation come to life. Depending on your screen resolution, you might be able to scroll, all handled courtesy of ListView. You can also play with the emulator's arrow keys and see that your Activity automagically has support for non-touch devices. Kind of neat, actually.

Part4screen_0

Let's pretty this up a bit, shall we? Specifically, let's try to get some iOS look-and-feel in there. Why? Because, as nice as grey and orange are, we want *some* type of continuity between our iOS and Android apps. There's a delicate balance between respecting an operating system's native UI guidelines and keeping a consistent cross-platform experience, so always count to 10 before doing something rash. We'll come back to this topic later.

One cool feature about Android that iOS lacks is the ability to apply an app-wide "theme", which enables you to reformat the look of every View element in one fell swoop; so if you want all your fonts to be in Marker Felt, you should use a theme instead of doing a custom XML file for each view in your app. Thankfully, there's a default theme we can use to get some of that iOS mojo. 

Look in your project folder and find AndroidManifest.XML. This is very much like the Info.plist in an iOS app. You should see something like:

A lot of this is pretty self-explanatory: package name, version code, version name, etc. Note the use of @drawable and @string to refer to special resources. We've already encountered @string, but what's @drawable? Check out your /res folder again. You will either see one folder (/drawable) or three folders (/drawable-hdpi, /drawable-ldpi, /drawable-mdpi), depending on how you created your project. The three folder configuration allows you to easily include multiple resolutions of the same resources for different pixel densities, much like the @2x feature on iOS.

What there isn't an equivalent to on iOS is the <intent-filter> section. On Android, there are more types of apps than just those that are launched by the tap of an icon; in fact, you can make apps that don't have a full screen activity at all. Accordingly, you use the <intent-filter> to specify how your app can be launched and used.

Anyway, back to making it pretty. Add android:theme="@android:style/Theme.Light" as a property of your application:

Run the app and you'll see we now have more pleasant list:

Part4screen

You should also realize that handset manufacturers can ship their own default themes and UI features in place of normal Android ones; for example, the Galaxy S devices often use blue UI elements and rubber-band scrolling. So while you might not be able to depend on getting the *exact* same look on every device with this approach, you can expect it to look the same as the other apps on the device.

We're still missing something from the iOS UI that's actual more than just eye candy: the disclosure arrow. Although a simple graphic, it's a valuable piece of UX information, as it lets the user know that the row can be tapped to go deeper in a navigation hierarchy. Unfortunately, there's no default Android style that has this, so I whipped up an icon in Photoshop that'll do the job (found in the source). You're probably better at simple icons then I am, so you might want to use something else for production. Just sayin.

Anyway, we want our list row to have a label aligned to the left and the arrow image aligned to the right, both centered vertically. In an iOS app, this would mean customizing a UITableViewCell, either in code or in Interface Builder. On Android, this means using our own subclass of ArrayAdapter in our ListActivity which knows how to use an XML layout to construct the row view. Make sense? If not, let's just Nike it and then we'll talk.

First, we want to actually write our row XML file. In /res/layout, create list_item_with_disclosure.xml (or whatever you want to call it). 

A CHALLENGER APPEARS: this time, we're going to use a RelativeLayout the parent of our layout. RelativeLayouts are pretty neat, actually. Recall that LinearLayouts just display one thing after another in the order listed in the XML file; RelativeLayouts, on the other hand, draw their children in terms of defined relationships. So if you want to write a caption for an image, you can position the caption below the image, irregardless of where the image is drawn. Make sense? Relative to our situation (heh, get it?), this also allows us to position elements relative to their parent elements (such as aligning them to the left and right, as we wish to do with our label and image). 

For the body of our layout, we want to use a TextView and an ImageView.

The first unusual thing you may notice is android:gravity. This is a property which defines a sort-of automatic padding of a UI element (in that it tells Android how to align the contents *inside* of a View, not outside). In this case, we want to align the contents of the TextView vertically centered. In both elements, you will also see the use of android:layout_alignParent, which is a property exclusive to RelativeLayouts that makes our lives easier. This especially helps in creating interfaces that are resolution and orientation independent, as is often the case on Android phones.

The other interesting thing going on here is android:id. We can assign any layout element an id, which is then built into R.java so we can access it from our code, much like how an IBOutlet lets us reference an Interface Builder element. However, it needs to be prefixed with the special "@+id/" to work.

Let's get back to talking code. As I mentioned earlier, we need to subclass ArrayAdapter to get this to work. Create a file called BrocabAdapter.java and have it extend ArrayAdapter<String>. There are quite a few imports here so I'll just copypaste below. We also need to implement a constructor, but it's pretty painless:

The function we need to override is getView. This is sort of like tableView:cellForRowAtIndexPath:, as it enables us to reuse already created views in our list to save resources.

Pretty simple stuff for the most part. We check to see if convertView (the view used for the row) already exists; if it doesn't, we create it using a LayoutInflater. This is a pretty handy object that is utilized quite often, as it lets you jump back and forth between View objects and XML files. (FYI: this.getContext() returns the context in which this ArrayAdapter exists, thus our parent ListActivity). As noted earlier, we use R.java to access the interface elements declared in the XML files: R.id.disclosure and R.id.term. 

To glue it all together, simply change ArrayAdapter<String> to BrocabAdapter in OfflineListActivity.java: 

Take a gander at our even prettier list:

Part4screen_2

I'm about to Steve Jobs it up because there's just ONE MORE THING! We're going to do something when a row is tapped. Ultimately, we want to push a new view to the stack, but let's start small.

On Android, every view has an "onClickListener" property. When the view is clicked (tapped), the listener's onClick function is called. To K.I.S.S., we're just going to have it display an AlertDialog, which is the equivalent of a UIAlertView.

BAM, we turned our ListActivity into an onClickListener for the entire row. We also tagged the row with its index, just "in case" we need to refer to it "later". We could have just made the Adapter itself an onClick listener, but it'll make things easier down the road if we do it this way. Also, it's a better separation of model and controller (...right?).

Import android.view.View.OnClickListener and android.app.AlertDialog. We need to implement the OnClickListener interface (like conforming to an Objective-C Protocol, if you're a bit foggy on Java) and provide an implementation for onClick:

All of it is pretty simple and uses familiar vocabulary (brocabulary?) to its iOS counterpart. One note: setButton is pretty verbose, but this is the non-deprecated use.

Here it is in action:

Part4screen_3

We covered a lot of ground this time:
  • ListActivities == UITableViewControllers
  • ArrayAdapters == NSArrayControllers; magically fill in ListViews.
  • Change themes and ALL KINDS OF AWESOME THINGS in AndroidManifest.XML.
  • Subclass ArrayAdapter to use a custom row XML file
  • Convert XML files to Views with LayoutInflaters
  • Use onClickListeners to track row events.

Click to continue to Part 5: Files and Objects; or, I prefer JSON Bateman's early work

Beginning Android for iOS Developers - Part 5: Files and Objects; or, I prefer JSON Bateman's early work

In the original spec for Brocabulary, we said one of our sources was a file included with the app. In this case, I'm going to be using a JSON data source for our data. Why JSON? It's easily readable and non-verbose in comparison to XML. There is fantastic support for XML parsing in Java and Android, actually more so than for JSON, so I'll leave the details of using an XML data source up to you; for now, I'll be sticking with JSON.

Let's take a look at our JSON structure real quick:

Appears as if we have an array of dictionaries. Each dictionary has one key, "brocab", which corresponds to a dictionary containing the core Brocab data. We need some way to turn from a file into a string into an ArrayList of corresponding Brocabulary objects. Guess we've got our work cut out for us.

First, we need to actually include our file with the project. Data files such as this are supposed to be included in /res/raw, so make that folder if it does not already exist and copy and paste brocabs.json into it (found in the source). And much like Bon Jovi, we're already half way there.

We could keep our Brocabulary objects as strings or dictionaries or hashes or something, but as seasoned iOS developers you should know it's good form to create a Java object to serve as our model. Create Brocab.java and give it String instance variables called term, author, and description. Unfortunately, Java doesn't have any handy mechanisms like @property for creating getters and setters, so you'll have to write those yourself. Poor you :'( When you're done, it should look like:

Mostly harmless.

Now we need to load the original file. Now, there are a few fancy ways you can set this up which are more efficient, but for simplicity we'll just store all of our Brocabs in an ArrayList in our OfflineListActivity. This means we'll need to to make some Find+Replace-esque changes. For starters, we need to change all mentions of String to Brocab (such as in our ArrayList and ArrayAdapter definitions). To spare you (once again, poor you :'( ) the trouble, here are all minute changes (in a before/after format):

Cool beans. Now let's get to the fun part: loading this bad boy. To make this pretty, we're going to put all of the loading in a separate function of OfflineListActivity. You might be tempted to put it in onCreate, but it'll look a bit sloppy.

This is going to be a bit of a mess, so I'll go through it in chunks.

We're going to store our JSON representation as a string, THEN parse that string.

We try to create an InputStream using our iphone.json file (found in the source). Note, once again, that R.java doesn't care for the extensions of our files. If it fails, we create a Toast. WAIT JUST A MINUTE THERE CLAY WHAT IS A TO--okay, that's understandable. A Toast is a neat little Android UI element that sort of resembles a UIProgressHUD (...Apple, I swear I don't know what that is and I've never used one...). It's a little box that fades in near the bottom of the screen, displays a message, and fades out. It's designed to be used for non-intrusive notifications, but I like them because they're dead easy to create.

Anyway, where were we?

I'm sorry this isn't as magical as it could be. There's probably a prettier abstraction somewhere, but this'll work. Basically, it reads through our InputStream and writes its contents to a Writer, which in turn we turn into our jsonRep string.

WHEW. Here's that whole block:

NEXT we need to turn our string into an ArrayList. There are a few options for JSON parsing in Java, some more magical than others. This is a pretty lo-fi one but, as with many things in my life, it "just works". Remember to import org.json.JSONException, org.json.JSONObject, and org.json.JSONArray.

This tries to turn our string into a JSONArray, which we know to be the structure of the data. If that fails, then something incorrectly formatted in your file =O

There's probably a way to compress this code, but I made it a bit verbose for readability. We iterate through the JSONArray with getJSONObject(i) to pick out each JSONObject (dictionary) before getting the real data we want from it with getJSONObject("brocab"). We then create strings for each property available, checking to see if the author exists (which it may not). Finally, we create a new Brocab object and add it to our ArrayList.

The complete code for this section looks like:

ALMOST THERE!

The last thing we need to do in our loadBrocabulary() function is actually create our BrocabAdapter with a simple

So, if you haven't been following along, the monstrous function looks like:

In the words of Drake, you can Thank Me Later.

SO ARE WE DONE YET??!?!?! *Almost*. We still need to tell our BrocabAdapter how to use the Brocab objects instead of simple strings. This, unlike Ron Burgandy, is not a big deal:

It's probably a good idea to handle this back in our OfflineListActivity onClick method as well:

OKAY. Now we're done. Run it and bask at what we've done...which looks remarkably like our previous version:

Part5screen

Here's a quick recap:
  • Creating a Java class for our model
  • Loaded a file included as a project resource
  • Parsed the JSON of said file into our model
  • Adjusted our ArrayAdapter to use the model
The awesome thing is that our BrocabAdapter will work the same with no changes for all ListActivities we use Brocabs in: our favorites activity, our online activity...speaking of which...

Beginning Android for iOS Developers - Part 7: HTTP Requests Part Deux; or, "It's my Intent to be POSTed up right here"

Let's think of our user: I'm downloading all these brodacious brocabulary words, but how can I get in on the action? Well, luckily our awesome server is RESTful and will let him (or her!) upload new words using POST requests.

We have the technology, but how do we put it all together? We'll need to create a new View for this. In the original Brocabulary, we popped up a modal view controller to serve as our form. There's no equivalent presentation type on Android, so we'll just have to come up with something else.

Wait, we haven't even discussed how to bring up arbitrary Activities have we? So far, we've let our TabActivity handle all of that behind the scene. So let's start there.

Create a new Activity called CreateBrocabActivity.java and a corresponding layout create.XML. Also add CreateBrocabActivity to our AndroidManifest.XML (<activity android:name=".CreateBrocabActivity" />). It'll look a bit plain: three text inputs for term, description, and (optionally) the author's name, plus buttons for canceling and submitting. Hey, I didn't say I was going to teach you about design did it?

This is going to be a pretty packed layout so let's take it a few elements at a time:

We're going to be using a relative layout as our parent. Why? We want to align things on top of each other and along the edges of the parent. Makes the most sense to use a RelativeLayout.

These are our elements for the Brocab's term. Why both a TextView and EditText (an equivalent to UITextField and UITextView)? Well, we want our EditText to be a singleLine, but we also want to give the user some instruction. Now, EditTexts do provide an "android:hint" option which serves as an equivalent to the UITextField's "placeholder" property; HOWEVER, if you enable singleLine, the hint disappears. I know, I know, that makes zero sense, but it's what happens. Google it or try it out.

We do the same sort of thing for the description and author inputs.

At the bottom of the page, we want two bottoms (similar to our OnlineListActivity.) We give them equal, non-zero weights so the layout is split evenly between them (recall layout_weight is a property of LinearLayout).

The whole thing looks like:

FUN STUFF. Now let's code it! We need to add some instance variables to our CreateBrocabActivity and make it implement the OnClickListener interface:

What's up with all those? We need to keep track of the buttons to see which one was tapped in our onClick function. The uploaded boolean is used to see if the brocab was uploaded, thus preventing the app from uploading it twice if the user taps the button repeatedly. We obviously need to keep our EditTexts so we can find the user input later. And the progress dialog is kept so we can show and dismiss it when needed.

We then connect all of these in our onCreate function:

All we have left to do is handle those button clicks:

We'll hold off on what needs to happen when the back button is clicked; for now, we need to fill in that upload function, which is another beast like its GET brother.

Cool story bro, you assigned the values of the EditTexts to string.

We do some basic input checking here. Note that since the author field is optional so we don't look at it. We're using some helper methods to shorten our code a bit, which we'll define later. Perhaps you should try and imagine what the code looks like? Basic AlertDialogs, nothing too difficult to implement yourself.

If there weren't any problems, we create a Handler. Note that the above statement is only creating the Handler, not the end of the else structure. This Handler does the same sort of thing as our GET Handler did, so it should look familiar.

Still inside of the else, we go ahead and URL encode all of the inputs for transport. We also account for the case where there wasn't an author.

Here are all the little helper functions I used to make it more readable:

So here's the big ole list of functions itself:

HOORAY! Now all we need to do is display it.

In iOS development, we use some sort of parent UIViewController to display new view controllers, such as a UINavigationController. Unfortunately, there's no equivalent class in Android. Instead, any Activity can spawn a new Activity and bring it to the front using Intents. Let's do this in our OnlineListActivity.

Back in that Activity's onClick method, add the following:

You also need to import android.content.Intent. This is a pretty simple implementation of starting a new Activity. The theory behind Activities is that they have a purpose that starts and ends; thus, it is also possible for an newly spawned Activity to send a message back to its spawner when it completes. This isn't necessary in our case, but...the more you know.

Anyway, back in CreateBrocabActivity, add a call to finish() in the onClick method:

And we're done! finish() is an Activity method that closes itself and returns the app to whence it came.

Get it a whirl! It won't actually work, since I'm not putting up my own server for you kids to send naughty requests to, but plug it should work fine for your own web apps.

Part7screen

Reflect on what we've done:
  • Create a new Activity using Intents
  • Use EditTexts to create a form
  • Sent HTTP requests with some URL encoded data

Click to continue to Part 8: Files and Objects Part Deux; or, "I prefer my breakfast with Serial"

Beginning Android for iOS Developers - Part 6: HTTP Requests; or, "Oh, you have to download that? Put it on my Tab."

Now that we've successfully loaded and parsed something from a local file...TO THE CLOUD!™ It's not all that difficult, especially since we've already written the code which parses the JSON; we simply need to make an HTTP request. But, unfortunately, doing only that in this article would be too easy: we also need to change how our application is structured.

If you recall, Brocabulary on iOS was built around UITabBarController. Thankfully, there is an equivalent on Android: TabActivity (hard to figure out, right?).

EDIT: More thanks to Cyril Mottier, who pointed out that this is the default layout Android provides for you, thus you don't need to create it yourself.

Let's lay this bad boy out. Create a new file called tab.XML, which will serve as our layout for the app.

Essentially, we make our parent layout a TabHost and then can layout our children however we wish. This is quite unlike iOS, where our UITabBar is stuck at the bottom of the screen. You could move our TabBar wherever you like, but having a TabBar on top is a native Android practice and should be respected wherever possible. You might also notice that for ids we're using "@android:id" instead of "@+id". This is a way of referencing android.R.java, not our R.java.

Next, we need to create a TabBarActivity. Make BrocabTabBarActivity, a subclass of TabActivity. All we're doing here is overriding onCreate and adding a tab:

A TabSpec is a simple way of organizing the label, icon, and Activity for the tab.

The interesting bit is this: "new Intent(this,OfflineListActivity.class)". What's all this about? Well I *intend* to tell you. :).

I briefly mentioned them way back in article 4 in AndroidManifest.XML. Intents are quite powerful objects used to specify an "operation to be performed" (such as when a system-wide event happens, another App opens a certain URL, or when a tab bar is tapped). In this case, our intent only contains information about the class to be created for that particular tab. TabSpec and TabHost abstract away actually dealing with handling the intent and just ask us for one; don't worry though, we'll be using our own soon enough.

Done yet? Nope. We have to actually get this TabActivity to display. Currently, we're launching the app with our OfflineListActivity. Open AndroidManifest.XML and let's change it to use our BrocabTabBarActivity:

See that last <activity> tag? For every Activity our application we use, we need to specify it in the Manifest.

Run our application and you should see something pretty similar to what we had before, except with a large grey bar on top. Looks like we need another Activity, no?

Part6screen

We're going to call our next ListActivity OnlineListActivity.java (poignant, no?). For now, just copypasta the definition of OfflineListActivity in there.

Add another tab to our TabHost and a line to our AndroidManifest.XML to put it all together:

Try running it now; much prettier, right? 

Part6screen_1

Real quick, we need to also tell our app that we're going to use the internet. There are many other permissions that we can request, but I'll leave that to you.

Let's Free Willy 1 and get back to our original porpoise: downloading from the cloud. However, we need to make some simple UI changes first. We're going to add a row of two bottoms at the bottom of the screen: "Refresh" and "Create" (we'll get to that chestnut later). 

Create a new XML file called online.XML and copypasta main.XML as a start. We're going to keep our LinearLayout but add a few things:

First, android:layout_weight. LinearLayouts support adding "weights" to layout elements, which provides a way for proportionally distributing screen real-estate (thus, a weight is unitless). So in this example, everything has a weight of 1, thus every element will take up the space specified by its layout_height (taking up the space necessary for its content, in this case). 

Everything else here should look typical. We assigned IDs to our two buttons, which we'll be using right...about...now!

Go back to OnlineListActivity.java, add two Button instance variables, and change our onCreate to look like:

Well, looks like we also need to update our onClick method.

There's a better way of doing this that we'll implement later, but for now this will do. We also added a fancy ProgressDialog which we'll show while refreshing so the user doesn't get impatient and, as Starcraft players would say, "QQ". So let's get to the Gorilla: downloadBrocabulary.

On iOS, making asynchronous HTTP requests is pretty simple: NSString -> NSURL -> NSURLRequest -> NSURLConnection. Lots of layers, yes, but it's not that hard to understand. Java, on the other hand, somehow makes everything difficult. There's no well defined solution for doing this, so we'll have to resort to external libraries. You can pick and choose what you want to use (Ning, NIO, Jetty are some examples), but I'm going to use some code by Greg Zavitz & Joseph Roth that uses just two classes: HTTPConnection and ConnectionManager. Add these (found in the source) to your project.

We're also going to use a Handler object, which lets us do all kinds of fancy threading magic with our functions.

So, with that in mind, here's downloadBrocabulary:

Pretty simple. Our handleMessage function (which overrides the default implementation, if you didn't catch the Java syntax) responds to changes in the HttpConnection's state. If it succeeds, we pass the response to our loadBrocabulary as expected (with the minor change of passing the string instead of loading it from a file). If it fails, we display the error with a separate function, which makes our code a little smaller since displaying errors is a pretty common thing; either way, we also dismiss our ProgressDialog. Both of these functions are listed below:

Run it and TELL THE INTERNET I SAID HI!

Part6screen_3

So what did we learn this go-round?
  • TabActivity == UITabBarController
  • How to set up a TabBar and TabActivity
  • Setting up Permissions and multiple Activities in AndroidManifest.XML
  • Sending an HTTP request (remember, there are other libraries that can do this too!)
  • Parsing the JSON response

Click to continue to Part 7: HTTP Requests Part Deux; or, "It's my Intent to be POSTed up right here".

Beginning Android for iOS Developers - Part 8: Files and Objects Part Deux; or, "I prefer my breakfast with Serial"

While we're on this creating new Activities and Intents business, let's go ahead and create a detail view for our Brocabulary. Instead of an AlertDialog appearing when the user selects a row, we should push a new Activity that gives the term, author, and description of the Brocab (pretty much how our CreateBrocabActivity looks). 

But...that's just *too* easy. We also want to keep track of the user's favorite Brocabulary, both from our offline and online sources. Sound like a plan?

Create BrocabDetailActivity.java and detail.XML. Remember to add BrocabDetailActivity to your AndroidManifest.XML! (<activity android:name=".BrocabDetailActivity" />) Accordingly, detail.XML bears a striking resemblance to create.XML, so I won't go into too much detail about its implementation:

That was quick. Now, let's talk for a moment about how we're going to pass this data around. When we did our CreateBrocabActivity, there was no need for it and the OnlineListActivity to communicate; with our detail Activity, however, we need to send the source Brocab object to the new Activity. There are a few potential ways of solving this, but I'm going to use a nifty trick Intents provide: "Extras". And no, not the Ricky Gervais show.

Intents can store extra data in a dictionary-like format which can then be accessed in the spawned Activity. Pretty neat, eh? Thus, we'll just pass our Brocab object inside the Intent and then get it out in our detail Activity's onCreate method. Speaking of which, let's take a quick look:

Pretty basic stuff. The only thing foreign is when we retrieve our Brocab: "brocab = (Brocab)this.getIntent().getSerializableExtra("brocab");". What's this "serializable" business? Well, you can't store just any old object in an Intent's extras; it needs to implement the Java Serializable interface, which is sort of like complying to the NSCoding and NSCopying protocols back in Objective-C. Now, those can be kind of a hassle to implement, so how about this Serializable business? 

NOPE. Not difficult in the least. We need only to say that our object is Serializable, declare a serialVersionUID, and Java will handle the rest. So, way back in Brocab.java, add:

AND THAT'S IT! Congratulations, your object is now serializable. This will come in handy very soon.

Now, back to our BrocabDetailActivity. We've retrieved our Brocab object, filled in the text boxes, and just need to get our onClicks working:

Piece of cake. Just like our CreateBrocabActivity, we just throw a finish() and we're done. We'll implement all the favoriting magic later.

In each of our ListActivities, we need to push the detail Activities. Where we previous had code creating AlertDialogs, use the following snippet:

Run the app and bask in your own abilities. 

Part8screen

Now, on to that favorites business. We need some way to keep a persistent list of the user's favorite Brocabs. On iOS, we have SQLite3, file system access, and NSUserDefaults. For something like this, I would probably go with NSUserDefaults since it's pretty painless to use for the amount of data we're storing (probably no more than a few dozen entries). On Android, we have equivalents of all those methods, plus the ability to store data externally (such as an SD card). So we're using the SharedPreferences (NSUserDefaults equivalent), right? 

Unfortunately, Android's SharedPreferences can only store primitive data types. We could figure out some way to compress Brocabs into a string or bytes or something, but that seems like a hack-ish solution. Our Brocabs are already Serializable...could that help? "Well, actually", having a class be Serializable allows us to easily read and write that class to a file. Problem solved.

So, where are we going to put these Favorites? In a new ListActivity, naturally. Create FavoritesListActivity.java, add it to our AndroidManifest (<activity android:name=".FavoritesListActivity" />), and make the corresponding favorites.XML. Copypasta main.XML into favorites.XML, as they are identical. Also use the same instance variables, onCreate, and onClick functions as OfflineListActivity.

The only thing we need to change is our loadBrocabulary method, which is thankfully much shorter:

Because of Serializable, all we need to do is create an ObjectInputStream from a FileInputStream and retrieve our ArrayList from it. Now, we aren't guaranteed that readObject will return an ArrayList, but because we know that's the only object we're ever putting into it we can ignore any warnings Eclipse gives you.

So go ahead and ru--WAIT. Almost forgot, we need to add it to our TabBar! Get into your Wayback Machine and add the following to BrocabTabActivity.java:

NOW run it. If you hit the Favorites tab, you'll see...WOOPS! We actually need to build let users add things to the favorites now don't we?

Back in BrocabDetailActivity.java, let's take another look at that onClick function. Add a call to the function addToFavorites:

addToFavorites is another long function, so I'll break it up and go one step at a time:

This is pretty much identical to our code in FavoritesListActivity, so it's not much of a big deal. HOWEVER, you do need to add the handleError method found in FavoritesListActivity to the class.

Anyway, moving on:

If the ArrayList is null, then there were no previous favorites. Thus, we should create a new ArrayList. Either way, we add our current brocab to it.

This is pretty much the serialization code in reverse, and it bears striking similarity. Give your app and run and watch it work :)

Part8screen_2

Let's recap our knowledge:
  • Making Java clases Serializable
  • Saving Serializable objects
  • Loading Serializable objects

Click to continue to Part 9: Preparing for the Market; or, "Wow, that's easy."

Beginning Android for iOS Developers - Part 9: Preparing for the Market; or, "Wow, this is actually really easy"

Well, we've made a pretty neat little app, and we want to share it with the whole world! Unlike iOS apps, there are a few different methods of distributing Android apps. You could even distribute it yourself so long as your users allow apps from unknown sources to be installed (which may or may not be possible, depending on the carrier and handset).

The most widespread way of selling your app is through Google's Android Market. What's different about it from the App Store? Here are some key points:

  • No review process. Once you submit an app, it's ready for download (after it propagates through all the servers). This is good for the developer, but questionable for the end-user, as many crap or malicious apps are left unfiltered.
  • $25 fee. 75% cheaper than Apple's yearly fee.
  • Payments handled through Google Checkout. Instead of waiting for your bank and tax info to clear through Apple, payments are instantly sent through Google Checkout. You don't even need to provide an SSN unless your app makes over $1k a month.
  • Arbitrary pricing. Your app prices do not need to conform to pricing "tiers". Want to charge $1.29? Go for it. Want to charge $0.99 and 0.99 Euros? That's cool too.
  • You can (and should) include promo graphics. Apple only asks select developers for large-form and banner-style graphics for display in iTunes; the Market, on the other hand, will psuedo-randomly show these images throughout the Store.
  • DRM optional. Like the App Store, Android Market has piracy. Google has provided a DRM solution that you can enable, but at the time of writing it is deprecated and will disabled in the future.

How do we prepare our app? It's not a big deal. Make sure you've declared minimum and base SDK targets in your AndroidManifest.XML:

When you're ready, you can use either the Android command line tools or Eclipse's "Export Android Application" option to build your application. You'll need to setup a keystore and key, which Eclipse will walk you through. At the end of this (very quick) process, you'll have a shiny APK ready to upload to the Market (here).

And that's all he wrote. As my Dad always told me after school: "I hope you learned something!"

You can check out Brocabulary on the App Store and the Android Market. Feel free to browse my other work as well!

AND MOST IMPORTANTLY: follow me on twitter: @clayallsopp :)