Android Development(Kotlin)- Kotlin Language Fundamentals & Activity Life Cycle

Day2: Kotlin Language Fundamentals & Activity Life Cycle

Kotlin Fundamentals

Kotlin Docs | Kotlin

Keywords and operators | Kotlin

Installation

1
2
3
 ~/ brew install kotlin
 ~/ kotlin -version
Kotlin version 1.5.31-release-548 (JRE 17.0.2+8-LTS-86)

Create and Run an Application

Create a simple application in Kotlin that displays "Hello, World!". In your favorite editor, create a new file called hello.kt with the following lines:

1
2
3
fun main() {
println("Hello, World!")
}
1
kotlinc hello.kt -include-runtime -d hello.jar && java -jar hello.jar

Definition

  • What is compilation?
    • Compilation is the process that translates the program written in a programming language into byte codes that the system can run.
  • What is a program?
    • A program is a set of instructions we provide to a system to get a task done.

Example

  • fun declares a function.
    • unit for the functions that do not return anything. The type with only one value: the Unit object. This type corresponds to the void type in Java.
  • val declares a read-only property or local variable.
  • var declares a mutable property or local variable.
    • Variables must either have a type annotation or be initialized
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
fun main(){
var first_name = 12
var second_name = 8
cal(first_name, second_name)

var summ = getAddition(39, 32)
println("Total is $summ - example1")
println("Total is ${getAddition(1,2, 10)} - example2")

var fruits : List<String> = listOf("Banana", "Apple", "Mongo")
getFruits(fruits)
}

fun cal(first_name: Int, second_name: Int ):Unit{ //a type annotation is required on a value parameters
println("------------------------------------")
println("Calculation Started:")
println("First number is $first_name")
println("Second number is $second_name")
println("Addition of them is ${first_name+second_name}")
println("Subtraction of them is ${first_name-second_name}")
println("Calculation Ended.")
println("------------------------------------")

}

fun getAddition(num1: Int, num2:Int): Int{
return num1+num2
}

// overloaded function
fun getAddition(num1: Int, num2: Int, num3: Int):Int{
return num1+num2+num3
}

// for each
fun getFruits(fruits: List<String>){
println("Size of the fruit is ${fruits.size}.")
fruits.forEach{
i -> println("This is $i")
}
}

Android Activity Lifecycle

Fragments life cycle is similiar to activity life cycle.

onCreate()

  • When we launch the activity, it comes to onCreate() state. At that time, android system will invoke activity instances on create callback function. In the onCreate() function, we perform basic application start up logic that should happen only once for the entire life of the activity. onCreate() is the must have function.
  • onCreate() function is the only compulsory lifecycle function. The other lifecycle functions are optional. We don’t have to overwrite them unless we need to use them.
1
2
3
4
5
6
7
8
java.lang.Object
↳ android.content.Context
↳ android.content.ContextWrapper
↳ android.view.ContextThemeWrapper
↳ android.app.Activity
↳ androidx.activity.ComponentActivity
↳ androidx.fragment.app.FragmentActivity
↳ androidx.appcompat.app.AppCompatActivity

onStart()

  • After the onCreate() method finishes execution, the activity enters to the onStart() state.
  • The onStart() function of the activity class prepares the activity to enter the foreground and become interactive.
    • Foreground is where the app initializes, and the code that creates the user interface

onResume()

  • The system calls the onStart() and onResume() in a quick succesion.
  • During the onResume() state, app comes to the foreground. This is the state which the activity interacts with the user
  • Common practice:
    • reconnecting with the server to load media files
    • initialize the camera

Activity Running

When this happen, onResume() function will be called. Activity stays in the resumed state until something happens to take focus away from it.

onPause()

  • when following events happen, activity will transit to onPause() state.
    • user navigates into another activity
    • user receives the phone call
    • device screens turning off
    • screen rotation
  • If the activity returns to the onResume() state from onPause() state, the system once again calls onResume() method.
  • if our app requires something to initialize every time it resumed, we should overwrite the onResume() function and add code there
  • The system calls the onPause() function and take the activity to onPause() state as soon as the user is leaving our activity
  • When app is moving from foreground to the background, we should use the onPause() overridden function to pause the activity

onStop()

  • After the onPause() state, if the app is not moving to the resumed state, the system may transit activity to the stop state. When that happen, activity instance will be still there in the memory but user interface will be destroyed.
  • If the user navigates back to the app, the system will invoke on onReseart() and onStart() functions to create the user interface again

onDestroy()

  • this function is called when the system destroying the activity.
    • When we programmatically ignore the finish function to intentionally destroy the activity
    • When the user makes a configuration change: rotate the screen or change the language [when this happen, the system will tempororarily destroy the activity and recreate it again in working onCreate function call.]

Simulation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.i("HEX", "MainActivity: onCreate()")
setContentView(R.layout.activity_main)
}

override fun onStart() {
super.onStart()
Log.i("HEX", "MainActivity: OnStart()")
}

override fun onResume() {
super.onResume()
Log.i("HEX", "MainActivity: OnResume()")
}

override fun onPause() {
super.onPause()
Log.i("HEX", "MainActivity: onPause()")
}

override fun onStop() {
super.onStop()
Log.i("HEX", "MainActivity: onStop()")
}

override fun onDestroy() {
super.onDestroy()
Log.i("HEX", "MainActivity: onDestroy()")
}
}

Monitor how MainActivity and MainActivity2 transit to life cycle states

  1. Launch the app
    • MainActivity: onCreate(), onStart(), onResume()
  1. Navigate to MainActivity2
    • MainActivity: onPause()
    • MainActivity2: onCreate(), onStart(), onResume()
    • MainActivity: onStop()
  1. Click on the back button, navigate back to MainActivity1
    • MainActivity2: onPause()
    • MainActivity1: onCreate(), onStart(), onResume()
    • MainActivity: onStop(), onDestroy()
  1. Rorate the screen
    • MainActivity1: onPause(), onStop(), onDestroy()
    • MainActivity1: onCreate(), onStart(), onResume()

Object Oriented Kotlin

Instance = Object

1
2
3
4
5
6
7
8
9
10
class Car{
fun start(){
println("Car is starting")
}
}

fun main(){
var car = Car()
car.start()
}

Constructor

Kotlins allows us to define the primary constructor embedded with the class definition

with init block, we can add more instances or variables when we call this class.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Driver(name: String){
// field variable/property
var driverName = ""
var car = Car()

init{
driverName = name
car.start()
}

fun showDetails(){
println("Driver name is ${driverName}")
}
}

fun main(){
val driver = Driver("Hex")
driver.showDetails()
driver.driverName = "Hannah"
driver.showDetails()
}

Lateinit

When we use Lateinit, we need to always provide the object type

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Driver(name: String){
lateinit var driverName : String

init{
driverName = name
}

fun showDetails(){
println("Driver name is $driverName")
}
}

fun main(){
val driver = Driver("Hex")
driver.showDetails()
}

another way: to put field variable in the ()

1
2
3
4
5
6
7
8
9
10
class Driver(var name: String){
fun showDetails(){
println("Driver name is $name")
}
}

fun main(){
val driver = Driver("Hex")
driver.showDetails()
}
  • If we use the init block, every time we create an instance of the class, the block will be executed. That means the code inside the init block is the first to be executed when the class is instantiated
  • the function in the class will only be executed only if we invoke that function

difference between property and a parameter

  • name is a property
    • functions can directly access a property or a field variable
  • credit is a parameter
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Driver(var name: String, credit: Int){
// field variable can be accessed by functions
var totalCredit = 50
init{
totalCredit+= credit

}
fun showDetails(){
println("Driver name is $name and total credit is $totalCredit.")
}
}

fun main(){
val driver = Driver("Hex", 27)
driver.showDetails()
}

Visibility Modifiers

  • public: visible to all the classes
  • private: only visible to itself
    • 99% of time we should make propery of a class private
  • protected: only visible to itself and its inherited classes
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Driver(var name: String, credit: Int){
private var totalCredit = 50
init{
totalCredit+= credit

}
fun showDetails(){
println("Driver name is $name and total credit is $totalCredit.")
}
}

fun main(){
val driver = Driver("Hex", 27)
driver.showDetails()
}

Inheritance

In Kotlin, all classes are final by default.

To permit the derived classes to inherit from the base class, we must use the open keyword in front of the base class

Child class can:

  • inherit the parent class’ property and function
  • override parent classes functions. [need to make base function open before overriding]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
open class Car{
var maxSpeed = 30
open fun start(){
println("Car is starting")
}
}

class MyCar : Car(){
override fun start(){
println("MyCar is starting")
}
}

fun main(){
var car = Car()
car.start()

var myCar = MyCar()
myCar.maxSpeed = 240
println(myCar.maxSpeed)
myCar.start()

}

Interfaces

  • An interface can be implemented by a class in order to use its defined functionality
  • It is a way to provide a description or a contract for classes in object-oriented programming
  • Interfaces provide a predefined structure for a class so other classes can deal with our class properly
  • Interfaces in Kotlin can contain declarations of abstract methods as well as method implementations
    • Abstract methods are those don’t have method body
  • In Kotline, interfaces can also contain method declarations
  • If we want to inherit the interface for a class, we must implement its abstract methods too
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
interface SpeedController{
//abstract methods
fun accelerate()
fun decelerate()

// non-abstract method declaration
fun getBrandId():String{
return "ABC"
}
}

open class Car{
var maxSpeed = 30
open fun start(){
println("Car is starting")
}
}

class MyCar : Car(), SpeedController{
override fun start(){
println("MyCar is starting. Brand id is ${getBrandId()}")
}

// without this implementation, you will receive an error "speedController.kt:19:1: error: class 'MyCar' is not abstract and does not implement abstract member public abstract fun accelerate(): Unit defined in SpeedController"
override fun accelerate(){
println("Accelerate")
}

override fun decelerate(){
println("Decelerate")
}
}

fun main(){
var car = Car()
car.start()

var myCar = MyCar()
myCar.maxSpeed = 240
println(myCar.maxSpeed)
myCar.start()

}

Function vs Method

  • Function is a piece of code that is called by name that can pass data to operate on
  • Method is a piece of code that is called by name that is associated with an object

In the most of time, they refer to the same thing.

In general, methods are functions that belong to a class but not all functions are methods