Sunday, February 7, 2010

 

Android vs. iPhone: A Developer's Perspective, part I

Android vs. iPhone: A Programmer's Perspective


(See also Part II.)

I've spent the last month or so building both Android and iPhone versions of my app iTravel. (See http://wetravelright.com/ for details and links.) Which gives me a pretty good perspective from which to compare and contrast the Android and iPhone environments and SDKs. Hence I give you the following head-to-head analysis, from a developer's point of view:


Language

Non-programmers often think that one's language of choice is a big deal, but really, once you've learned two or three programming languages, picking up another is generally something you can do in a day or two. That said, there are often substantive differences. And this is definitely true of Java (for Android) and Objective-C (for iPhone.)

Let's start off with the really annoying stuff: Objective-C's memory management. By which I mean, its complete lack of any. Programmers have to manually allocate and release memory when writing for the iPhone SDK, which is positively medieval. If you fail to do so, and there are many pitfalls, then you leak memory which is lost until the device reboots. This is awful. (And it's no longer true of the Mac SDK, incidentally; but the iPhone is behind the times.)

There are other annoyances. You have two files to contend with for every class - a .h and a .c file. Which is inconvenient and complicating and inelegant. And suppose you have a basic, bog-standard instance variable. You generally wind up declaring it in, count 'em, not one, not two, not three, but four different places.

In your .h:

{
NSObject *object
}

@property (nonatomic, retain) NSObject *object


In your .c;

@synthesize object

and later, in dealloc(),

[object release];

Whereas with Java, you have one single .java file, which in general will have

private Object object;
public Object getObject() { return object; }
private void setObject(Object o) { object=o; }

all in one place. I know which one I think is easier.

But. On the other hand. Objective-C is sort of the bastard son of C, which is awful, and Smalltalk, which is awesome. As a result, it has Smalltalk-like features like selectors:

[caller performSelector:@selector(myFunctionName)]

...in short, you can use functions as (more or less, ish) first-class objects. Try that in Java and if memory serves you'll most likely wind up in the irritating labyrinth of reflection. Plus, you get options like "doesNotRecognizeSelector:", which can be easily misused, but is potentially very powerful, and does not exist in Java.

On the other hand, Objective C is really annoyingly logorrheic (meaning wordy) especially when it comes to string handlers. Suppose you have strings A and B, and you wish to combine them into string C. In Java, the syntax is

C=A+B;

whereas in Objective-C, you type

C = [A stringByAppendingString: B]

Or suppose you want the location of the last slash in string A. Java:

n=A.lastIndexOf("/");

Objective-C:

n = [A range ofString:@"/" options:NSBackwardSearch].location;

I much prefer Java's syntax and simplicity. But I do admire Objective-C's flexibility.


Development environment

By this I mean: the "integrated development environment" in which coders work; the documentation for the IDE, the language, and the libraries; the testing and source-code support; and all the stuff that is meant to help you write better code faster.

The Android and iPhone IDEs and documentation really incarnate the attitudes of the two companies in question. Android doesn't exactly have an IDE of its own, although they recommend that you use the Android plug-in for the open-source Eclipse IDE, which is slow, irritating, and buggy in various minor ways. The documentation is written by smart people for smart people, with little handholding. Flashy graphics are minimal to nonexistent. And a lot of important stuff is still handled by tools meant to be run from a shell rather than a GUI. But the search function is excellent.

Apple's IDE is slick, seamless and powerful. It comes with a visual tool to help you lay out the screens of your app. The documentation is full of step-by-step guides (although they are often oddly lacking or confusing) and high-quality graphics and other visualizations.

I have many complaints about both. Eclipse is slow and annoying, and I could only get Android's JUnit test harness to run successfully from a terminal window, rather than the IDE; similarly, I had to use shell tools to sign packages, get a fingerprint for a Maps IDE, install a package on my phone, etc. All of which really calls into question the I in IDE.

On the other hand, at last the external unit-testing actually works; XCode's built-in harness is so bad that Google built and released an entirely separate one, which has the advantage of actually functioning correctly. On the other hand, its Subversion integration is excellent, which is not true of Eclipse.

Both have plenty of official and unofficial online support, as well, at official support sites and places like Stack Overflow. Android's open-source ethos gives it a big advantage in terms of external packages, though; for instance, if you want to build a barcode scanner into an Android app, there's a whole open-source library out there for you, ready to be plugged in. For the iPhone? You'll have to roll your own. Sorry.


Multithreading

In phone apps multithreading is key, because the phone needs to remain as responsive as possible, so you need to do your heavy lifting behind the scenes, outside the main UI thread.

Both the iPhone SDK and Android support multithreading, but the latter's is much more convenient, especially if you want to call back to the main thread once your background thread has done its thing. On the iPhone, you have to do something like:

-(void) doWebView {
NSThread* htmlThread = [[NSThread alloc] initWithTarget:self selector:@selector(loadHtml) object:nil];
[htmlThread start];
[htmlThread release];
}

-(void) loadHtml {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *html = doUnroll ? [self getUnrolledData] : root.data;
html=[NSString stringWithFormat: @"%@%@</body></html>", [Util getBaseHtml], html];
[self performSelectorOnMainThread:@selector(setHtml:) withObject:html waitUntilDone:NO];
[pool release];
}

-(void) setHtml:(NSString*)html {
[webView loadHTMLString:html baseURL:nil];
[webView sizeToFit];
[self.tableView setTableHeaderView:webView];
}

Whereas on Android, you can use Java's equally irritating Runnable() framework, but Android provides an extremely convenient (and quite flexible) short form. Just subclass AsyncTask in an inner class:

new LoadHtmlTask().execute();

class LoadHtmlTask extends AsyncTask {
protected String doInBackground(String... strings) {
String headerData = Settings.GetHtmlPrefix() + (unrolled ? getUnrolledData(viewRoot) : viewRoot.getData());
return headerData;
}

protected void onPostExecute(String results) {
mHeaderView.loadDataWithBaseURL("local", headerData, "text/html", "utf-8", "");
}
}

which seems much more encapsulated and intuitive to me.


Persistence

On paper, the iPhone environment has a big advantage here: it features the Core Data object-persistence layer above the SQLite database, whereas Android requires direct DB access.

For me, though, direct DB access was not awful, and given the constraints of my app, arguably simpler than jumping through all of Core Data's hoops - using the separate tool to declare a data model, having to rebuild your custom code every time you add a column, etc. All that without even getting thread safety.

However, I'm totally comfortable writing SQL, not all developers are, and my app had pretty straightforward DB requirements. Core Data is undeniably more elegant and ultimately better. Plus you get nifty little features like shake-to-undo, semi-automatic migration data models in installed apps, etc. And it's not like the Android tools are particularly easy to work with. Check out the method in android.database.sqlite.SQLiteDatabase you use to perform a query:

public Cursor query (boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit)

As a (Google employee) friend of mine said, "Holy positional parameters, Batman!" Needless to say, one quickly wraps this monstrosity in other methods less prone to grievous error...


Part II of this post compares and contrasts system features, phone features, settings and resources, screen building, internet connectivity, and the app install/release process. (It does not compare and contrast graphics programming, as my apps are data-heavy not graphics-heavy.) Don't touch that dial.

Labels: , , , , , , , , , , , , ,


Comments:
Hey Jon! I'm a former Torontonian who began writing my first Android app last week so your blog posts on Android have been very interesting and I look forward to reading more of them. I noticed that several months ago you were thinking of using App Engine as the back-end for your app but I didn't spot a post about how that went. I made the same decision but I wrote the back-end first so i already have an App Engine back-end using a REST+JSON API for which I've written a simple AJAX UI as well as a WebOS client (for the Palm Pre) and am now working on an Android one. I'd love to hear what your experiences with using App Engine with Android were if you ever tried that.
 
Jon,
Thanks for sharing your views on the Threading!
Sean__Wong
 

Post a Comment

Subscribe to Post Comments [Atom]





<< Home

This page is powered by Blogger. Isn't yours?

Subscribe to Posts [Atom]