Colophon

Android for iOS Developers: Kotlin Edition 2018

ISBN: 978-3-906926-15-5

© Copyright 2016-2018 by Adrian Kosmaczewski – All Rights Reserved.

logo

AKOSMA Training Adrian Kosmaczewski

Ringkengässchen 11 – 8200 Schaffhausen – Switzerland

This document is geared towards providing exact and reliable information in regards to the topic and issue covered. The publication is sold with the idea that the publisher is not required to render accounting, officially permitted, or otherwise, qualified services. If advice is necessary, legal or professional, a practiced individual in the profession should be ordered.

In no way is it legal to reproduce, duplicate, or transmit any part of this document in either electronic means or in printed format. Recording of this publication is strictly prohibited and any storage of this document is not allowed unless with written permission from the publisher. All rights reserved.

The information provided herein is stated to be truthful and consistent, in that any liability, in terms of inattention or otherwise, by any usage or abuse of any policies, processes, or directions contained within is the solitary and utter responsibility of the recipient reader. Under no circumstances will any legal responsibility or blame gbe held against the publisher for any reparation, damages, or monetary loss due to the information herein, either directly or indirectly.

Respective authors own all copyrights not held by the publisher.

The information herein is offered for informational purposes solely, and is universal as so. The presentation of the information is without contract or any type of guarantee assurance.

The trademarks that are used are without any consent, and the publication of the trademark is without permission or backing by the trademark owner. All trademarks and brands within this book are for clarifying purposes only and are owned by the owners themselves, not affiliated with this document. Android is a trademark of Google Inc. iOS is a trademark or registered trademark of Cisco in the U.S. and other countries and is used under license by Apple Inc. Java is a trademark of Oracle Corporation and/or its affiliates. Kotlin is a trademark of Google LLC.

The Android robot is reproduced or modified from work created and shared by Google and used according to terms described in the Creative Commons 3.0 Attribution License.

Written and published in Switzerland. Created with the eBook Template Toolchain by Adrian Kosmaczewski based on Asciidoctor and PlantUML.

Abstract

This book provides a quick introduction of Android for iOS developers using the Kotlin programming language. It targets iOS developers with medium or advanced level, having shipped some iOS applications already in either Objective-C and Swift.

Dedication

To hernún.

Preface

The world of mobile development is a ground in constant motion. However, for the past five years, Android and iOS have both reached the level of dominant players in the field, moving other platforms out of sight. Due to the complexity of these systems, developers tend to concentrate their efforts in just one platform; however businesses must target both platforms to remain competitive in the mobile market.

This book provides an iOS developer’s perspective on Android, using the Kotlin programming language, highlighting the similarities and the major differences between both platforms. The author hopes that these lines will help other developers to jump to the fascinating world of Android using their hard earned iOS knowledge.

Target Audience

This book is intended as a step-by-step guide to guide developers well versed in the arts of iOS into the realm of Android mobile application development.

How to Read this Book

The author assumes that the reader has never written Android applications before; at most, maybe, the reader has played with an Android device at some point, but nothing else. If you are already familiar with Android Studio and Kotlin, you can skip directly to chapter 2, and start creating apps right away.

If you are not familiar with the Android developer tools, it is strongly recommended to read this book linearly, and to build the sample applications one after the other. This will help you build your skills step by step.

You can use this book as reference, later during your development work, using the provided source code as a basis for your own projects. The book can work as a "cookbook" text, providing specific help about some common (and not-so-common) tasks.

Requirements

This book assumes that the reader is using a Mac – after all, the reader is supposed to be an iOS developer!

It also assumes working programming knowledge in Objective-C and Swift, and of the most common iOS frameworks, such as Foundation, UIKit, Core Location, Core Data and others. Given their similarities, the text will heavily draw from the Swift knowledge of the reader as the guiding path to learn Kotlin, highlighting differences and similarities whenever possible.

Most importantly, it is not assumed that the reader has seen any Kotlin code yet. This book provides a quick introduction to the language, even though it is not by any means a complete reference. The "Bibliography" section at the end of the book provides a few useful titles for starting your exploration of Kotlin. In particular I’d recommend JetBrains' own Kotlin Tutorials and Try Kotlin websites as an excellent starting point.

In terms of software requirements, this book assumes that the latest version of Android Studio (3.0.1 at the time of publishing) is installed in the development machine, as well as Homebrew.

Source Code

The code bundled with the book has been prepared and tested with the latest version of Android Studio; make sure to download and install it in your system before starting.

All applications use the same baseline (or minSdkVersion): API 21, also known as Lollipop 5.0. This version of Android was released in November 2014, and at the time of this writing, 80% of all Android devices in the wild run a version equal or older to Lollipop. This should hopefully give this book the wide possible reach as well as a solid foundation for the future of the platform. Similarly, all code projects target the latest Android version available at the time of publication, API 27, Oreo 8.1 (targetSdkVersion and compileSdkVersion in the module Gradle files.)

Every time that the text of the book references some sample code, a "Follow Along" callout section will appear with the path of the project, which you can open on Android Studio to run the project directly on your device or the emulator:

Follow along

The code of this section is located in the Graphics/Draw folder.

Each application is as simple as possible, but not simpler. All the applications are working examples, tested at least in four environments:

  • The official Android Emulator.

  • The Genymotion Android Emulator.

  • A OnePlus 3 Android smartphone.

  • A Samsung Galaxy Tab S2 tablet.

Given the large variety of the Android device market, it is possible that some bits and pieces of the source code will not work in some devices; I remember having trouble with some Android devices during my career, so I would not be surprised if some of you encounter difficulties. I will not be able to provide support for your particular device, but I have made every possible effort so that the code works in the environments enumerated above.

Structure

This book is structured around code. The chapters are meant to be read with Android Studio open, in the order they have been written; I have reused bits and pieces of knowledge from previous chapters in many others, so you should be better served by reading them in order.

To help readers get up and running as fast as possible, every chapter features a section called "TL;DR" at its very beginning, including a handy summary of the most important similarities and differences between Android and iOS. You can use the tables in this section as a reference, and if you find them useful you can print a copy of the Appendix C, which contains all the TL;DR tables together in the same place.

The source code included in the book points directly to the projects available in the code zip file, which contains all the sample applications showcased in the pages of this book.

Thanks

I would like to thank all the readers of the first edition of this book; your support is what made this second edition possible! In particular I would like to mention Nick Ager, Caylan Larson, Luca Torella, Patrick Balestra and Nick K., who sent me lots of feedback and errata via e-mail and Twitter. And a very, very special shoutout to Florent Pillet who not only provided lots of feedback and errata, but actually gave me the idea of creating a Kotlin version for this second edition. Thanks a lot!

About the Author

Adrian Kosmaczewski is a writer, a software developer and a trainer. He is the author of many books about mobile software development, and has shipped mobile, web and desktop apps for iOS, Android, Mac OS X, Windows and Linux since 1996. Adrian holds a Master in Information Technology from the University of Liverpool.

When not coding or teaching, Adrian likes to spend time with his wife Claudia, his cat Max and his Olivetti Lettera 22 typewriter.

Part 1: Introduction

Getting Started

This first part of the book will guide the reader in the world of Android app development. We will first learn how to install and use Android Studio, we are going to get familiar with the tools and ecosystem, not only to create applications but to be able to debug them effectively.

1. Toolchain

Each platform vendor tries – and, to a large extent, succeeds at – locking third-party developers into their own ecosystem. This is true of many software platforms, and neither iOS nor Android are the exception to this rule.

One of the biggest efforts for iOS developers new to the Android ecosystem is getting used to a new set of tools, paradigms, workflows and even new keyboard shortcuts all over the place. This chapter will present an introduction to the various tools used in the everyday life of a seasoned Android developer.

1.1. TL;DR

As an introduction, these are the most important differences that distinguish the iOS developer experience from that of Android.

Table 1. Android vs. iOS Toolkits
Android iOS

IDE

Android Studio

Xcode

Profiling

Android Device Monitor

Instruments

Preview

Android Emulator

iOS Simulator

Programming Language

Kotlin or Java

Swift or Objective-C

Command Line

gradlew – ant

xcodebuild

Hacking

Rooting

Jailbreaking

Application metadata

AndroidManifest.xml

Info.plist

Dependency Manager

Gradle

CocoaPods – Carthage

Distribution

APK

IPA

Debugger

ADB + DDMS

LLDB

Logger

LogCat

NSLog() or print()

View Debugging

Hierarchy viewer

Xcode view debugging

Static Analysis

Android Lint

Clang Static Analyzer

1.2. Kotlin

For almost a decade, the only official language proposed by Google to create Android applications was Java. Since 2017, however, developers can use a new language called Kotlin, created by the same team that provides the Android Studio IDE.

Kotlin is a language that is 100% compatible and interoperable with Java; that means that all existing Java libraries can be used with Kotlin, and any binaries compiled with Kotlin can be integrated into standard Java projects. But it provides a much more "modern" syntax, with the following features:

  • Optionals and strict null checks

  • Type inference

  • Generics

  • Functional and object oriented features

  • Operator overloading

  • Pattern matching

Overhead

Using Kotlin in your Android project requires adding a small library used at runtime for interoperability with Java; this library increases the size of the final application in around one megabyte.

Kotlin compiles its code to native Android Runtime bytecode, which means that setting the small overhead of the runtime library aside, an application created with Kotlin behaves and is distributed exactly like one created with Java. Not only that, but you can mix and match Kotlin and Java code files in the same project without problem. Kotlin is able to access any JAR file compiled with Java, and Java is able to access anything defined in Kotlin.

This chapter offers a small overview of Kotlin; during the following chapters we are going to learn more about it just by using it in small projects.

Follow along

The code of this section is located in the Toolchain/Kotlin folder.

Variables and Constants

In Kotlin there are two types of in-memory storage: variables and constants. As the name implies, the former can be modified at runtime, while the latter cannot. To create them, just use var for variables and val for constants. The same syntax is used for class properties and for inline variables and constants.

Variables and constants
var variable = 43
val constant = "Hello"

var typedVariable: Float = 5.6F
val typedConstant: Boolean = true

var optionalVariable: Employee? = null
val optionalConstant: URL? = URL("https://sbb.ch")

var anyVariable: Any = "This can be anything"

var manager = Manager.managerFactory()
let is val

A very common problem when writing Kotlin with a Swift background is writing let instead of val. You have been warned.

String Interpolation

Whenever you need to compose a string with other values, you can simply interpolate variables using the $ sign.

String interpolation
val date = Date().toString()
val person = Employee("Johnny", 70)
print("Today is $date and ${person.name}'s age is ${person.age}")

You can use the ${obj.property} syntax to interpolate complex values or even calculations.

Parentheses and Brackets

There are two major differences between Kotlin and Swift regarding the use of parentheses and brackets in control flow statements such as if, while and for:

  1. Kotlin does require parentheses for if and while conditions, as well as the for statement.

  2. Kotlin does not require the use of curly brackets for their associated code blocks, just like in Java and many other languages.

Parentheses and brackets in Kotlin
val str = "Hello, Kotlin"

fun increase(value: Int): Int = value + 1

fun statements() {
    var i = 0
    while (i < 10) i = increase(i)
    if (str == "something") print(str)
}

The same code in Swift would look like this (pay attention to the placement of parentheses and brackets):

Parentheses and brackets in Swift
let str = "Hello, Swift"

func increase(_ value: Int) -> Int { return value + 1 }

func statements() {
    var i = 0
    while i < 10 { i = increase(i) }
    if str == "something" { print(str) }
}

Also pay attention to the fact that in Kotlin, if and when are expressions, not statements; this means that the following code is legal, although quite esoteric at first glance:

Expressions
val test = if (true) "Test" else "False"

val state = State.Off
fun decide() = when(state) {
    State.Off -> "Off"
    State.On -> "On"
}
val decision = decide()

Ranges

Ranges are very simple to create and use, and very similar to those in Swift.

Ranges
for (index in 1..5) {
    println("$index times 5 is ${index * 5}")
}
Double dot!

Please remember that to create ranges in Kotlin you need two dots, instead of just three as is the case in Swift.

Optional Types

Just like in Swift, Optional types are specified using the ? sign at the end of the class or type name; they indicate that a variable or constant can hold the null value. This makes it obvious in the code and to the compiler that some values might be null at runtime, while others may not. This makes your code safer and stronger.

Kotlin optionals
val optionalEmployee: Employee? = Employee("Olivia", 45)

val greeting = optionalEmployee?.greet()
println("greeting: $greeting")

val age = optionalEmployee?.age ?: 30 (1)

if (optionalEmployee != null) {
    val greetingAgain = optionalEmployee.greet()
    println("greeting: $greetingAgain")
    manager.addPerson(optionalEmployee)
}
1 The "Elvis" operator ?: assigns a default value to the age variable if the null check fails.

Instead of using the classic if (optional != null) construction, Kotlin provides the let() method, which works similarly to Swift’s if let statement:

Using the let optional methods
optionalEmployee?.let { (1)
    it.greet()
    println("Employee ${it.name} is ${it.age} years old")
}

optionalEmployee?.let { employee -> (2)
    employee.greet()
    println("Employee ${employee.name} is ${employee.age} years old")
}
1 By default, the "unboxed" value of the optional is stored inside of the it variable.
2 You can provide your own variable name if you want, using this syntax.

Optionals are a very modern and practical way to avoid null pointer exceptions. Code using optionals will clearly state the possibility that a reference contains a null value or not; in those cases, the use of a ? sign helps everyone who reads the code to understand what is going on.

Double bang!

Please remember that to unwrap a Kotlin optional you must use a "double bang" !! unlike Swift, which only requires one.

As a corollaire to their use, and similarly to the corresponding recommendation in Swift, you should pay attention never to abuse of the !! operator, which effectively tells the compiler "believe me, I know this reference is not null at this point in time." Once you tell your compiler this, it is your responsibility to actually make sure that the reference is never null, or your code could crash at runtime.

Smart Casting of Optionals

Kotlin automatically unwraps optionals that have been checked using if (optional != null), similarly to how Swift uses conditional binding with the if let syntax. This is shown in Android Studio as follows:

Smart casting in action
Figure 1. Smart casting in action

Collections

Kotlin can use the standard collection types available to Java, but it provides a simpler syntax, which makes them easier to use.

Collections
val stringArray = arrayOf<String>()
val stringList = listOf<String>()
val stringFloatMap = mapOf<String, Float>()
val stringSet = setOf<String>()

// Iterating over the elements of arrays, lists, maps and sets
for (str in stringArray) {
    println("A value in the array is '$str'")
}

for (str in stringList) {
    println("A value in the list is '$str'")
}

for ((str, num) in stringFloatMap) {
    println("Pair => $str: $num")
}

for (str in stringSet) {
    println("Set element: $str")
}

// Arrays vs Lists: which one to choose?
// An array has a fixed size and is usually very fast
val shoppingList = arrayOf("salt", "sugar", "milk", "cheese")
// You cannot add or remove items! This won't work:
// shoppingList.add("bread")
// but you can modify an individual item if needed
shoppingList[1] = "bottle of wine"

// If you need to add or remove items at runtime,
// consider using a mutable list instead:
val countries = mutableListOf<String>("Switzerland", "France", "Germany")
countries.add("Italy")
countries.remove("France")

val jobs = mutableMapOf(
        "Roger" to "CEO",
        "Martin" to "CTO"
)
jobs["Adrian"] = "Writer"
Collection creation syntax

As a Swift developer, please pay attention to the fact that in Kotlin one does not use [] to instantiate an empty array, but rather the arrayOf() function; the same applies to listOf(), mapOf(), and setOf(). This is a very common mistake for Swift developers new to Kotlin.

Pattern matching

Kotlin bundles powerful pattern matching capabilities, and includes the when expression, which is much more flexible than its switch counterpart in Java.

Pattern matching
val number = 42
when (number) {
    in 0..7, 8, 9 -> println("1 digit")
    10 -> println("2 digits")
    in 11..99 -> println("2 digits")
    in 100..999 -> println("3 digits")
    else -> println("4 or more digits")
}

Functions and Methods

Kotlin uses the keyword fun to define functions and methods. When functions are one-liners, they can have their body defined with the = sign, and they do not need to explicitly have a return type; it will be inferred from the returned value.

Pattern matching
fun method1(input: String): Int {
    return input.length
}

fun method2(input: String) = input.length

fun <T>method3(input: T) = input.toString()
In Kotlin, methods without an explicit return type do not use Void but Unit, and that means that they are actually returning a value even if this value is discarded at runtime.

Object-Oriented Programming

Kotlin is a fully featured object oriented language, including different useful features very similar to their Swift counterparts. Not only does it contain concepts such as classes and interfaces, but it also provides useful abstractions such as data classes and interface extensions.

Data classes provides a quick way to create typical "POJOs" (Plain Old Java Objects) in your apps, and as you might expect, interface extensions provides the possibility to include a default implementation for interface methods. This opens the door to powerful design patterns and flexible code, and also to use our "protocol oriented programming" techniques in Kotlin.

Interfaces

Kotlin interfaces are the equivalent of Swift protocols, and they also include extensions.

Interfaces
interface Person {
    (1)
    var name: String
        get set

    (2)
    fun greet() = "Hello! I am $this"

    (3)
    fun showMoreInformation()
}
1 Interfaces can specify properties and methods; in this case, a read-write property, to be implemented by subclasses.
2 This function provides a default implementation; classes implementing this interface can override this behaviour if needed.
3 This is a standard interface method, and just like in Java, classes must provide an implementation for it or otherwise the code will not compile.
Class Constructors

One of the most puzzling things about Kotlin for a Swift developer is the slightly uncommon syntax for constructors. The parameters of the class constructors are placed directly after the class declaration, including their visibility modifiers; they are not only the parameters of the constructor, but also the class fields, all in one definition.

Kotlin class constructor
class Manager(private var backingName: String = "",
              private var staff: MutableList<Person> = mutableListOf<Person>(),
              var state: State = State.Off) : Person {

To initialize class fields not part of the constructor parameters, or to perform some code at construction, you can provide an init method.

Init method
private val isActive: Boolean

init {
    isActive = true
}

In this example we use the init body to initialize a constant at construction time.

Data Classes

Kotlin also provides data classes which are the basis for POJOs; these classes provide automatically an implementation of hashCode() and toString().

Data class
data class Employee(private var backingName: String = "",
                    var age: Int = 30) : Person {

For all practical purposes, one can consider data classes as the Kotlin equivalent of Swift structs.

Class Instantiation

Once defined, you can use classes in your code using exactly the same syntax as you would in Swift:

Instantiating and using classes
val person1 = Employee("Olivia", 45) (1)

val person2 = Employee().apply { (2)
    name = "Thomas"
    age = 56
}
println("People: ${person1.greet()} and ${person2.showMoreInformation()}")

manager.addPerson(person1)
manager.addPerson(person2)
manager.state = State.On
1 The classic constructor call syntax in Kotlin is pretty much the same as in Swift.
2 This syntax, using the apply() function, will sound familiar to C# developers; it allows to customize a new instance, explicitly passing the values of the different parameters, resulting in very clear and explicit code.
Class Extensions

Kotlin allows you to extend any type with new properties and methods; this can be very powerful to create terse, more compact code and to place helper methods where they belong.

Defining class extensions
val Double.fahrenheit: Double get() = (this * 9 / 5) + 32
val Double.celsius: Double get() = (this - 32) * 5 / 9
Using class extensions
val temperature: Double = 32.0
val fahrenheit = temperature.fahrenheit
val celsius = fahrenheit.celsius
println("$temperature degrees Celsius is $fahrenheit degrees Fahrenheit")
Simple Objects and Singletons

Another nice feature of Kotlin is that you do not need to define a class to instantiate just an object; you can use the keyword object and define any static object that you need in your application, like singletons.

Data class
object Constants {
    val PI = 3.14
    val ANSWER = 42

    fun name() = "Math contstants"
}

This approach is commonly used in Android to define broadcast listeners or event handlers, for example.

Companion Objects

Kotlin classes do not have static members. If you need to provide static methods and constants to your classes, you must do so using a feature called companion object.

Companion object
companion object OptionalName {
    val MAXIMUM_EMPLOYEE_COUNT = 10

    fun managerFactory() = Manager("Maria Hill")
}

All variables, constants and functions inside of the companion object appear automatically as static members for the calling code. The companion object can have an optional name; in that case you can use it to access its members.

Operator Overloading

Kotlin makes it very easy to overload operators, since they are simply methods with specific names; we can, for example overload the + operator for any class by adding an operator fun plus() method with the required types.

Operator overloading
operator fun plus(person: Person): Team {
    return Team(this, person)
}

The table below gives an idea of the various operators that can be overloaded in Kotlin

Table 2. Overloading operators
Operator Method to override

+

unaryPlus()

-

unaryMinus()

!

not()

++

inc()

--

dec()

+

plus()

-

minus()

*

times()

/

div()

%

rem()

..

rangeTo()

in

contains()

[]

get() and set()

()

invoke()

+=

plusAssign()

-=

minusAssign()

*=

timesAssign()

/=

divAssign()

==

equals()

> < >=

compareTo()

Using overloaded operators is as simple as you might expect.

Using overloaded operators
val team = manager + person

As is the case with any language that provides operator overloading (such as C++ or Swift), make sure that using this feature actually increases the readability of the code.

Infix Methods

Kotlin allows methods taking just one parameter to be defined as infix.

Infix method
infix fun addPerson(person: Person) {
    if (staff.count() < MAXIMUM_EMPLOYEE_COUNT) {
        staff.add(person)
    }
    else {
        throw Exception("Cannot add more staff members")
    }
}

Using an infix method is like using an operator, without the need of a dot and parentheses, which may increase the readability of the code.

Using infix methods
manager addPerson person

Enumerations

If your application requires types that have only a few discrete values, you can simply define an enumeration to hold them all together.

Enumerations
enum class State {
    On,
    Off
}

Enumerations are fully-fledged classes, and can contain properties, functions and more.

Comparing Kotlin to Objective-C and Swift

The following table provides a comparison between these three languages.

Table 3. Comparison of Kotlin 1.2, Objective-C 2.0 and Swift 4
Kotlin 1.2 Objective-C 2.0 Swift 4

Inheritance

Simple, with interfaces and extensions

Simple, with protocols

Simple, with protocols and protocol extensions

Semicolons

Optional

Mandatory

Optional

Class definition

class

@interface & @implementation

class

Interfaces

implements interface

conforms to @protocol

conforms to protocol

Including code

import (symbols)

#import (files)

import (symbols)

Class extensions

Extensions

Categories

Extensions

Dynamic typing

Any

id

Any

Private field suffix

Not used

_ (underscore)

_ (underscore)

Memory management

Garbage collection

Manual or Automatic Reference Counting

Automatic Reference Counting

Generics

yes (type erasure)

yes (type erasure)

yes

Method pointers

no

@selector

#selector

Callbacks

Lambdas

Delegate objects and blocks

blocks

Pointers

no

yes

Via library classes

Root class

Object

NSObject / NSProxy / …

NSObject / NSProxy / …

Visibility

public / internal / protected / private

@public / @protected / @private (only fields)

open / public / internal / fileprivate / private

Exception handling

try / catch / finally + Exception

@try / @catch / @finally + NSException

do / try / catch + Error

Namespaces

Packages

Through class prefixes

Implicit, via modules

Formal grammar

kotlinlang.org

developer.apple.com

Converting Java Projects to Kotlin

To convert a Java project to Kotlin is very easy:

  1. Select the Tools  Kotlin  Configure Kotlin in Project menu entry. This will modify the Gradle files of the project to automatically include the Kotlin plugin for the modules.

  2. Once this is done, select the Java files you would like to convert in the Android pane on the left side of the Android Studio window, and select the Code  Convert Java File to Kotlin File menu entry.

The conversion from Java to Kotlin is usually quite fast and provides relatively good quality Kotlin code. You might need, depending on your project, to rewrite some Java idioms into Kotlin ones, particularly in what pertains to optionals.

Java and Kotlin in the same project

Remember that Android Studio projects can contain any number of both Java and Kotlin files, and they can coexist peacefully one next to the other. The Toolchain/Kotlin projects shows how a Kotlin class can use a Java class and viceversa.

The Android Runtime

Another important fact about Android is that, by design, the Java applications compiled for the Android operating system are not compatible with a standard Java Virtual Machine – JVM – such as the ones available for Windows, macOS or Linux. This simple fact is often overlooked but it is very important to remember.

Android and the JVM

Compiled Android Java applications are not compatibles with the standard Java Virtual Machine by Oracle.

Android applications are compiled as DEX binaries (which stands for "Dalvik Executables") and run in a special virtual machine, optimized for mobile devices, formerly known as "Dalvik" and now most commonly referred to as the Android Runtime (ART.) Binaries targeting the ART have the following characteristics:

  1. Developers can include Java code bundled in binary form, such as JARs (Java Archives) in their applications; they can also include the source files in their projects, but all of this will be compiled as Android DEX binaries, which has a different binary structure.

  2. Not all valid Java APIs for a standard JVM exist under ART; in particular most of the javax. packages are unavailable in Android.

  3. DEX files are smaller than their equivalent JARs.

  4. ART uses a register-based architecture, instead of the standard JVM stack-based architecture, in order to increase performance.

  5. ART uses non-JVM standard bytecode instructions, and a different inter-process protocol.

  6. ART can run several Android applications in the same process if required.

From Android 2.2 "Froyo" to Android 5 "Lollipop", a just-in-time compiler (JIT) had been added to the Dalvik virtual, helping it increase the performance of the final code. ART, on the other hand, single handedly compiles all downloaded apps to native code upon installation, and provides much better garbage collection and debugging facilities than Dalvik.

Compilation

The next diagram shows how close "APK" files are to the equivalent "IPA" files distributed by the Apple App Store. In both cases it consists of a compressed archive containing both the binary of the executable and all of its bundled resources, following a very particular folder structure.

diagram compilation
Figure 2. Android Application Compilation

Android Release History

The following table shows the history of Android releases, borrowed from Wikipedia, combined with information from the Android developer dashboard. This information is valid as of August 2017.

Table 4. Android Version History And Market Share
Code Name Version Number Release Date API Level Support status %

Alpha

1.0

September 23, 2008

1

Discontinued

Beta

1.1

February 9, 2009

2

Discontinued

Cupcake

1.5

April 27, 2009

3

Discontinued

Donut

1.6

September 15, 2009

4

Discontinued

Eclair

2.0 - 2.1

October 26, 2009

5 - 7

Discontinued

Froyo

2.2 - 2.2.3

May 20, 2010

8

Discontinued

Gingerbread

2.3 - 2.3.7

December 6, 2010

9 - 10

Discontinued

0.4%

Honeycomb

3.0 - 3.2.6

February 22, 2011

11 - 13

Discontinued

Ice Cream Sandwich

4.0 - 4.0.4

October 18, 2011

14 - 15

Discontinued

0.5%

Jelly Bean

4.1 - 4.3.1

July 9, 2012

16 - 18

Discontinued

5.9%

KitKat

4.4 - 4.4.4

October 31, 2013

19 - 20

Discontinued

13.4%

Lollipop

5.0 - 5.1.1

November 12, 2014

21 - 22

Supported

26.3%

Marshmallow

6.0 - 6.0.1

October 5, 2015

23

Supported

29.7%

Nougat

7.0 - 7.1.2

August 22, 2016

24 - 25

Supported

23.3%

Oreo

8.0 - 8.1

August 21, 2017

26 - 27

Supported

0.5%

As mentioned in the preface, the code samples that are bundled with this book support Lollipop (API 21) as their minimum requirement. This is because at the time of this writing, 80% of all Android devices in circulation run a version of Android equal or bigger to Lollipop.

1.3. Android Application Startup

When a user taps on the icon of an Android application a whole series of events happen in the device. Many of these events are very similar to those in iOS, and it turns out that, quite unsurprisingly, both operating systems use a very similar architecture, but with quite different class structures backing them.

Let us create a small project in Android Studio. In that project, add a subclass of the android.app.Application class, and register that class as the main application class in your AndroidManifest.xml file. Add two breakpoints in the source code, one in the Application.onCreate() method, and another in the MainActivity.onCreate() method.

The stack traces when hitting both breakpoints is shown below:

Application.onCreate()
training.akosma.startup.StartupApplication.onCreate(StartupApplication.java:8)
com.android.tools.fd.runtime.BootstrapApplication.onCreate(BootstrapApplication.java:370)
android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1012)
android.app.ActivityThread.handleBindApplication(ActivityThread.java:4553)
android.app.ActivityThread.access$1500(ActivityThread.java:151)
android.app.ActivityThread$H.handleMessage(ActivityThread.java:1364)
android.os.Handler.dispatchMessage(Handler.java:102)
android.os.Looper.loop(Looper.java:135)
android.app.ActivityThread.main(ActivityThread.java:5254)
java.lang.reflect.Method.invoke(Method.java:-1)
java.lang.reflect.Method.invoke(Method.java:372)
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
MainActivity.onCreate()
training.akosma.startup.MainActivity.onCreate(MainActivity.java:10)
android.app.Activity.performCreate(Activity.java:5990)
android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106)
android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2278)
android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387)
android.app.ActivityThread.access$800(ActivityThread.java:151)
android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303)
android.os.Handler.dispatchMessage(Handler.java:102)
android.os.Looper.loop(Looper.java:135)
android.app.ActivityThread.main(ActivityThread.java:5254)
java.lang.reflect.Method.invoke(Method.java:-1)
java.lang.reflect.Method.invoke(Method.java:372)
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)

There are several interesting bits of information in the stack traces above. First of all, the android.os.Looper class, which as the name suggests provides the main run loop of the application. Most GUI toolkits include a similar construction, created at application runtime, holding an event queue and routing events from the operating system to the different activities and components of the application.

Looper == NSRunLoop

For all practical purposes, iOS developers will recognize that the android.os.Looper class is the equivalent of the NSRunLoop class in Cocoa. If you want to learn more about Looper, please check the official Android documentation by Google.

If you click on the name of a class in Android Studio while holding down the key, the IDE will open the corresponding class file; if you do not have the Android source code available in your local workstation the IDE will simply decompile the code from the local SDK and show a stub implementation of the corresponding class, with most of its methods.

By doing this repeatedly, from both the MainActivity and the Application subclass you created previously, you are going to arrive to the android.content.Context class, which is arguably the most important class in the Android SDK. The Context class includes many different methods, ranging from file management to database creation to inter-process communication, and it also holds a reference to the underlying Looper class.

Equivalent in iOS

There is no similar equivalent of android.content.Context in iOS, however one could argue that NSResponder fulfills a similar role, since many different classes such as UIViewController, UIView and even UIApplication are all subclasses of NSResponder. However, Context is a very different beast from NSResponder!

The next diagram shows a simplified class hierarchy of the Activity and Application classes and its relationship with the Looper class.

diagram context class
Figure 3. The android.content.Context class

1.4. Zygote

One of the biggest problems with any Java Virtual Machine (JVM) is the long startup time. In the case of Android, this problem is even bigger, given the limited resources of many devices in the market. Moreover, since every application has to run its own copy of the JVM to ensure privacy and security through sandboxing, the price to pay would be too steep.

Zygote is the name of a process that Android runs as soon as the operating system stops booting. Its objective is to launch a copy of the Android Runtime (ART), which is Android’s version of the JVM, so that it is ready to use by every application in the system.

As soon as the user taps on the icon of an application to launch it, Android will ask Zygote to "fork" a copy of the JVM process, so that each application runs in its own sandbox, without conflicting with other processes. Zygote also preloads a certain number of libraries and resources that are usually required by most Android applications to run properly. All of this substantially speeds up the launching time of applications.

More about Zygote

If you want to know more about Zygote, this answer in Stack Overflow provides an excellent summary.

1.5. Android Studio

Android Studio is a free IDE provided by Google to develop Android applications. It replaced the venerable Eclipse Android Developer Tools, historically the first official IDE for Android software development for many years. It was announced for the first time in May 2013 at the Google I/O conference. The first stable release was in December 2014. It is available for Windows, macOS and Linux, and is now considered the official IDE for Android development.

End-of-life of the Eclipse Android Developer Tools

Google has announced in November 2nd, 2016 the official end of support and development of the Eclipse Android Developer Tools, which are completely superceded by Android Studio 2.2.

Android Studio is powered by IntelliJ IDEA, a popular IDE for Java development for the past 15 years. It has a solid reputation, and is particularly appreciated by its advanced support for refactoring, code generation and project navigation features.

Android Studio is available from the Android Studio website. The current version at the time of this writing is 3.0.1. Android Studio is, by far, the most important piece in the daily workflow of an Android Developer, and includes many different features targeted to simplify the development of Android apps, which like all software development can be quite a complex endeavour sometimes.

Android Studio Splashscreen
Figure 4. Android Studio Splashscreen

Once downloaded and launched, Android Studio will launch a configuration wizard. Most developers will choose the standard settings. Finally, Android Studio will automatically download all the elements required for it to work properly.

Android Studio Migrating Preferences
Figure 5. Android Studio Migrating Preferences
Android Studio Setup Wizard – Step 1
Figure 6. Android Studio Setup Wizard – Step 1
Android Studio Setup Wizard – Step 2
Figure 7. Android Studio Setup Wizard – Step 2
Android Studio Setup Wizard – Step 3
Figure 8. Android Studio Setup Wizard – Step 3
Android Studio Setup Wizard – Step 4
Figure 9. Android Studio Setup Wizard – Step 4
Android Studio Setup Wizard – Step 5
Figure 10. Android Studio Setup Wizard – Step 5

Once Android Studio is ready to go, it will display some tips and tricks every day – something you can easily dismiss if you want.

Android Studio Tips
Figure 11. Android Studio Tips
Android SDK Environment

Once Android Studio is installed, it is strongly recommended to configure the environment of your system to point to the folder where the Android SDK resides. In my system, I have added an ANDROID_HOME environment variable in my .zshrc file, as follows:

# Path for the Android SDK
export PATH=~/Library/Android/sdk/platform-tools:~/Library/Android/sdk/tools:"${PATH}"
# For Android stuff
export ANDROID_HOME=~/Library/Android/sdk

Creating a New Project

To create a new project in Android Studio , just select the File  New  New Project menu item, and follow the instructions as shown in the following screenshots.

New Project Wizard – Step 1
Figure 12. New Project Wizard – Step 1
New Project Wizard – Step 2
Figure 13. New Project Wizard – Step 2
New Project Wizard – Step 3
Figure 14. New Project Wizard – Step 3
New Project Wizard – Step 4
Figure 15. New Project Wizard – Step 4

After running the project wizard, Android Studio should show you a windows similar to the one featured in the image below.