Preface
This is a practical guide on kotlin language. This one file can be used as your pocket reference if you had already mastered the language or a life savior for the newbies who are looking for a short and simple tutorial.
I will try to update it frequently, but you can feel free to add examples in codes/
directory or commit changes in readme file
NOTE: This is exported from jupyter notebook. If you want that, mail me tbhaxor@gmail.com
Introduction
Kotlin is a cross-platform, statically typed, general-purpose programming language with type inference
Every kotlin program starts from the main function, as demonstrated below
fun main(args: Array<String>) {
// your code
}
NOTE : Since this is an interactive notebook, the main
function part will be skipped.
Basics
Printing on the console
Documentation: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.io/println.html#println
println("Hello World")
Hello World
Variables
Variables are used to store the value of specific type, the types supported by kotlin there in documentation
Documentation: https://kotlinlang.org/docs/reference/basic-types.html, https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/
var age: Int = 22
age
22
Changing value of the variable
age = 30
age
30
Kotlin support three types of variables
-
var
β mutable variables, values of such variables can be changed during the program set -
val
β immutable variables, values of such variables can be initialized only single time
val i = 10
i
10
i = 20
Val cannot be reassigned
i
10
Using underscored number literal
val oneMillion = 1_000_000
oneMillion
1000000
Floating Numbers
Documentation: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-float/
// the f means to use floating number, otherwise it will use the double and then type cast it into float
val price: Float = 44.77f;
price
44.77
Strings
Documentation: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/
var name: String = "Gurkirat Singh"
name
Gurkirat Singh
Length of string
name.length
14
Getting one character
name[0] == name.get(0)
true
Comparing two strings
val name2 = "Gurkirat Singh"
name2
Gurkirat Singh
name == name2
true
name.compareTo(name2)
0
Here 0
means both strings are identical
Concatenating two strings
name.plus(name2)
Gurkirat SinghGurkirat Singh
name + name2
Gurkirat SinghGurkirat Singh
Arrays
Collection of similar type of data
Documentation: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-array/
var numbers = arrayOf(1, 2, 3, 4, 5, 6)
numbers
[Ljava.lang.Integer;@728561a2
To get the value, use the index number
numbers[0]
1
numbers[4]
5
Getting the length of array
numbers.size
6
Empty array of specific type
val emptyArray = arrayOf<Int>()
emptyArray
[Ljava.lang.Integer;@303524fb
emptyArray.size
0
Type Conversion
val num1 = 1
val num2 = "2"
Both look identical (numbers), but the type of both the variables are not same
num1 + num2
None of the following functions can be called with the arguments supplied:
public final operator fun plus(other: Byte): Int defined in kotlin.Int
public final operator fun plus(other: Double): Double defined in kotlin.Int
public final operator fun plus(other: Float): Float defined in kotlin.Int
public final operator fun plus(other: Int): Int defined in kotlin.Int
public final operator fun plus(other: Long): Long defined in kotlin.Int
public final operator fun plus(other: Short): Int defined in kotlin.Int
num1 + num2.toInt()
3
Operators and Operands
Documentation: https://kotlinlang.org/docs/reference/keyword-reference.html#operators-and-special-symbols
Arithmatic Operators
val num1 = 20
val num2 = 30
Addition
num1 + num2
50
Subtraction
num2 - num1
10
Multiplication
num1 * num2
600
Division
num2 / num1
1
num2.toFloat() / num1.toFloat()
1.5
Finding remainder
num2 % num1
10
Relation Operators
val num1 = 20
val num2 = 30
Equality
num1 == num2
false
NOTE: Don't misunderstand ==
with =
. First one is called equal to operator and another is called assignment operator (evaluates and assigns the RHS value to LHS)
Less than
num1 < num2
true
num2 < num2
false
Greater than
num1 > num2
false
Greater than equal to
num1 >= num1
true
Less than equal to
num1 <= num1
true
Not equal to
num1 != num2
true
Unary Operators
var num1 = 10
num1
10
Post increment
num1++
num1
11
Pre increment
++num1
num1
12
Post decrement
num1--
num1
11
Pre decrement
--num1
num1
10
Bitwise Operator
var num1 = 10
var num2 = 20
num1.toString(2)
1010
num2.toString(2)
10100
Shift left by one bit
num1 = num1.shl(1)
num1.toString(2)
10100
Shift right by one bit
num1 = num1.shr(1)
num1.toString(2)
1010
Bitwise or
num1.or(num2).toString(2)
11110
Bitwise and
num1.and(num2).toString(2)
0
Bitwise xor
num1.xor(num2).toString(2)
11110
num1.and(num1).toString(2)
1010
Bitwise inverse
num1.inv().toString(2)
-1011
num1.inv()
-11
Logical Operators
AND operator
true && true
true
false && true
false
true && false
false
false && false
false
OR operator
true || true
true
true || false
true
false || true
true
false || false
false
NOT Operator
true && !false
true
Conditionals
IF - ELSE
Documentation: https://kotlinlang.org/docs/reference/control-flow.html#if-expression
var age = 18
var age2 = 14
if (age >= 18) {
println("You are an adult")
}
else {
println("Hey kiddo")
}
You are an adult
if (age2 >= 18) {
println("You are an adult")
}
else {
println("Hey kiddo")
}
Hey kiddo
WHEN
Documentation: https://kotlinlang.org/docs/reference/control-flow.html#when-expression
var num = 4
when(num) {
1 -> println("Sunday")
2 -> println("Monday")
3 -> println("Tuesday")
4 -> println("Wednesday")
5 -> println("Thursday")
6 -> println("Friday")
7 -> println("Saturday")
else -> println("Number should be in between 1 and 7") // will be executed if no value matches
}
Wednesday
To run same lines of code for multiple choices
when(variable) {
1, 2, 3 -> println("your input is either 1 or 2 or 3")
else -> {
// running multiple lines
println("This is not a joke")
println("Enter number 1, 2, 3 only")
}
}
To run same lines of code for a range of numbers
when(variable) {
in 1..3 -> println("your input is either 1 or 2 or 3")
else -> {
// running multiple lines
println("This is not a joke")
println("Enter number 1, 2, 3 only")
}
}
FOR Loop
Documentation: https://kotlinlang.org/docs/reference/control-flow.html#for-loops
var numbers = arrayOf<Int>(1, 2, 3, 4, 5, 6)
Simple demonstration
for (number in numbers){
println(number)
}
1
2
3
4
5
6
With indices
for ((idx, number) in numbers.withIndex()) {
println("number '$number' is at index '$idx' in the array")
}
number '1' is at index '0' in the array
number '2' is at index '1' in the array
number '3' is at index '2' in the array
number '4' is at index '3' in the array
number '5' is at index '4' in the array
number '6' is at index '5' in the array
Range based loop
for (i in 1..5)
{
println(i)
}
1
2
3
4
5
Range based loop with step
for (i in 1..5 step 2)
{
println(i)
}
1
3
5
Reverse loop with step
for (i in 6 downTo 0 step 2)
{
println(i)
}
6
4
2
0
WHILE and DO-WHILE Loop
Documentation: https://kotlinlang.org/docs/reference/control-flow.html#while-loops
var num = 5
While Loop
while (num > 0)
{
println(num--)
}
5
4
3
2
1
Do While Loop
do {
println(num--)
} while (num > 0)
0
Difference between while and do-while loop: https://stackoverflow.com/a/3347010/10362396
Jump statements like break
and continue
are used to end and skip the following loop body.
Documentation: https://kotlinlang.org/docs/reference/returns.html#returns-and-jumps
Functions
A function is a unit of code that performs a special task. In programming, function is used to break the code into smaller modules which makes the program more manageable.
Declaring a function
Documentation: https://kotlinlang.org/docs/reference/functions.html#function-declarations
Simple function
fun greet() {
println("Hello User")
}
greet()
Hello User
Receiving parameters
fun sum(x: Int, y: Int) {
println(x+y)
}
sum(10, 11)
21
Calling function with wrong type
sum(10.4f, 11)
The floating-point literal does not conform to the expected type Int
Return statements
fun say_hello(name: String) : String {
return "Hello, " + name
}
say_hello("John")
Hello, John
say_hello("Dale")
Hello, Dale
Recursion
A function which calls itself is called as recursive function and this process of repetition is called recursion.
fun factorial(num: Int): Int {
// base condition
if (num <= 1) {
return 1
}
// function calling itself
return num * factorial(num - 1)
}
factorial(5)
120
Default arguments
Documentation: https://kotlinlang.org/docs/reference/functions.html#default-arguments
fun say_hello_default(name: String = "Guest"): String {
return "Hello, " + name
}
say_hello_default()
Hello, Guest
say_hello_default("Sheldon")
Hello, Sheldon
Named arguments
Documentation: https://kotlinlang.org/docs/reference/functions.html#named-arguments
fun say_hello_default_name(name: String = "Guest", robot: String): String {
return "Hello, " + name + ". I am " + robot
}
say_hello_default_name(robot = "Alex")
Hello, Guest. I am Alex
say_hello_default_name("Dale", robot = "Alice")
Hello, Dale. I am Alice
Lambda Functions
The lambda functions are the functions that are not declared, but passed immediately as an expression
Documentation: https://kotlinlang.org/docs/reference/lambdas.html#lambda-expressions-and-anonymous-functions
fun multiply(x: Int, y: Int, callback: (Int) -> Unit)
{
callback(x * y)
}
var cb: (Int) -> Unit = {p -> println("The product is $p") } // lambda function
multiply(10, 20, cb)
The product is 200
Higher order functions
Function that accept functions as the parameters and can return function as a value. This is basically implemented by the lambda functions
Documentation: https://kotlinlang.org/docs/reference/lambdas.html#higher-order-functions
Accepting function
var fn:(Int, Int) -> Int = {x, y-> x + y};
fun adder(num1: Int, num2: Int, callback: (Int, Int) -> Int): Int {
return callback(num1, num2)
}
adder(10, 20, fn)
30
Inline function
Documentation: https://kotlinlang.org/docs/reference/inline-functions.html
inline fun inlineFunc(myFunc: () -> Unit): Unit {
myFunc()
}
inlineFunc({println("Printing inside inline function")})
Printing inside inline function
Exception Handling
Try Catch
Documentation: https://kotlinlang.org/docs/tutorials/kotlin-for-py/exceptions.html#throwing-and-catching
var num1 = 100
var num2 = 0
try {
num1 / num2
} catch (e: ArithmeticException) {
println("Attempeted divide by zero")
}
Attempeted divide by zero
Try-Catch as an Expression
fun toInt(v: String): Int {
return try {
Integer.parseInt(v)
} catch (e: NumberFormatException) {
0
}
}
toInt("10")
10
toInt("hello")
0
The finally blocks runs regardless of the successful or failed execution
try {
// some code
} catch (e: Exception) {
//some execption
} finally {
// this will run after try or catch block execution
}
Throwing Exception
fun divMe(x: Int, y: Int): Int {
if (y < 0){
throw IllegalArgumentException("y should be strictly greater than 0")
}
return x / y
}
try {
divMe(10, 0)
} catch (e: ArithmeticException) {
print("Aborted: ")
println(e)
} catch (e: IllegalArgumentException) {
print("Aborted: ")
println(e)
}
Aborted: java.lang.ArithmeticException: / by zero
try {
divMe(10, -20)
} catch (e: ArithmeticException) {
print("Aborted: ")
println(e)
} catch (e: IllegalArgumentException) {
print("Aborted: ")
println(e)
}
Aborted: java.lang.IllegalArgumentException: y should be strictly greater than 0
NULL Safety
Documentation: https://kotlinlang.org/docs/reference/null-safety.html#nullable-types-and-non-null-types
var myVar: Int = 7
myVar
7
myVar = 10
myVar
10
myVar = null
Null can not be a value of a non-null type Int
Use Int?
while defining the variable, so as to accept null values
var myVar: Int? = 7
myVar
7
myVar = 10
myVar
10
myVar = null
myVar
Safe Casting
Documentation: https://kotlinlang.org/docs/reference/null-safety.html#safe-casts
var num: Int? = 19
num = null
var num2: Int? = num as? Int
num2
num = 10
var num2: Int? = num as? Int
num2
10
Elvis Operator
Documentation: https://kotlinlang.org/docs/reference/null-safety.html#elvis-operator
val s1: String? = null;
val s2: String? = "Hello World";
var l1: Int = if (s1 != null) s1.length else -1
l1
-1
var l2: Int = if (s2 != null) s2.length else -1
l2
11
Simplifying the above with elvis operator
var l1: Int = s1 ?.length ?: -1
l1
-1
var l2: Int = s2 ?.length ?: -1
l2
11
Collections
Lists
Documentation:https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-list/
Immutable List: listOf
Documentation: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/list-of.html
var numbers = listOf(1, 2, "3", 4, 5)
for (number: Any in numbers) {
println(number)
}
1
2
3
4
5
List with type specification
var numbers = listOf<Int>(1, 2, 3, 4, 5)
for (number: Int in numbers) {
println(number)
}
1
2
3
4
5
Mutable List: mutableListOf
Documentation: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/mutable-list-of.html
var list = mutableListOf<Int>()
list.isEmpty()
true
list.size
0
Adding an element
list.add(10)
list.size
1
list[0]
10
Adding multiple elements
list.addAll(listOf(20, 30, 40))
list.size
4
Arrays: arrayListOf
Documentation: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/array-list-of.html
var array = arrayListOf<Int>(10, 20, 30)
for(element in array) {
println(element)
}
10
20
30
array.add(100)
for(element in array) {
println(element)
}
10
20
30
100
array[2] = -100
for(element in array) {
println(element)
}
10
20
-100
100
Inserting at specific location
array.add(1, -200)
for(element in array) {
println(element)
}
10
-200
20
-100
100
Map
Documentation: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-map/
Immutable Map: mapOf
Documentation: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/map-of.html
var map: Map<String, Int> = mapOf<String, Int>("ONE" to 1, "TWO" to 2)
map["ONE"]
1
map.keys
[ONE, TWO]
for (key in map.keys) {
println(map[key])
}
1
2
Mutable Map: mutableMapOf
Documentation: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/mutable-map-of.html
var map = mutableMapOf<Int, String>(10 to "TEN", 20 to "TWENTY")
map
{10=TEN, 20=TWENTY}
map[10]
TEN
map[30] = "THIRTY"
for(key in map.keys) {
println(map[key])
}
TEN
TWENTY
THIRTY
HashMap
It is an implementation of the interface MutableMap
Documentation: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-hash-map/
var hmap: HashMap<Int, String> = HashMap<Int, String>();
// HashMap<Int, String>(initalCapacity) use this to reserve the memory while initilization
// you can add more keys later on
hmap.put(1, "Spiderman")
hmap.put(2, "Ironman")
hmap.put(3, "Black Widow")
hmap.put(4, "Ant Man")
hmap[1]
Spiderman
hmap.get(2)
Ironman
hmap.keys
[1, 2, 3, 4]
for(key in hmap.keys) {
println(hmap[key])
}
Spiderman
Ironman
Black Widow
Ant Man
hashMapOf
Documentation: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/hash-map-of.html
var hmap = hashMapOf<Int, Int>(1 to 10, 2 to 20)
hmap.size
2
for(key in hmap.keys) {
println(hmap[key])
}
10
20
Sets
Documentation: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-set/#kotlin.collections.Set
Immutable Set: setOf
Documentation: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/set-of.html
var set1 = setOf(1, 2, 3, 4, 4, 2, 3)
set1
[1, 2, 3, 4]
for(element in set1){
println(element)
}
1
2
3
4
set1.contains(1)
true
set1.contains(10)
false
Mutable Set: mutableSetOf
Documentation: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/mutable-set-of.html
val set2 = mutableSetOf<Int>()
set2.add(1)
set2.add(1)
set2.add(2)
set2.add(2)
set2.add(3)
true
set2
[1, 2, 3]
for(element in set2) {
println(element)
}
1
2
3
set2.remove(1)
true
set2.remove(5)
false
for(element in set2) {
println(element)
}
2
3
Hashset: hashSetOf
Documentation: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/hash-set-of.html
val set3 = hashSetOf<Int>(1, 2, 3, 5)
set3
[1, 2, 3, 5]
for(el in set3) {
println(el)
}
1
2
3
5
Classes
Basic Example
Documentation: https://kotlinlang.org/docs/tutorials/kotlin-for-py/classes.html#declaration-and-instantiation
class Vehicle {
// class properties
var speed: Int = 0
var wheels: Int = 0
var model: String = ""
// class methods
fun SetModel(m: String) {
model = m
}
fun SetSpeed(s: Int) {
speed = s
}
}
var vehicle1 = Vehicle()
vehicle1
Line_166_jupyter$Vehicle@6400abd0
vehicle1.model
vehicle1.SetModel("BMW")
vehicle1.model
BMW
vehicle1.wheels
0
vehicle1.wheels = 4
vehicle1.wheels
4
Nested Classes
Documentation: https://kotlinlang.org/docs/reference/nested-classes.html#nested-and-inner-classes
class C1 {
fun ShowMe() {
println("From Outer Class C1")
}
class C2 {
fun ShowMe() {
println("From Inner Class C2")
}
}
}
var c1 = C1()
c1.ShowMe()
From Outer Class C1
var c2 = C1.C2()
c2.ShowMe()
From Inner Class C2
Constructor
Documentation: https://kotlinlang.org/docs/reference/classes.html#constructors
Primary Constructor: Default
class Car {
var wheels: Int
var model: String
init {
println("Starting the car")
wheels = 4
model = "BMW"
}
fun Stop() {
println("Stopping the car")
}
}
var car = Car()
Starting the car
car.wheels
4
car.Stop()
Stopping the car
Primary Constructor: Parameterized
class Vehicle(_wheels: Int, _model: String) {
var wheels: Int
var model: String
init {
println("starting")
wheels = _wheels
model = _model
}
fun Stop() {
println("stopping")
}
}
var v1 = Vehicle(4, "BMW")
var v2 = Vehicle(2, "Kawasaki Ninka")
starting
starting
v1.wheels
4
v2.wheels
2
v1.Stop()
v2.Stop()
stopping
stopping
NOTE: Keyword init
can be used multiple times
class InitOrderDemo(name: String) {
val firstProperty = "First property: $name"
init {
println("First initializer block that prints ${name}")
}
val secondProperty = "Second property: ${name.length}"
init {
println("Second initializer block that prints ${name.length}")
}
}
InitOrderDemo("hello")
First initializer block that prints hello
Second initializer block that prints 5
Line_186_jupyter$InitOrderDemo@7435796a
Secondary Constructor
Documentation: https://kotlinlang.org/docs/reference/classes.html#secondary-constructors
class Person {
var name: String;
var age: Int;
constructor(name: String, age: Int) {
this.name = name;
this.age = age;
}
fun whoami() {
println("I am $name and I am $age years old.")
}
}
var p1 = Person("John", 23)
var p2 = Person("Sarrah", 44)
p1.whoami()
I am John and I am 23 years old.
p2.whoami()
I am Sarrah and I am 44 years old.
Visibility Modifiers
Documentation: https://kotlinlang.org/docs/reference/visibility-modifiers.html#classes-and-interfaces
class Person {
private var name: String;
constructor(name: String) {
this.name = name
}
fun whoami(): String {
return "I am $name"
}
}
var p1 = Person("Joel")
p1.whoami()
I am Joel
p1.name
Cannot access 'name': it is private in 'Person'
Inheritance
Documentation: https://kotlinlang.org/docs/reference/classes.html#inheritance
open class Vehicle {
public var wheels: Int = 0;
public var model: String = "";
fun Start() {
println("Starting")
}
fun Stop() {
println("Stop")
}
}
class Car: Vehicle {
constructor(model: String, wheels: Int) {
this.wheels = wheels
this.model = model
}
}
var car = Car("BMW", 4)
car.Start()
Starting
car.model
BMW
car.Stop()
Stop
Method Overriding
Documentation: https://kotlinlang.org/docs/reference/classes.html#overriding-methods
open class Vehicle {
public var wheels: Int
constructor(wheels: Int) {
this.wheels = wheels
}
open fun Start() {
println("Starting the vehicle")
}
open fun Stop() {
println("Stopping the vehicle")
}
}
class Car(_wheels: Int): Vehicle(_wheels) {
init {
this.wheels = _wheels;
}
override fun Start() {
println("Starting the car")
}
override fun Stop() {
println("Stopping the car")
}
}
var car = Car(4)
car.wheels
4
car.Start()
Starting the car
car.Stop()
Stopping the car
Property Overriding
Documentation: https://kotlinlang.org/docs/reference/classes.html#overriding-properties
open class Shape {
open protected val ndims: Int = 0
fun getDims(): Int {
return this.ndims
}
}
class Rectangle : Shape() {
override protected val ndims = 4
}
var rect = Rectangle()
rect.getDims()
4
rect.ndims
Cannot access 'ndims': it is protected in 'Rectangle'
Abstract Class
Documentation: https://kotlinlang.org/docs/reference/classes.html#abstract-classes
abstract class Shape(_n: Int) {
protected var ndims: Int
init {
this.ndims = _n
}
public fun getDims(): Int {
return this.ndims
}
}
class Rect: Shape(4) {
}
var rect = Rect()
rect.getDims()
4
Accessing super class from base class
open class Person {
open fun sayHello() {
println("Hello from super class")
}
}
class Student: Person {
constructor() : super() {}
override fun sayHello() {
println("Hello from sub class")
super.sayHello()
}
}
var student = Student()
student.sayHello()
Hello from sub class
Hello from super class
Data Class
Documentation: https://kotlinlang.org/docs/reference/data-classes.html#data-classes
data class Student(var name: String, var age: Int);
var student: Student = Student("John", 22)
student
Student(name=John, age=22)
student.name
John
student.age
22
Sealed Class
Documentation: https://kotlinlang.org/docs/reference/whatsnew11.html#sealed-and-data-classes
sealed class Shape {
data class Circle (var radius: Int)
data class Rectangle (var width: Int, var height: Int)
data class Square (var side: Int)
}
var c = Shape.Circle(20)
c
Circle(radius=20)
var r = Shape.Rectangle(20, 10)
r
Rectangle(width=20, height=10)
var s = Shape.Square(20)
s
Square(side=20)
Extension Function
Documentation: https://kotlinlang.org/docs/reference/extensions.html#extension-functions
class Person {}
fun Person.sayHello(): String {
return "Hello"
}
var p = Person()
p.sayHello()
Hello
Generic Functions
Documentation: https://kotlinlang.org/docs/reference/functions.html#generic-functions
fun <T> Return(x: T): T {
return x
}
Return<Int>(5)
5
Return<String>("Hello")
Hello
Misc
Regex
Documentation: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/-regex/
var str = "Hello world at 10:22!!"
var pattern = Regex("[0-9]{2}:[0-9]{2}")
pattern
[0-9]{2}:[0-9]{2}
pattern.containsMatchIn(str)
true
pattern.findAll(str)
kotlin.sequences.GeneratorSequence@53db2a04
Call Java from Kotlin
Documentation: https://kotlinlang.org/docs/reference/java-interop.html
System.out.println("Hello")
Hello
Like Java, it also supports imports
Call Kotlin from Java
Documentation: https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html
filename: main.kt
fun main() {
}
fun Print() {
println("Calling from kotlin file")
}
filename: app.java
public class app
{
public static void main() {
MainKt.Print()
}
}
I hope you have learnt something new today. Follow the links to reach me
- Email: tbhaxor@gmail.com
- Twitter: @tbhaxor
- Facebook: @tbhaxor
- GitHub: @tbhaxor
- LinkedIn: @gurkirat--singh
- Instagram: @_tbhaxor_
Top comments (8)
Thanks for sharing this great article! Very easy to understand. Here I have drafted one more reference, It should be helpful for further process. blog.mirrorfly.com/build-android-c...
Wow ! Really detailed article. Did not expect it to be so thorough, when I clicked it. Need the erstwhile Unicorn button for this.
Hi @citronbrick, I am glad you liked it :D
Hey dale
best guide I have seen to date. Would love if you keep it updated.
Awesome
Please check out this app: dapks.com/afk-arena-mod-apk/
This is made in Kotlin. Can you please tell me how this app would be made in Kotlin.
Would really appreciate the help!
Dale hey