📌 Android is an operating system, like Windows and MacOS. Unlike those two systems, Android is a Linux-based OS, like Ubuntu and Red Hat. Unlike Ubuntu and Red Hat, though, Android has been very heavily optimized for mobile devices—battery-powered mobile devices, in particular.
The Android Stack
- A piece of warm silicon. While the hardware is not part of the Android stack, it is important to recognize that the hardware for which Android was designed imposes some fairly tough constraints on the system. By far, the most significant of these constraints is power. Most common operating systems just assume an infinite power supply. The Android systems cannot.
- The Android operating system depends on the Linux kernel.
- A kernel is responsible for providing the basic services that developers expect: a filesystem, threads and processes, network access, interfaces to hardware devices, and so on.
- Linux is free and open source and, thus, a popular choice for hardware and device manufacturers.
- The system services layer is big and complex.
- It includes a wide variety of utilities, from code that runs as part of the kernel (drivers or kernel modules), and long-running applications that manage various housekeeping tasks (daemons), to libraries that implement standard functions like cryptography and media presentation.
- This layer includes several system services that are unique to Android. Among them are Binder, Android’s essential interprocess communication system; ART, which has replaced Dalvik as Android’s analog of the Java VM; and Zygote, Android’s application container.
- ART and its predecessor Dalvik were originally created specifically for the Android project. ART as the runtime executes the Dalvik Executable format and Dex bytecode specification.
- The layer above the system services is the implementation of the Android Runtime Environment.
- The Android Runtime Environment is the collection of libraries that you use from your application by including them with
importstatements: android.view, android.os, and so on. They are the services provided by the layers below, made available to your application. They are interesting because they are implemented using two languages: usually Java and C or C++.
- The top of the stack are Android applications.
- Applications, in the Android universe, are actually part of the stack.
- They are made up of individually addressable components that other applications can “call.” The Dialer, Camera, and Contacts programs are all examples of Android applications that are used as services by other applications.
The Android Application Environment
- Android applications are programs translated from a source language (Java or Kotlin) into a transportable intermediate language, DEX.
- The DEX code is installed on a device and interpreted by the ART VM, when the application is run.
- Android apps are libraries of components. The Android runtime, Zygote, manages processes, lifecycles, and so on. It calls an application’s components only when it needs them.
- Component subclasses override the methods that are called by the framework in order to provide application-specific behavior.
- Often, the superclass has important work to do when one of these template methods is called. In those cases, the overriding method in the subclass must call the superclass method that it overrides.
- Android supports four types of components:
- Broadcast receiver
- Content provider
- The implementations of these components must be registered in a manifest: AndroidManifest.xml.
Intentis a small packet that names the component that it targets.
- Components are started with
- An intent as a function call.
- This code fires an
Intentfired by this line of code is called an explicit intent because it names a specific, unique class, in a unique application (identified by a
Context, discussed in a moment), to which the
Intentis to be delivered.
- Imagine that the email application you’ve had on your phone for years allows editing messages with an external editor. We now can guess that it does this by firing an intent that might look something like this:
val intent = Intent(Intent.ACTION_EDIT))
- The target specified in this intention is not explicit. The
Intentspecifies neither a
Contextnor the fully qualified name of a component within a context. The intent is implicit and Android will allow any component at all to register to handle it.
- Because Android components are just subsystems run in a larger container, they need some way of referring to the container so that they can request services from it. From within a component, the container is visible as a
Contexts come in a couple of flavors: component and application. Let’s have a look at each of them.
- This call uses a
Contexttwice. First, starting an
Activityis a function that a component requests from the framework, the
Context. In this case, it called the
startActivity. Next, in order to make the intent explicit, the component must identify the unique package that contains the component it wants to start. The
Intent’s constructor uses the
contextpassed as its first argument to get a unique name for the application to which the
contextbelongs: this call starts an
Activitythat belongs to this application.
Contextis an abstract class that provides access to various resources, including:
- Starting other components
- Accessing system services
SharedPreferences, resources, and files.
- When Android starts an application, it usually creates a singleton instance of the
Applicationclass. That instance is a
Contextand, though it has a lifecycle, that lifecycle is essentially congruent with the lifecycle of the application. Because it is long-lived, it is quite safe to hold references to it in other long-lived places.
Android Application Components: The Building Blocks
The lifecycles of Android application components are managed by the Android framework, which creates and destroys them according to its needs.
The activity lifecycle
- Fires when the system first creates the activity.
- Basic application startup logic that should happen only once for the entire life of the activity.
- Makes the activity visible to the user, as the app prepares for the activity to enter the foreground and become interactive.
- This method is where the app initializes the code that maintains the UI.
onStart()method completes very quickly and, as with the Created state, the activity does not stay resident in the Started state.
- Once this callback finishes, the activity enters the Resumed state, and the system invokes the
- When the activity enters the Resumed state, it comes to the foreground, and then the system invokes the
- This is the state in which the app interacts with the user.
- The app stays in this state until something happens to take focus away from the app.
- Such an event might be, for instance, receiving a phone call, the user’s navigating to another activity, or the device screen’s turning off.
- The system calls this method as the first indication that the user is leaving your activity (though it does not always mean the activity is being destroyed); it indicates that the activity is no longer in the foreground (though it may still be visible if the user is in multi-window mode).
- Use the
onPause()method to pause or adjust operations that should not continue (or should continue in moderation) while the
- Paused activity may still be fully visible if in multi-window mode.
- When your activity is no longer visible to the user, it has entered the Stopped state, and the system invokes the
- This may occur, for example, when a newly launched activity covers the entire screen. The system may also call
onStop()when the activity has finished running, and is about to be terminated.
onDestroy()is called before the activity is destroyed. The system invokes this callback either because:
- The activity is finishing (due to the user completely dismissing the activity or due to
finish()being called on the activity), or
- The system is temporarily destroying the activity due to a configuration change (such as device rotation or multi-window mode)
- The activity is finishing (due to the user completely dismissing the activity or due to
Fragments are an afterthought added to Android’s stable of component-like features only at version 3 (Honeycomb, 2011).
- They were introduced as a way of making it possible to share UI implementations across screens with shapes and sizes so different that it affects navigation: in particular, phones and tablets.
Fragments are not
Contexts. Though they hold a reference to an underlying
Activityfor most of their lifecycle
Fragments are not registered in the manifest. They are instantiated in application code and cannot be started with
Fragmentas something like an iframe on a web page: almost an
Activityembedded in an
- Android supports a navigation paradigm sometimes called card-deck navigation.
- Navigating to a new page stacks that page on top of the previous page.
- When a user presses a back button the current page is popped from the stack to reveal the one that previously held the screen.
- This paradigm is fairly intuitive for most human users: push new cards on top; pop them off to get back to where you were.
Serviceis an Android component that is, almost exactly, an
Activitywith no UI. That may sound a bit odd, given that an
Activity’s sole reason for existence is that it manages the UI!
- Perform long-running tasks that are not attached to any UI: monitoring location, synchronizing a dataset over the network, and so on.
- There are two different kinds of
Service: bound and started.
- REST-like interface to data held by an application. Because it is an API, not simply direct access to data, a
ContentProvidercan exercise very fine-grained control over what it publishes and to whom it publishes it.
- External applications get access to a
- The original concept for a
BroadcastReceiverwas as a kind of data bus.
- Listeners could subscribe in order to get notification of events that were of interest.
- The most common use of a
BroadcastReceiveris as a way of starting an application, even if there has been no user request to do so.