Android
Android is an operating system developed by Google. Native android applications are developed in Kotlin mostly using Android Studio.
- Android Courses + CodeLabs (official, free)
- Android Docs
- Android Guides
- Android Teach (slides...)
- Android UI and Material Design (Google UI Guidelines)
- Android Compose and Jetpack Compose (New Way To Build UI)
β‘οΈ Google recommends using Kotlin over Java since 2019.
Android projects are managed by Gradle. It's used to:
- π manage dependencies (import a library...)
- βοΈ compile the code
- ποΈ generate the APK (Android Package) installed on devices
You will have to edit the second build.gradle (Module: XXX)
.
Android Framework
Application
An Android application corresponds to an instance of the Application class. The default implementation is usually enough.
Activities and fragments
Applications are made of activities. An activity is most of the time a screen of an application (ex: the login screen).
In practice, an activity typically corresponds to a specific task or user interaction (ex: we may group the register and login screen in one activity).
Activities are associated with one "screen". When we choose to display multiple screens during one activity, we can use fragments.
A fragment is a modular reusable UI component ("screens", menubar...).
π You can create apps without any fragments. Using fragments is a choice based on stuff like data handling, code reuse, modularity...
β‘οΈ See also: Single Activity Pattern.
Activity/Fragment lifecycle
Both activities and fragments have a lifecycle which we need to be familiar with in order to know where we will write our code.
For instance, code to handle an event, such as a click on a button, would be in onCreate()
(activity) or onViewCreated()
(fragment).
View and ViewGroups
A view is a visual element such as a Button. They are grouped in containers called ViewGroups to apply styles on multiple views or create responsive screens (i.g., adapting to the size of the screen).
AndroidManifest.xml
The Android Manifest defines things like:
- π the first activity executed when starting the application
- π the permissions required by the application
- ποΈ the activities, services, and other components...
- ...
Model View ViewModel (MVVM)
Model View ViewModel, or MVVM for short, is a popular architectural design pattern in which
- π¦ The model is the classes used to store Data
-
data class XXX(...)
- They are usually stored in
.data
- Classes interacting with the API/Room/the FileSystem...
-
- πΌοΈ The view is what is displayed to the user
- Most XML displayed (res/layout, res/menu...)
- They are usually stored in
.ui.viewname
- π The ViewModel (ViewModel + LiveData)
- They are usually stored in
.ui.viewname
with their View - See also: DataBinding
- They are usually stored in
The "main" component is the ViewModel. This is a component that will link the View with the model. When the model is updated, it will update the View. When the View is updated, it will update the model.
- β Controllers (Activities, Fragments)
There are still controllers like in MVC. They are responsible for rendering the view, and listening to events.
Android Application
When an Android application is started, it instantiates the Application
class which loads the main activity.
π The default implementation is enough most of the time.
Use case: run code only once
Code loaded in an Activity will be run when we navigate between activities, when we rotate the screen... The only way to run code once is inside Application#onCreate
.
Ex: the code to create notification channels (see notifications).
Use case: Listen for application-level changes
Ex: app foreground/background
-class MainApplication : Application() {
+class MainApplication : Application(), DefaultLifecycleObserver {
override fun onCreate() {
super<Application>.onCreate()
+ ProcessLifecycleOwner.get().lifecycle.addObserver(this)
}
+ override fun onStart(owner: LifecycleOwner) {
+ // App in the foreground
+ }
+ override fun onStop(owner: LifecycleOwner) {
+ //App in the background
+ }
}
class MainApplication : Application() {
override fun onCreate() {
super.onCreate()
}
}
In your AndroidManifest.xml, look for the tag "application", and add an attribute "android:name" pointing to your newly created file.
<application
...
android:name=".MainApplication"
/>
Activities
Activities are screens of an application, while in fact, one activity can serve multiple screens using fragments according to the app design.
- π Activities must be declared in AndroidManifest.xml
- π The first screen is usually called "MainActivity"
- π An activity is associated with one layout (ex: R.layout.activity_main)
A short version to declare an activity:
class MainActivity : AppCompatActivity(R.layout.activity_main) {
}
The extended and most commonly used version is:
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Load the associated layout
setContentView(R.layout.activity_main)
}
}
Activity lifecycle
Android activities' lifecycle is a bit complex. To summarize,
- π onCreate is where you will configure the view
- π Before presenting the activity, onStart is called. If the user press "home"/the activity isn't visible anymore, onStop is called.
- π Before the user can interact with the activity, onResume is called. If the user isn't able to interact with the activity anymore, onPause is called. The activity is still visible.
As for onDestroy, it is called
- when the user closes the app
- when the system terminates the app (to free up memory...)
- when it's easier to kill and recreate the app
- π€ the language changed
- β οΈ the rotation changed (don't forget to enable rotation on the phone, especially on emulated devices, as it's disabled by default)
β‘οΈ When needed, you can override these methods.
Note: onPause must be lightweight, otherwise it will delay the other application from showing up in the front screen (ex: a call).
Note (2): A bundle is a small, in-memory, dictionary. It's passed to onCreate, if the app was recreated. See onRestoreInstanceState and onSaveInstanceState too, if you want to use it to store/load data.
Fragments
Fragments are in many ways similar to activities. They are loaded by an activity, but they have their own lifecycle.
- π
Activity#onCreated
was split into 3 methods - π New methods and attributes are present to access some attributes/methods that were available in an activity
- Use
requireActivity()
to get the parent Activity - Use
activity
to get the parent Activity (@Nullable) - ...
- Use
Create a fragment
- File > New > fragment > [select a template]
BlankFragment template
class BlankFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Load the associated View
return inflater.inflate(R.layout.fragment_blank, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// See View to configure the view (listeners...)
// use "view.xxx()" instead of "xxx()"
// ex: view.findViewById<XXX>(...)
}
}
Load a fragment in an activity
β‘οΈ See also: Navigation Component.
The Fragment lifecycle is as follows.
π Debugging π
Use the Logger instead of print/println to keep track of what your application is doing (=logs).
You must give a tag to your log. You will be able to filter messages by tag in the Logcat tab.
// β improper, but faster
Log.v("SOME_TAG_NAME", "message")
There are 5 levels of logs. You can increase/decrease the level of logs inside Logcat or by editing the log settings.
-
Log.v
: verbose -
Log.d
: debug -
Log.i
: info -
Log.w
: warn -
Log.e
: error
If the level of logging is debug, then all below are included, meaning that only verbose logs won't be shown/logged.
// β
proper logging
class XXX : YYY() {
companion object {
private const val TAG = "SOME_TAG_NAME"
}
fun xxx() {
Log.v(TAG, "verbose message")
}
}
OR, with the TAG outside, and not inside a companion object
// β
proper logging
private const val TAG = "SOME_TAG_NAME"
class XXX : YYY() {
...
}
π» To-do π»
Stuff that I found, but never read/used yet.
- Android ProGuard
- Modern Android Development (MAD)
- /e/OS
- LineageOS
- Android Tests + Advanced testing
- Recommended App architecture
// Activity.title: set the title shown in task list
// and inside the default menubar
title = "Some title"
Topics
- services (independent processes)
- content providers (manage app data, enable data sharing),contentResolver,
_deviceId = Settings.Secure.getString(contentResolver, Settings.Secure.ANDROID_ID)
- context (app env info, access to resources)
- broadcast receivers (listen for events)
- AndroidManifest.xml (metadata, perms, components)
- src/resources directory
Features
- NFC
- Talkback
- leanback/touchscreen