#Mobile Applications
Smartphones and tablets are considered to be mobile devices running a graphical user interface. There are some caveats when comparing desktop and mobile applications:
- Mobile applications are smaller, obviously, since they tend to be designed for hand-held devices (and not large computer screens).
- Mobile applications use multi-touch as a primary input mechanism. These applications might support keyboard input, but it's secondary to touch.
- Applications are typically run full-screen, and most mobile operating systems do not support windowed applications.
Mobile devices often have similar graphical and processing capabilities and low-end notebook or desktop computers; the limits on these devices are often related to the challenge of interacting with a rich UI on a small screen.
You should expect most interaction to consist of multi-touch gestures or on-screen actions that you perform. The following are common gestures:
- Press: select the target under the point of contact and activate it (i.e. analogous to single-click with a mouse)
- Long-press: equivilent to right-clicking on an element.
- Swipe: move or translate content.
- Tap-swipe: move a chunk e.g. page up or page down.
- Pinch/zoom: change the scale of the content.
For text entry and manipulation, you should support a soft keyboard (i.e. on-screen). Do not assume that the user has a physical keyboard connected. When possible show a keyboard optimized for region and data that you're collecting e.g. a numeric keyboard for entering phone numbers.
Do not assume mouse or stylus, except under very specific circumstances where you know they will exist. e.g. building a drawing application optimized for a stylus.
Challenges that are unique to mobile devices:
- Given the screen size issues, menus are a bad idea. Widgets should be considerably larger than they would be on desktop to support touch interaction.
- Keyboard support is limited. Mobile devices tend to rely on "soft" on-screen keyboards. On-screen keyboards lack tactile feedback, are slower and less accurate than physical keyboards.
- The configuration of a mobile device can change dynamically e.g. rotating the device from vertical to horizontal generally causes the screen to "rotate" to match the new configuration.
#Getting started
Android is an open-source, Linux based operating system designed to run across a variety of devices and form-factors. It's an example of a layered architecture, which increasing levels of abstraction as we move from the low-level hardware to higher-level application APIs. Mid-level components exist to provide services to components futher up the stack.

#Install the SDK
To work in Android, you need to install the Android SDK from the Android Developer Site. You have two options for coding your Android project.
- Android Studio is a fork of IntelliJ IDEA supported Google. It can downloaded from the Android Developer Site and it's optimized for Android development. It's recommended for mobile, but NOT desktop development. If you install this, it includes the Android SDK.
- IntelliJ IDEA has full support for Android. You can use IntelliJ IDEA Community Edition, which includes an Android plugin by default. This is a general IDE that can be used for both Android and desktop development. If you install this, you will need to separately install the Android SDK.
Android SDK
Regardless of which IDE you choose, you will need to install the Android SDK. It's bundled with Android Studio, so it's easiest to install that to get the SDK, and then use whichever IDE you prefer.
#Create a new project
In Android Studio, select File
> New
> New Project
. This will launch the New Project Wizard. (In IntelliJ IDEA, select File
> New
> Project
and choose Android
from the list of project types.)

In this example, we'll just use the Empty Activity
project, and keep default settings. This will generate a Hello World
style application.

#Installing a virtual device
With mobile development, it's quite common to use virtual devices
for testing (instead of needing to purchase every model of phone that you need to support).
You can setup a device in the IDE under: Tools
> Android
> Device Manager
.

"Run" the device, click on the Power button and it should power up! By default, the IDE will install and run from this virtual device.

#Compile and package
Android projects use Gradle, with the standard Gradle project configuration. However, for performance reasons, Android Studio doesn't populate or update the Gradle tasks lists automatically. For that reason, the Gradle menu appears mostly empty.

Instead of using the Gradle menu, rely instead on the Build
and Run
menus:
When you build an Android executable, it compiles your code along with any required data or resources files into an APK file, an archive file with an .apk
suffix. This is installed on the device automatically by the IDE.
#Android platform
As a developer, the entire feature-set of the Android OS is available to you through APIs written in Java and/or Kotlin1. These APIs form the building blocks you need to create Android apps by providing critical services: :
- A rich and extensible View System you can use to build an app’s UI, including lists, grids, text boxes, buttons, and even an embeddable web browser
- A Resource Manager, providing access to non-code resources such as localized strings, graphics, and layout files
- A Notification Manager that enables all apps to display custom alerts in the status bar
- An Activity Manager that manages the lifecycle of apps and provides a common navigation back stack
- Content Providers that enable apps to access data from other apps, such as the Contacts app, or to share their own data
Android also includes a set of core runtime libraries that provide most of the functionality of the Java programming language, including some Java 8 language features, that the Java API framework uses.
For devices running Android version 5.0 (API level 21) or higher, each app runs in its own process and with its own instance of the Android Runtime (ART). ART is written to run multiple virtual machines on low-memory devices by executing DEX files. ART provides Ahead-of-time (AOT) and just-in-time (JIT) compilation, and Optimized garbage collection (GC) to the platform2.
#Project structure
Android uses Gradle, so the project structure should look similiar to earlier projects. Expand the Project folder (CMD-1 or Ctrl-1) to see the contents of the project.

#src folder
The src
folder contains source code, nested into a directory structure that matches the package name of your classes. In the example above, src/main/java
is the top level source code folder, and net.codebot
is the package name. FirstFragment
, MainActivity
and SecondFragment
are classes that exist in this project.
#res folder
The res
folder contains resources for your project: sounds, images and other useful files that aren't source code.

Resources in Android also include XML files, which are commonly used to store application data. The following subfolders are used:
- The
drawable
folder contains images that you wish to draw on-screen (directly, or on a widget). It also contains default icons for your application. - Under the
layout
folder, we have XML files represent a screen layout. IntelliJ IDEA includes a GUI builder for creating layouts and saving them as XML. These can be loaded dynamically to instantiate a screen at runtime. - The
values
folder contains XML files with application constants: colours, themes, titles, help text etc.
#Manifest File
The AndroidManifest.xml
file is generated with your project; one is reproduced below. This file contains settings that tell the application how to present itself on Android e.g. icon, label, theme. The activity
element tells is which class to launch when the application launches. Other permissions and settings can be added in here as-needed.
You should be very careful when modifying this file! If you remove critical settings, or break the formatting, your project may not build.
#Components
There are four different types of core components that can be created in Android. Each represents a different style of application, with a different entry point and lifecycle.
These four component types exist in Android:
- An Activity is an Android class that represent a single screen. It handles drawing the user interface (UI) and managing input events. An application may include multiple activities, where one is the "entry point".
- A Service is a general-purpose background service, representing some long-running operation that the OS should perform, which does not require a user-interface. e.g. a music playback service.
- Broadcast Receivers: A service that can launch itself in response to a system event, without the need to stay running in the background like a regular service. e.g. an application to pop up a reminder when the user arrives at a destination.
- Content Providers managed shared information that other services or applications can access. e.g. a shared contact database.
#Activities
Activities are the most common type of component, since they include user interfaces and visible components.
Typically one activity will be the "main" activity that represents the entry point when your application launches.
There are a standard set of steps that occur when your Android application launches. The system uses the information in the AndroidManifest.xml
to determine which activity to launch, and how to launch it. In this case, it's a class named MainActivity
:
The MainActivity
is a class that extends AppCompatActivity
. This is a base class that supports all modern Android features while providing backward compatibility with older versions of Android. For compatibility with older version of Android, you should always use AppCompatActivity as a base class.
Our base class contains a number of methods. The onCreate()
method is the first method that is called when the MainActivity
is instantiated. Here's a basic onCreate()
method:
Activities typically have an associated layout file which describes their appearance. The activity and the layout are connected by a process known as layout inflation. When the activity starts, the views that are defined in the XML layout files are turned into (or "inflated" into) Kotlin view objects in memory. Once this happens, the activity can draw these objects to the screen and also dynamically modify them 3.
R.layout.activity_main
in this example corresponds to the layout/activity_main.xml
file. That file contains the full layout for the screen, including the top toolbar. There are multiple pieces to this particular layout, so the line <include layout="@layout/content_main"/>
is including the contents of a second layout file (just split up to make it easier to manage).
#Activity Lifecycle
Applications consist of one or more running activities, each one corresponding to a screen.
Activities in the system are managed as activity stacks. When a new activity is started, it is usually placed on the top of the current stack and becomes the running activity -- the previous activity always remains below it in the stack, and will not come to the foreground again until the new activity exits.
An activity can be one of the following running states:
- The activity in the foreground, typically the one that user is able to interact with, is running.
- An activity that has lost focus but can still be seen is visible. It will remain active.
- An activity that is completely hidden, or minimized is stopped. It retains its state (it's basically paused) BUT the OS may choose to terminate it to free up resources.
- The OS can choose to destroy an application to free up resources.
This diagram shows the possible states:

https://developer.android.com/reference/android/app/Activity#Fragments
These phases correspond to the following callback methods. You can override a method in your Activity to add code that will get exexuted when the applicaiton enters or exits a particular stage:
There are three key loops that these phases attempt to capture:
The entire lifetime of an activity happens between the first call to
onCreate(Bundle)
through to a single final call toonDestroy()
. An activity will do all setup of "global" state in onCreate(), and release all remaining resources in onDestroy(). For example, if it has a thread running in the background to download data from the network, it may create that thread in onCreate() and then stop the thread in onDestroy().The visible lifetime of an activity happens between a call to
onStart()
until a corresponding call toonStop()
. During this time the user can see the activity on-screen, though it may not be in the foreground and interacting with the user. Between these two methods you can maintain resources that are needed to show the activity to the user. For example, you can register aBroadcastReceiver
in onStart() to monitor for changes that impact your UI, and unregister it in onStop() when the user no longer sees what you are displaying. The onStart() and onStop() methods can be called multiple times, as the activity becomes visible and hidden to the user.The foreground lifetime of an activity happens between a call to
onResume()
until a corresponding call toonPause()
. During this time the activity is in visible, active and interacting with the user. An activity can frequently go between the resumed and paused states -- for example when the device goes to sleep, when an activity result is delivered, when a new intent is delivered -- so the code in these methods should be fairly lightweight.https://developer.android.com/reference/android/app/Activity#Fragments
#Activity Stacks
A task is a collection of activities that users interact with when performing a certain job. The activities are arranged in a stack—the back stack)—in the order in which each activity is opened. For example, an email app might have one activity to show a list of new messages. When the user selects a message, a new activity opens to view that message. This new activity is added to the back stack. If the user presses the Back button, that new activity is finished and popped off the stack.
The device Home screen is the starting place for most tasks. When the user touches an icon in the app launcher (or a shortcut on the Home screen), that app's task comes to the foreground. If no task exists for the app (the app has not been used recently), then a new task is created and the "main" activity for that app opens as the root activity in the stack.
The device Home screen is the starting place for most tasks. When the user touches an icon in the app launcher (or a shortcut on the Home screen), that app's task comes to the foreground. If no task exists for the app (the app has not been used recently), then a new task is created and the "main" activity for that app opens as the root activity in the stack.
When the current activity starts another, the new activity is pushed on the top of the stack and takes focus. The previous activity remains in the stack, but is stopped. When an activity stops, the system retains the current state of its user interface. When the user presses the Back button, the current activity is popped from the top of the stack (the activity is destroyed) and the previous activity resumes (the previous state of its UI is restored). Activities in the stack are never rearranged, only pushed and popped from the stack—pushed onto the stack when started by the current activity and popped off when the user leaves it using the Back button. As such, the back stack operates as a "last in, first out" object structure.

If the user continues to press Back, then each activity in the stack is popped off to reveal the previous one, until the user returns to the Home screen (or to whichever activity was running when the task began). When all activities are removed from the stack, the task no longer exists.
This is standard behaviour for most applications. For unusual workflows, you can manually manage tasks.
#Fragments
A Fragment
represents a reusable portion of your app's UI. A fragment defines and manages its own layout, has its own lifecycle, and can handle its own input events. Fragments cannot live on their own--they must be hosted by an activity or another fragment. The fragment’s view hierarchy becomes part of, or attaches to, the host’s view hierarchy.
Fragments introduce modularity and reusability into your activity’s UI by allowing you to divide the UI into discrete chunks. Activities are an ideal place to put global elements around your app's user interface, such as a navigation drawer. Conversely, fragments are better suited to define and manage the UI of a single screen or portion of a screen.

A fragment represents a modular portion of the user interface within an activity. A fragment has its own lifecycle, receives its own input events, and you can add or remove fragments while the containing activity is running.
To create a fragment, extend the AndroidX Fragment
class, and override its methods to insert your app logic, similar to the way you would create an Activity
class. To create a minimal fragment that defines its own layout, provide your fragment's layout resource to the base constructor, as shown in the following example:
Generally, your fragment must be embedded within an AndroidX FragmentActivity
to contribute a portion of UI to that activity's layout. FragmentActivity
is the base class for AppCompatActivity
, so if you're already subclassing AppCompatActivity
to provide backward compatibility in your app, then you do not need to change your activity base class.
You can add your fragment to the activity's view hierarchy either by defining the fragment in your activity's layout file or by defining a fragment container in your activity's layout file and then programmatically adding the fragment from within your activity.
Here's an example activity layout containing a single FragmentContainerView
:
The android:name
attribute specifies the class name of the Fragment
to instantiate. When the activity's layout is inflated, the specified fragment is instantiated, onInflate()
is called on the newly instantiated fragment.
To programmatically add a fragment to your activity's layout, the layout should include a FragmentContainerView
to serve as a fragment container, as shown in the following example:
While your activity is running, you can make fragment transactions such as adding, removing, or replacing a fragment. In your FragmentActivity
, you can get an instance of the FragmentManager
, which can be used to create a FragmentTransaction
.
#Intents
An intent is an asynchronous message, that represents an an operation to be performed. This can include activating components, or activities. An intent is created with an Intent
object, which defines a message to activate either a specific component (explicit intent) or a specific type of component (implicit intent).
Applications then, consist of a number of different component working together. Some of them you will create, and some are preexisting components that you can activate (e.g. you can create an intent requesting that the camera take a picture; you don't need to write code to make that happen, you just need to use the intent to ask someone else to take it for you and return the data).
#Launch with intent
Similarly, intents can be used to activate an Activity. The startActivity(Intent)
method is used to start a new activity, which will be placed at the top of the activity stack. It takes a single argument, an Intent
, which describes the activity to be executed. To be of use with Context.startActivity()
, all activity classes must have a corresponding <activity>
declaration in their package's AndroidManifest.xml
.
Sometimes you want to get a result back from an activity when it ends. For example, you may start an activity that lets the user pick a person in a list of contacts; when it ends, it returns the person that was selected. To do this, you call the startActivityForResult(Intent, int)
version with a second integer parameter identifying the call. The result will come back through your onActivityResult(int, int, Intent)
method.
#Bundles
Parcelable and Bundle objects are intended to be used across process boundaries such as with IPC/Binder transactions, between activities with intents, and to store transient state across configuration changes.
When an app creates an Intent
object to use in startActivity(android.content.Intent)
in starting a new Activity, the app can pass in parameters using the putExtra(java.lang.String, java.lang.String)
method. This creates a bundle that is passed to the new Activity (and automatically unpackaged by the new Activity).
The OS parcels the underlying Bundle
of the intent. Then, the OS creates the new activity, un-parcels the data, and passes the intent to the new activity, which can fetch the data from the intent.
#ViewModel
One major challenge when working with Android is the need to handle lifecycle changes: activities can be paused or stopped, and fragments can go out-of-scope. This makes data sharing between components very difficult.
There's numerous ways to address this, including saving data to a bundle, or manually persisting to a data store. Jetpack Compose
introduces classes to manage this for us.
The ViewModel
class is designed to store and manage UI-related data in a lifecycle conscious way. The ViewModel
class allows data to survive configuration changes such as screen rotations.
Assigning excessive responsibility to UI controllers can result in a single class that tries to handle all of an app's work by itself, instead of delegating work to other classes. Assigning excessive responsibility to the UI controllers in this way also makes testing a lot harder.
It's easier and more efficient to separate out view data ownership from UI controller logic.
Architecture Components provides ViewModel
helper class for the UI controller that is responsible for preparing data for the UI. ViewModel
objects are automatically retained during configuration changes so that data they hold is immediately available to the next activity or fragment instance. For example, if you need to display a list of users in your app, make sure to assign responsibility to acquire and keep the list of users to a ViewModel
, instead of an activity or fragment.
You can then access the list from an activity as follows:
If the activity is re-created, it receives the same MyViewModel
instance that was created by the first activity. When the owner activity is finished, the framework calls the ViewModel
objects's onCleared()
method so that it can clean up resources.
#The lifecycle of a ViewModel
ViewModel
objects are scoped to the Lifecycle
passed to the ViewModelProvider
when getting the ViewModel
. The ViewModel
remains in memory until the Lifecycle
it's scoped to goes away permanently: in the case of an activity, when it finishes, while in the case of a fragment, when it's detached.
Figure 1 illustrates the various lifecycle states of an activity as it undergoes a rotation and then is finished. The illustration also shows the lifetime of the ViewModel
next to the associated activity lifecycle. This particular diagram illustrates the states of an activity. The same basic states apply to the lifecycle of a fragment.

It's very common that two or more fragments in an activity need to communicate with each other.
This can be addressed by using ViewModel
objects. Fragments can share a ViewModel
using their activity scope to handle this communication.
Navigation refers to the ability to move between screens or activities within an application. This includes simple scenarios e.g., click a button to navigate, to complex cases like the Android navigation drawer.
The Navigation classes were originally designed to work with fragments
(you can think of them as pieces of a UI), which have since been superceded by Jetpack Compose. We'll discuss using these classes on Android, assuming Jetpack Compose.
The built-in navigation classes are only fully supported on Android, not Compose Multiplatform/Desktop. If you are working with Compose Multiplatform, or want something that feels a little more "idiomatic", you might consider a third-party navigation library instead e.g., Voyager.
There are three components that work together:
- Navigation graph - resource i.e. XML file that defines routes.
- NavHost - UI element that contains the current navigation destination.
- NavController - Coordinator for managing navigation.
Best practices for working within Compose is to create a single activity, and then use navigation components to tear-down and build-up the single activity to reflect how you want the screen to appear.
Here's the steps you would take to use the Navigation components:
To create a NavController when using Jetpack Compose, call rememberNavController():
The nav graph is just a data structure that holds our routes between screens. Since this is Compose, we'll create everything programatically.
If you need to pass data to a destination, define the route with a class that has parameters. For example, the Profile route is a data class with a name parameter.
To navigate to a composable, you should use NavController.navigate<T>
. With this overload, navigate()
takes a single route argument for
which you pass a type. It serves as the key to a destination.
Android Developer Relations has published an excellent codelab, which will help you learn how to use Jetpack Navigation. See this page to get started.
#Features
#Create a main method
Android projects are structured differently from desktop projects. Instead of a main
method, you have a main Activity
class. Think of an activity as a single screen, and the main Activity is the screen that launches with the application. The onCreate()
method is the entry point for your main Activity, and the method that we will override to set up our application.
Here is the starter code that is generated:
This basic structure does the following:
class MainActivity
is just defining the activity class that we'll use.override fun onCreate()
is the callback function that we'll override. This gets called when the application is launched.setContent()
is a scoping function that defines our composable scope! Composables can be called from within this function.MyApplicationTheme
is just an override of theMaterialTheme
class (Android expects you to customize it by default).Surface
is a composable layout that we can use to hold our other composables.
The rest of the structure should look familiar, since it's all just Compose! You should be able to swap out everything in the setContent
block with Compose code that you write.
#Handle touch input
onClick
handlers can be used in mobile applications as well, and correspond to a touch of on-screen elements.