Android apps can only be written in Java*, a language that compiles to bytecode. iOS runs machine code directly like a desktop computer. While a big strength of Java bytecode is that it can run on multiple CPU architectures, machine code is typically faster in practice, even after the Java bytecode is JIT** compiled into machine code, because of all the safety checks*** that must be injected into the resulting machine code to fulfill all the rules of Java.
While this checking makes bugs easier to track down during development, it takes a severe toll on the CPU’s ability to perform instruction pipelining, something that was of little concern in the 1990s when Java was developed, but is now a crucial source of speed gains on modern CPU’s.
Google was probably trying to encourage a diverse ecosystem of devices by picking Java, but in reality, almost every manufacturer is using some kind of ARMv7-compatible CPU. All in all, using Java doesn’t make much sense.
* C code can be embedded in an Android app via the NDK and RenderScript API’s. But this just proves my point: Even Google realizes that Java doesn’t always cut the mustard.
*** Bounds checking for arrays being the primary culprit, since it involves a compare-and-branch operation every time an array element is accessed. Branch prediction in the CPU can mitigate this somewhat, but it’s still extra work.
Another innovation of Java is that unused RAM is freed automatically by a garbage collector, instead of having to be managed more actively by the application. The drawback of this becomes apparent when one attempts it: A memory scan is necessary to discover unused areas, and the app must be momentarily halted while it happens, causing those momentary glitches you see so often on Android devices.
Android tries to limit how often that happens by giving each app a memory allowance that it must use up first. The net result is that every Android app uses as much memory as it can all the time. Not good.
iOS uses a much simpler system called Automatic Reference Counting, the idea being to embed memory management into the programming language (Objective-C or Swift) on a fine-grained level. An object in iOS memory is freed immediately once no code can hold a reference to it anymore. In practice, this leads to smoother-running apps.
Android was originally developed by Google as a competitor to Blackberry OS. When Apple unexpectedly released the iPhone, Google scrambled to refashion Android as a competitor to iOS. The Android API* reeks of being a rushed job. The multi-touch feature was unceremoniously tacked on without a redesign. Even years after introducing a feature, documentation tends to be minimal at best, lacking at worst. To use a car analogy: The engine compartment is badly designed and the service manual is incomplete.
The iOS API is, comparatively speaking, downright beautiful. Everything the programmer might want to do is explained in clear English in voluminous pages of easily searchable documentation. High-performance algorithms for various types of data processing are built into the operating system for the programmer’s convenience. With the addition of the elegant Swift programming language, the clunky Objective-C programming language, a major drawback of iOS, can be retired.
* Application Programming Interface
An argument commonly heard from fans is that you get more for less when you buy Android devices. Can you guess why Android always gets the apps later than iOS? It’s because Android users are less willing to pay up. That’s why they bought an Android phone in the first place, because it was the cheaper option.
Almost all the good apps out there cost money to develop, and startup companies are looking for a return on their investment. They’re far more likely to get that with iOS users, who are willing to pay for things. Reason #3 above seals the deal.
Even quite old iOS devices receive new versions of iOS. Apple has a slow release cycle. Product series and models are often supported for years. The resale value for Apple product is therefore high.
Most Android device manufacturers abandon their devices shortly after releasing the next flagship in the line, and users must resort to rooting their phones to try out newer Android releases.