Android: Unveiling Android Runtime: A Comprehensive Overview for Developers and Enthusiasts

Hello Readers, CoolMonkTechie heartily welcomes you in this article (Unveiling Android Runtime: A Comprehensive Overview for Developers and Enthusiasts).

In this article, We will learn about Runtime in android. The Android operating system uses the Android Runtime (ART) as its managed runtime environment to run applications. It replaced the Dalvik runtime in Android 5.0 (Lollipop) as the default runtime. ART is responsible for executing and managing Android applications on the device.

A famous quote about learning is :

“In learning you will teach, and in teaching you will learn.”

So Let’s begin.

What is Android Runtime?

Android Runtime (ART) is the managed runtime environment used by the Android operating system to run applications. It replaced the Dalvik runtime in Android 5.0 (Lollipop) as the default runtime. ART is responsible for executing and managing Android applications on the device.”

ART utilizes an Ahead-of-Time compilation approach, where the app’s bytecode is translated into native machine code during the app installation process. In contrast, the Dalvik runtime employed Just-in-Time (JIT) compilation, interpreting the bytecode at runtime.

When we write our code in Java/Kotlin and build the APK, it gets converted to bytecode. Subsequently, our APK contains .dex files that house this bytecode. However, our Android device cannot run bytecode format directly. Therefore, the translation of the app bytecode into native machine code becomes necessary. This translation process is facilitated by Android Runtime (ART).

Android Runtime Types and Their Evolutions

Android has undergone several changes in its runtime environments over the years. The primary runtimes in Android include Dalvik and Android Runtime (ART). Let’s explore their evolution:

Dalvik Runtime:

Dalvik was the original runtime environment which uses in Android before version 5.0 (Lollipop). It uses Just-in-Time (JIT) Compilation, which translated the application’s bytecode into native machine code at runtime. This allowed for flexibility but sometimes led to increased startup times.

Disadvantage: Increased startup times, Low performance and decreases battery performance.

Android Runtime (ART):

ART replaced Dalvik as the default runtime in Android 5.0 (Lollipop). It uses default runtime (Android 5.0 – Present).

Ahead-of-Time (AOT) Compilation: One significant change in ART is the shift from JIT to Ahead-of-Time (AOT) compilation. The app’s bytecode converts into native machine code during the app installation process, reducing runtime overhead and improving overall performance.

Improved Performance: AOT compilation contributes to faster app startup times and more efficient execution.

Compact Dalvik:

Compact Dalvik introduced in Android 4.4 (KitKat) as an intermediate step before transitioning to ART.

Performance Improvements: While still using JIT compilation, Compact Dalvik included optimizations to improve app performance compared to earlier versions.

Project Mainline (Android 10 and Later):

Starting with Android 10, Project Mainline introduced a modular approach to system updates, enabling the Google Play Store to update core parts of the Android runtime independently of full system updates

Security and Update Flexibility: Mainline improves the security and flexibility of Android updates. It enables more frequent updates for critical runtime components.

ART Compiler (Android 7.0 – Nougat):

Android 7.0 (Nougat) introduced significant changes to the ART compiler, including the introduction of the Just-In-Time (JIT) compiler alongside the existing Ahead-of-Time (AOT) compiler.

Mixed Compilation: The mixed compilation approach employed both Ahead-of-Time (AOT) and Just-In-Time (JIT) compilation to enhance performance. The system compiled frequently executed code ahead of time, and it compiled less frequently used code at runtime for adaptability.

Project Treble (Android 8.0 – Oreo):

While not directly a runtime, Project Treble, introduced in Android Oreo, rearchitected the Android OS to separate the vendor implementation from the Android framework. This separation aimed to streamline the update process for Android devices.

Android Runtime (ART) Optimizations:

Ongoing: With each new Android version, ART continues to receive optimizations and improvements to enhance the performance and resource efficiency of Android applications.

ART in Android 12:

Ongoing Evolution: Android 12 and subsequent versions continue to refine ART with optimizations, security enhancements, and improvements in resource management.

Dalvik vs ART

DalvikART
JIT (Just In Time) based CompilationAOT (Ahead-of-Time) based Compilation
Low performanceHigh performance
More startup timeLess startup time
Less install timeMore install time
Less space on the diskMore space on the disk
Less boot timeMore boot time
Decreases battery performanceIncreases battery performance
Does not have a better Garbage collection as compared to ARTBetter Garbage collection than Dalvik
Comparision between Dalvik and ART

That’s all about in this article.

Conclusion

In this article, we learned about Android Runtime (ART). Understanding the evolution of Android runtimes is crucial for developers to adapt their applications to leverage new features, performance improvements, and security enhancements introduced in each version.Developers should also consider the compatibility of their apps with different runtime environments across various Android versions. We also discussed the different comparison between Dalvik and ART in Android.

Thanks for reading ! I hope you enjoyed and learned about Activity Lifecycle Concept in Android. Reading is one thing, but the only way to master it is to do it yourself.

Please follow and subscribe us on this blog and and support us in any way possible. Also like and share the article with others for spread valuable knowledge.

You can find Other articles of CoolMonkTechie as below link :

You can also follow official website and tutorials of Android as below links :

If you have any comments, questions, or think I missed something, feel free to leave them below in the comment box.

Thanks again Reading. HAPPY READING !!😊😊😊

iOS – Are 20 Quick Valuable Concepts Best way to Learn Swift?

Hello Readers, CoolMonkTechie heartily welcomes you in this article (Are 20 Quick Valuable Concepts Best way to Learn Swift? ).

In this article, We will discuss 20 quick valuable concepts which is the best way to learn swift and helps to build iOS applications. We’ll need Swift Foundation Concepts as we start building apps. It means that we introduce each topic in a way. This provides enough background to understand the foundation concepts.

A famous quote about learning is :

The beautiful thing about learning is that nobody can take it away from you.

So Let’s begin.


1. Hello World

It is common to start any tutorial for a new language with the Hello World example so we’ll start out by showing how easy this is to do in Swift:

print("Hello World!")      // Prints "Hello World!" to the output window in Xcode

To make this a little more personal, let’s look at one of the handy features of Swift (called string interpolation) where we can insert values into strings using the \(...) syntax. Below, we’ve inserted name into the middle of our string:

let name: String = "World"
print("Hello \(name)!")     // Prints "Hello World!"


2. When to use let vs var

We’ll notice in the example above we’ve used let to create the new variable for the name “Bob”. In Swift, we’ll choose from the following 2 options when creating a new variable:

  • let => Use let when we are defining a constant (a value that will not change)
let numberOfContinents: Int = 7   // Seven continents will not change so we've used "let"
  • var => Use var when we are defining a variable (a value that might change)
var continentsVisited: Int = 2   // Continents visited increases over time so we've used "var"

In general, it is considered a best practice to use constants (let) whenever possible.


3. Numbers

The two most common types of numbers we’ll use in Swift are integers (Int) and doubles (Double):

Integers are whole numbers with no fractional component:

let minValue: Int = -42
let maxValue: Int = 55 

Doubles can have a fractional component:

let pi: Double = 3.14159
let billAmount: Double = 10.25


4. Strings

Strings represent a series of characters:

let hello: String = "Hello"
let world: String = "World"

We can use string interpolation to construct new strings:

let helloWorld: String = "\(hello) \(world)"    // "Hello World"

Or we can use the + operator to combine strings:

let helloWorld: String = hello + " " + world    // "Hello World"


5. Booleans

Boolean is a very simple type in Swift as it can only ever be true or false:

let swiftIsCool: Bool = true
let iMissObjectiveC: Bool = false 


6. Arrays

Arrays store a list of values that must be of the same type. Below we’ve kept track of the previous bill amounts (which is a list of doubles):

// Notice how we've used "var" here since we want to append new items to the array
var previousBillAmounts: [Double] = [10.25, 21.32, 15.54]

To add a new bill to the array:

previousBillAmounts.append(52.45)    // Result: [10.25, 21.32, 15.54, 52.45]

To check on how many bills there are in the array:

let count = previousBillAmounts.count            // Result: 4

Or to check the first bill amount in the array:

let firstBillAmount = previousBillAmounts[0]    // Result: 10.25


7. Dictionaries

Much like we might use a real-world dictionary to look up the definition for a word, you can use the dictionary data structure in Swift to create associations between keys (the word in the real-world dictionary) and values (the definition in the real-world dictionary).

For example, let’s say we want to keep track of the ages of people that are using our app. This will best done using the following dictionary:

var people: [String: Int] = [
                              "Bob": 32,
                              "Cindy": 25
                            ]

Here, the key is the name of the person and the value is the person’s age.

Later on if we want to find out Bob’s age, we can look it up by doing:

let bobsAge = people["Bob"]

If we get a new user we can easily add them to our dictionary using the following syntax:

people["Dan"] = 56


8. Specifying Types

In most of the examples in this article, we are explicit with the types of our constants and variables. Explicit typing looks something like:

let name: String = "Bob"   // Explicitly designating "name" to be of type "String"

However, Swift is smart enough to infer the type for us in a lot of cases. The short example of previous example is:

let name = "Bob"   // Swift infers "name" is of type "String" since "Bob" is a String

In cases where Swift can infer the type, it’s not necessary to be explicit with the types for our constants and variables. We just do it in this guide so that the examples are easier to follow.


9. Any and AnyObject

Swift has two special “catch all types” that come in handy when a more specific type cannot determine.

  • AnyObject can represent an instance of any class type.
  • Any can represent an instance of any type at all.

In general, it’s a best practice to be as specific with our types as possible and avoid the use of AnyObject and Any, but they become particularly helpful when interacting with Objective-C code that is less strict on typing.


10. Optionals

Optionals is a very important concept in Swift and it means to improve the safety of Swift code. By simply placing a question mark (?) after any type, it declares that variable to be optional. An optional type allows that variable to exist in one of the following two states:

  1. There is a value and it equals x
  2. There isn’t a value at all

Let’s look at an example to make this more clear. Consider the following 2 examples where we are trying to convert a String to an Int:

// Example 1 (Conversion succeeds)
let input: String = "123"
let optionalConvertedInput: Int? = Int(input)  // optionalConvertedInput = 123

// Example 2 (Conversion fails - input is not a number)
let input: String = "123abc"
let optionalConvertedInput: Int? = Int(input)  // optionalConvertedInput = nil

Swift requires optionalConvertedInput to be of type Int? (or “optional Int”) so that it is explicit that convertedInput might not contain a value (in the case when the conversion fails). If we were to declare convertedInput as simply Int, we’d get a compile error.

There’s a handy syntax in Swift that we’ll use quite often when working with optionals. If we wanted to use the value of optionalConvertedInput later on in our code, we’d have to first check to make sure it’s not nil. We can do so using the following code:

if let convertedInput = optionalConvertedInput {
   // Code that gets executed when optionalConvertedInput is NOT nil
} else {
   // OptionalConvertedInput IS nil, do something else
}

In other languages like Java, NullPointerException is a common source of crashes. This exception fires when a null reference accesses. Swift’s Optionals go a long way to reduce this type of programming error.


Optionals in string interpolation

When using optionals in string interpolation, the value with either be Optional(...) or nil without being explicitly unwrapped. When the inner value needs, the optional must unwrap.

let maybeString: String? = "value"

print("\(maybeString)")  // prints -> Optional("value")
print("\(maybeString!)")  // prints -> "value"


11. Functions

Functions in Swift are very similar to other languages. The simplest function in Swift can write as:

// This prints "Hello!" to the output window
func printHello() {
    print("Hello!")
}

// Calls this function
printHello()

We can extend this function to be a little more personable by taking in a name and returning the greeting instead of printing it out:

// Takes in a "personName" parameter of type String and returns the greeting as a String
func sayHello(personName: String) -> String {
    // Implicitly returns when there is a single statement
    "Hello \(personName)!"
}

// Calls this function
let greeting: String = sayHello("Bob")

Things get a little more interesting when we start to have multiple parameters as Swift has the concept of external and local parameter names. An external parameter name is used to label arguments passed to a function call. A local parameter name is a name used in the implementation of the function.

// "to" + "and" are the external parameter names
// "person" + "anotherPerson" are the local parameter names
func sayHello(to person: String, and anotherPerson: String) -> String {
    "Hello \(person) and \(anotherPerson)!"
}

// Calls this function using the "external" parameter names
let greeting: String = sayHello(to: "Bill", and: "Ted")


12. Control Flow


Conditional Statements

If statements are very similar to other languages and can express as:

let temperatureInFahrenheit: Int = 90

if temperatureInFahrenheit <= 32 {
    print("It's very cold. Consider wearing a scarf.")
} else if temperatureInFahrenheit >= 86 {
    print("It's really warm. Don't forget to wear sunscreen.")
} else {
    print("It's not that cold. Wear a t-shirt.")
}


Loops

The two most common types of loops we’ll need in Swift are for loops and for-in loops.

For loops work well when we want to do something until a particular condition is met (in the case below until index >= 3):

// Simple for loop that prints "Hello" 3 times
for var index = 0; index < 3; index++ {
    print("Hello")
}

C-style for loops deprecated and will remove in future versions of Swift. For-in loops are preferred instead. The above example could be re-written as:

for _ in 0..<3 {
          print("Hello")
      }

For-in loops come in really handy when we want to do something to each item in a collection (such as an array):

let names = ["Anna", "Alex", "Brian", "Jack"]

// Loops over each name in "names" and prints out a greeting for each person
for name in names {
    print("Hello, \(name)!")
}

Sometimes, we want to loop over each item in an array and also keep track of the index of the item. Array’s enumerated() method can help you achieve this:

let names = ["Anna", "Alex", "Brian", "Jack"]

for (index, value) in names.enumerated() {
    print("Item \(index + 1): \(value)")
}


13. Classes

Classes are the building blocks of our app’s code. We define properties and methods to add functionality to our classes by using the same syntax as for variables and functions.

Below we can find a Person class that is meant to show an example of the types of things we’ll want to do when building our classes.

class Person {
	
    // Custom initializer - takes in firstName and lastName
    init(firstName: String, lastName: String) {
        self.firstName = firstName
        self.lastName = lastName

        // Increment type property each time a new person is created
        Person.numberOfPeople++
    }
	
    // *** Properties ***
	
    // Stored Property - Stored as part of the current instance of the class
    var firstName: String
    var lastName: String

    // Computed Property - computes "fullName" from "firstName" and "lastName"
    var fullName: String {
    	get {
            "\(firstName) \(lastName)"
    	}
    }

    // Type Property - Single instance for all instances of the class,
    // similar to a static property in Java
    static var numberOfPeople = 0   
    
    // *** Methods ***
    
    // Instance Method
    func greet() {
    	// Notice the use of "self" - self refers to the current instance and 
        // is similar to "this" in Java
    	print ("Hello \(self.firstName)")
    }
    
    // Type Method
    class func printNumberOfPeople() {
    	print("Number of people = \(Person.numberOfPeople)")
    }
}

// ... Using the Person Class ...

// Create a new instance of the Person class
let bob = Person(firstName: "Bob", lastName: "Smith")

// Call instance method
bob.greet()   // Prints "Hello Bob"

// Accessing properies
print("Bob's first name is: \(bob.firstName)")  // Prints "Bob's first name is: Bob"
print("Bob's full name is: \(bob.fullName)")    // Prints "Bob's full name is: Bob Smith"

// Call type method
// Prints "Number of people = 1" (since we've only created one Person)
Person.printNumberOfPeople()


14. Protocols

Protocols are similar to interfaces in other languages. Think about a protocol as a contract. The contract includes a set of methods that must be implemented. Any classes that choose to implement a protocol sign this contract and implement all the methods that are in the protocol.

Let’s say we have the following protocol (MyFriendlyGreeterProtocol) that defines 2 methods sayHello() and sayBye():

protocol MyFriendlyGreeterProtocol {
    func sayHello()
    func sayBye()
}

Any classes that implement this protocol (you implement a protocol by adding its name after the class defintion as shown below), must implement both of these methods:

class MyEnglishPerson: MyFriendlyGreeterProtocol {
    func sayHello() {
        print("Hello!")
    }

    func sayBye() {
        print("Bye!")
    }
	
    // ... other methods for this class ...

}

class MySpanishPerson: MyFriendlyGreeterProtocol {
    func sayHello() {
        print("Hola!")
    }

    func sayBye() {
        print("Adios!")
    }
	
    // ... other methods for this class ...
}

There is a lot more you can do with protocols as they form one of the key design patterns in iOS. The code above merely shows how to get started with the syntax for protocols.


15. Swift Closures

Closures are self-contained blocks of code that can be passed around and used in our code. These are similar to blocks in Objective-C and lambdas in other programming languages.

Swift Closures can capture and store references to any constants and variables from the context in which they are defined. This is known as “closing” over those constants and variables. Swift handles all of the memory management of capturing for you.

Closure Example:

Example: A function called makeIncrementer which contains a nested function

Here’s an example of a function called makeIncrementer, which contains a nested function called incrementer. The nested incrementer() function captures two values, runningTotal and amount, from its surrounding context. After capturing these values, incrementer is returned by makeIncrementer as a closure that increments runningTotal by amount each time it is called.

func makeIncrementer(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementer() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return incrementer
}

The return type of makeIncrementer is () -> Int. This means that it returns a function, rather than a simple value. The function it returns has no parameters, and returns an Int value each time it is called.

The makeIncrementer(forIncrement:) function defines an integer variable called runningTotal, to store the current running total of the incrementer that will be returned. This variable is initialized with a value of 0.

The makeIncrementer(forIncrement:) function has a single Int parameter with an external name of forIncrement, and a local name of amount. The argument value passed to this parameter specifies how much runningTotal should be incremented by each time the returned incrementer function is called.

makeIncrementer defines a nested function called incrementer, which performs the actual incrementing. This function simply adds amount to runningTotal, and returns the result.

When considered in isolation, the nested incrementer() function might seem unusual:

func incrementer() -> Int {
    runningTotal += amount
    return runningTotal
}

The incrementer() function doesn’t have any parameters, and yet it refers to runningTotal and amount from within its function body. It does this by capturing a reference to runningTotal and amount from the surrounding function and using them within its own function body. Capturing by reference ensures that runningTotal and amount do not disappear when the call to makeIncrementer ends, and also ensures that runningTotal is available the next time the incrementer function is called.

Example: a function called makeIncrementer in action

Here’s an example of makeIncrementer in action:

// This example sets a constant called incrementByTen to refer to an //incrementer function that
// adds 10 to its runningTotal variable each time it is called.

let incrementByTen = makeIncrementer(forIncrement: 10)

incrementByTen()  // returns a value of 10
incrementByTen()  // returns a value of 20
incrementByTen()  // returns a value of 30


16. Type Casting (as, as?, as!)

Type casting changes the type of a particular instance to another compatible type. There are 3 ways to accomplish this with Swift:

  1. Guaranteed conversion with as : This is the safest cast. It will never fail since the compiler can guarantee the cast will work. Use this when you are upcasting from a child class to its parent or doing something like 1 as Float.
// Guaranteed conversion as the compiler can verify this will succeed
let myFloat = 1 as Float

// Guaranteed conversion as upcasting from a type to its parent type is safe 
// UIView is a parent of UITableView
let myView = myTableView as UIView

2. Conditional conversion with as? : This is a cautious cast. If the cast fails, it will return nil. This is needed when downcasting from a parent type to a child type.

// If myView is actually a tableView, the downcast will succeed, otherwise it will fail safely
if let myTableView = myView as? UITableView {
    print("The downcast succeeded!")
} else {
    print("The downcast failed!")   	   
}

3. Forced conversion with as! : This is a dangerous cast that you should avoid using. If the cast fails, this will crash our app. Use this cast carefully.

// DANGEROUS: If myView is actually a tableView, the downcast will succeed
// Otherwise it will crash the app
let myTableView = myView as! UITableView


17. Understanding the Exclamation Mark (!)

There are various places you might come across an exclamation mark in Swift code. The following examples are meant to capture the major types of use cases for the exclamation mark operator that can cause confusion when first learning Swift.

When getting the actual value out of an optional (called unwrapping an optional):

let possibleString: String? = "An optional string."

// DANGEROUS: possibleString must NOT be nil or this will crash
let forcedString: String = possibleString! 

// SAFE: Will only enter the if clause if possibleString is NOT nil
if let actualString = possibleString {
    // do something with actualString
}

// SAFE: Generally preferred alternate syntax to "if let" that can exit early
guard let actualString = possibleString else {
    // exit early or throw exception
}
// do something with actualString

When type casting (called forced conversion):

// DANGEROUS: If myView is actually a tableView, the downcast will succeed
// Otherwise it will crash the app
let myTableView = myView as! UITableView

When defining variables that are initially nil but get set soon afterwards and are guaranteed not to be nil after that (called implicitly unwrapped optionals):

let assumedString: String! = "An implicitly unwrapped optional string."

// no need for an exclamation mark since assumedString is an implicitly unwrapped optional
let implicitString: String = assumedString


18. Property Observers

A very useful inclusion of the Swift language is Property Observers. While the language might sound complex, it’s actually a literal explanation of what it does. It allows you to observe properties and respond to impending or finished property changes. It’s part of Apple’s goal to make Swift a cleaner language because a developer merely has to keep any logic related to updating properties in one convenient place.

Let’s look at an example.

Assume we have a Fitness tracking application and whenever a user enters their weight, we calculate and display their BMI to them.

Without property observers, and keeping in good practice (since BMI is calculated and not set in initialization), we might have a class like this –

Swift

class Profile {
    let height: Double
    var weight: Double
    private var BMI: Double
    
    init(weight: Double, height: Double) {
        self.height = height
        self.weight = weight
        self.BMI = weight / (height*height)
    }
    
    func getBMI() -> Double {
        self.BMI
    }
    
    func updateBMI() {
        self.BMI = weight / (height*height)
    }
}  

In a view where we ask the user to enter their new weight, we would call profile.updateBMI() after the new weight is set. Isn’t this a little tedious? It’s almost a trap for developers. We have to actively remember that we should update our BMI every time we update our weight.

Thankfully, with property observers, we don’t have to actively watch every property change as a developer. Our class becomes –

class Profile {
    let height: Double
    var weight: Double {
        didSet {
            updateBMI()
        }
    }
    private var BMI: Double
    
    init(weight: Double, height: Double) {
        self.height = height
        self.weight = weight
        self.BMI = weight / (height*height)
    }
    
    func getBMI() -> Double {
        self.BMI
    }
    
    func updateBMI() {
        self.BMI = weight / (height*height)
    }
}  

It might not look like much, but now whenever we update BMI, we don’t have to worry about calling updateBMI() and to be honest, we can clean this up even more by making BMI private(set), changing Profile to a struct and adding a mutating func.

struct Profile {
    let height: Double
    var weight: Double {
        didSet {
            updateBMI()
        }
    }
    private(set) var BMI: Double
    
    mutating private func updateBMI() {
        BMI = weight / (height * height)
    }
}  

What is mutating we ask? Well, normally Struct’s are read only. This is because in order for them to be fast, they need to take up space on Stack instead of Heap. A simple way to explain this is to imagine that Stack is writing with a Pen and Heap is writing with a Pencil. Some of you might think “well what’s the big deal? they both write.” But think about all the extra work that comes with a Pencil – We need an eraser, we have to clean the eraser off the paper and can end up using more material if we edit a lot. A pen, on the other hand, we just write (we’re assuming you’re not using an erasable pen or white-out) and it’s set.

Mutating gives us the ability to say, “Hey, this Struct will be read-only, but if I make it a variable, I might want to update its properties, so please give me the ability to edit that Struct”.

There’s a little more to this under the hood, but Structs tend to be pretty thread-safe, so we can assume every Struct exists by itself and it’s pretty safe to edit like this.


Other Property Observers

There are other property observers for every stage of a state change – willSet, set/get are included. willSet has the added ability of being able to compare newValue to the original value (called the property name).

A few hints about where didSet can be quite powerful is when dealing with network data and data sources. When a user has the ability to get objects from a server with a regular network call, a search and tapping a keyword, it can be useful if the var dataSource: [Models] has didSet to reload the data of the view. That way we won’t have to do it manually.


19. Working with JSON

A lot of the time when working with REST API’s (like Instagram, Twitter, etc), the data that comes back will be JSON. JSON is a human readable data format (very similar to XML).

Below is an example of JSON that simulates the type of JSON. We might get back when using an endpoint that returns movies and their ratings:

  • An open curly brace means the start of a dictionary
  • An open bracket means the start of an array
{
    "status": "OK",
    "movies": [
        {
            "title": "Whiplash",
            "rating": 8.5
        }, 
        {
            "title": "Feast",
            "rating": 5.2
        }, 
        {
            "title": "Kung Fury",
            "rating": 7.1
        }
    ]
}


Below is an example of how we extract the movies and ratings from that response:

// data returned from the network response will typically be of type
// NSData (which is a buffer of bytes)
let responseData: NSData = // ... some value retrieved from the network response ...

// Wrap our code in a do catch as our code might throw an exception which we need to handle
do {
    // Start by converting the NSData to a dictionary - a dictionary for the entire response
    if let responseDictionary = try NSJSONSerialization.JSONObjectWithData(responseData,
        options:NSJSONReadingOptions(rawValue:0)) as? [String:AnyObject] {

            // Dip inside the response to find the "movies" key and get the array of movies
            if let movies = responseDictionary["movies"] as? [AnyObject] {

                // Get each movie dictionary from the array of movies
                for movie in movies {
                
                    // Use the movie "title" key and "rating" key to get their values
                    if let title = movie["title"] as? String {
                        if let rating = movie["rating"] as? Double {
                            print("Title:\(title), rating:\(rating)")
                        }
                    }
                }
            }
    }
} catch {
    print("Error parsing JSON")
}


20. Playgrounds

Xcode includes a very useful tool for learning Swift called “Playgrounds”. It’s very easy to create a new playground through Xcode.

Once inside a playground, we can write Swift code and see it run immediately (without needing to build and run a project each time). This allows you to try out different syntaxes and test out our code before including it in our app.

We highly recommend checking out Playgrounds while we are learning Swift.

That’s all about in this article.

Related Other Articles / Posts


Conclusion

In this article, We discussed 20 quick valuable concepts which are the best way to learn swift and help to build iOS applications.

Thanks for reading! I hope you enjoyed and learned about the 20 quick valuable Swift Foundation Concepts. Reading is one thing, but the only way to master it is to do it yourself.

Please follow and subscribe us on this blog and and support us in any way possible. Also like and share the article with others for spread valuable knowledge.

You can find Other articles of CoolmonkTechie as below link :

You can also follow other website and tutorials of iOS as below links :

If you have any comments, questions, or think I missed something, feel free to leave them below in the comment box.

Thanks again Reading. HAPPY READING !!???

Android – Understanding Android Activity Lifecycle

Hello Readers, CoolMonkTechie heartily welcomes you in this article (Understanding Android Activity Lifecycle).

In this article, We will learn about Activity Lifecycle in android. Activity in Android is one of the most important components of Android. It is the Activity where we put the UI of our application. So, if we are new to Android development then we should learn what an Activity is in Android and what is the lifecycle of an Activity.

A famous quote about learning is :

“Change is the end result of all true learning.”


So Let’s begin.


What is an Activity in Android?

The Activity class is a crucial component of an Android app, and the way activities are launched and put together is a fundamental part of the platform’s application model.

Whenever we open an Android application, then we see some UI drawn over our screen. That screen is called an Activity. It is the basic component of Android and whenever we are opening an application, then we are opening some activity.

For example, when we open our Gmail application, then we see our emails on the screen. Those emails are present in an Activity. If we open some particular email, then that email will be opened in some other Activity.

When we all started with coding, we know about the main method from where the program begins execution. Similarly, in Android, Activity is the one from where the Android Application starts its process. Activity is one screen of the app’s user interface. There is a series of methods that run in an activity.

There is a lifecycle associated with every Activity and to make an error-free Android application, we have to understand the lifecycle of Activity and write the code accordingly.


What is the Android Activity Lifecycle ?

As a user navigates through, out of, and back to our app, the Activity instances in your app transition through different states in their lifecycle. The Activity class provides a number of callbacks that allow the activity to know that a state has changed: that the system is creating, stopping, or resuming an activity, or destroying the process in which the activity resides.

Within the lifecycle callback methods, we can declare how our activity behaves when the user leaves and re-enters the activity.

For example, if we’re building a streaming video player, we might pause the video and terminate the network connection when the user switches to another app. When the user returns, we can reconnect to the network and allow the user to resume the video from the same spot. In other words, each callback allows us to perform specific work that’s appropriate to a given change of state. Doing the right work at the right time and handling transitions properly make our app more robust and performant. For example, good implementation of the lifecycle callbacks can help ensure that our app avoids:

  • Crashing if the user receives a phone call or switches to another app while using our app.
  • Consuming valuable system resources when the user is not actively using it.
  • Losing the user’s progress if they leave our app and return to it at a later time.
  • Crashing or losing the user’s progress when the screen rotates between landscape and portrait orientation.

The Core Set Of Android Activity Lifecycle Callbacks

An Android activity undergoes through a number of states during its whole life cycle. To navigate transitions between stages of the activity lifecycle, the Activity class provides a core set of six callbacks: onCreate()onStart()onResume()onPause()onStop(), and onDestroy(). The system invokes each of these callbacks as an activity enters a new state.

Source: Android Developer – Android Activity Lifecycle

 The Activity lifecycle consists of 7 methods:

  1. onCreate() : This method calls When a user first opens an activity. We must implement this callback, which fires when the system first creates the activity. On activity creation, the activity enters the Created state. In the onCreate() method, we perform basic application startup logic that should happen only once for the entire life of the activity.
  2. onStart(): When the activity enters the Started state, the system invokes this callback. The onStart() call makes the activity visible to the user, as the app prepares for the activity to enter the foreground and become interactive..
  3. onResume(): When the activity enters the Resumed state, it comes to the foreground, and then the system invokes the onResume() callback. This is the state in which the app interacts with the user. 
  4. onPause():  The system calls this method as the first indication that the user is leaving your activity. it indicates that the activity is no longer in the foreground. Use the onPause() method to pause or adjust operations that should not continue while the Activity is in the Paused state, and that we expect to resume shortly.
  5. onStop(): When our activity is no longer visible to the user, it has entered the Stopped state, and the system invokes the onStop() callback. 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.
  6. onRestart(): It calls when the activity in the stopped state is about to start again.
  7. onDestroy(): It  calls when the activity clears from the application stack.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).

So, these are the 7 methods that associates with the lifecycle of an activity.


Use-cases of Activity Lifecycle

Now, let’s see real-life use-cases to understand the lifecycle for an activity.


Use Case 01

When we open the activity for the first time, the sequence of state change it goes through is,

onCreate -> onStart -> onResume

After this point, The user uses the activity when it is ready.


Use Case 02

Now, let’s say we are minimizing the app by pressing the home button of the phone. The state changes it will go through is,

onPause -> onStop


Use Case 03

When we are moving to and from between activities, let’s say Activity A and Activity B. So, we will break it down into steps.

First, it opens Activity A, where the following states call initially,

onCreate -> onStart -> onResume

Then let’s say on a click of a button we opened Activity B. While opening Activity B, first, onPause will be called for Activity A and then,

onCreate -> onStart -> onResume

will call for Activity B. Then to finish this off, onStop of Activity A will be called and finally, Activity B would be loaded.

Now, when we press the back button from Activity B to Activity A, then first,onPause of Activity B is called and then,

onRestart -> onStart -> onResume

calls for Activity A and it displays to the user. Here we can see onRestart gets called rather then onCreate as it is restarting the activity and not creating it.

Then after onResume of Activity A is called then,

onStop -> onDestroy 

calls for Activity B and hence the activity destroys as the user has moved to Activity A.


Use Case 04

Pressing the lock button while activity is on then,

onPause -> onStop 

calls and when we reopen the app again,

onRestart -> onStart -> onResume

calls.


Use Case 05

When we kill the app from the recent app’s tray,

onPause -> onStop -> onDestroy 

it gets called. Here you can see we are getting the onDestroy state getting called as we are killing the instance of the activity.

When we now reopen the activity, it will call onCreate and not onRestart to start the activity.


Use Case 06

Consider a use-case where we need to ask permission from the user. Majority of the times we do it in onCreate.

Now, an edge case here is let’s say we navigate to a phone’s Settings app and deny the permission there, and then I came back to the initial app’s activity. Here, onCreate would not be called.

So, our permission check could not be satisfied here. To overcome this, onStart is the best place to put your permission check as it will handle the edge cases.

That’s all about in this article.


Conclusion

In this article, we learned about what an Activity is in Android and what is the lifecycle of an Activity . We also discussed the different Use-cases of Activity LifeCycle in Android.

Thanks for reading ! I hope you enjoyed and learned about Activity Lifecycle Concept in Android. Reading is one thing, but the only way to master it is to do it yourself.

Please follow and subscribe us on this blog and and support us in any way possible. Also like and share the article with others for spread valuable knowledge.

You can find Other articles of CoolMonkTechie as below link :

You can also follow official website and tutorials of Android as below links :

If you have any comments, questions, or think I missed something, feel free to leave them below in the comment box.

Thanks again Reading. HAPPY READING !!???

iOS – An Overview Of Swift Closures In iOS

Hello Readers, CoolMonkTechie heartily welcomes you in this article (An Overview Of Swift Closures In iOS) .

In this article, we will learn about Swift Closures in iOS. Swift Closures are other types of Swift functions which can be defined without using keyword func and a function name. Closures in Swift are similar to blocks in C and Objective-C and to lambdas in other programming languages. This article covers Swift Closures related concepts (like Closure Expressions, Trailing Closures, Capturing Values, Closure as Reference Types and Auto-closures) in iOS with an authentic example.

A famous quote about learning is :

” Develop a passion for learning. If you do, you will never cease to grow. ”

So Let’s begin.

Swift Closures Overview

Closures are self-contained blocks of functionality that can be passed around and used in our code. It is similar to blocks in C and Objective-C and to lambdas in other programming languages.”

Swift Closures can capture and store references to any constants and variables from the context in which they are defined. We know this as closing over those constants and variables. Swift handles all the memory management of capturing for us.

Global and nested functions are special cases of closures. Closures take one of three forms:

  • Global functions are closures that have a name and don’t capture any values.
  • Nested functions are closures that have a name and can capture values from their enclosing function.
  • Closure expressions are unnamed closures written in a lightweight syntax that can capture values from their surrounding context.

Swift’s closure expressions have a clean and clear style, with optimizations that encourage brief, clutter-free syntax in common scenarios. These optimizations include:

  • Inferring parameter and return value types from context
  • Implicit returns from single-expression closures
  • Shorthand argument names
  • Trailing closure syntax

Swift Closure Expressions

Closure expressions are a way to write inline closures in a brief, focused syntax. Closure expressions provide several syntax optimizations for writing closures in a shortened form without loss of clarity or intent. The closure expression examples below illustrate these optimizations by refining a single example of the sorted(by:) method over several iterations, each of which expresses the same functionality in a more succinct way.

The Sorted Method

Swift’s standard library provides a method called sorted(by:), which sorts an array of values of a known type, based on the output of a sorting closure that we provide. Once it completes the sorting process, the sorted(by:) method returns a new array of the same type and size as the old one, with its elements in the correct sorted order. The original array is not modified by the sorted(by:) method.

The closure expression examples below use the sorted(by:) method to sort an array of String values in reverse alphabetical order. Here’s the initial array to be sorted:

let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]

The sorted(by:) method accepts a closure that takes two arguments of the same type as the array’s contents, and returns a Bool value to say whether the first value should appear before or after the second value once the values are sorted. The sorting closure needs to return true if the first value should appear before the second value, and false otherwise.

This example is sorting an array of String values, and so the sorting closure needs to be a function of type (String, String) -> Bool.

One way to provide the sorting closure is to write a normal function of the correct type, and to pass it in as an argument to the sorted(by:) method:

func backward(_ s1: String, _ s2: String) -> Bool {
    return s1 > s2
}
var reversedNames = names.sorted(by: backward)
// reversedNames is equal to ["Ewa", "Daniella", "Chris", "Barry", "Alex"]

In this example, if the first string (s1) is greater than the second string (s2), the backward (_:_:) function will return true, it is showing that s1 should appear before s2 in the sorted array. For characters in strings, “greater than” means “appears later in the alphabet than”. This means that the letter (B) is greater than the letter (A), and the string (Tom) is greater than the string (Tim). This gives a reverse alphabetical sort, with (Barry) being placed before (Alex), and so on.

However, this is a rather long-winded way to write what is essentially a single-expression function (a > b). In this example, it would be preferable to write the sorting closure inline, using closure expression syntax.

Closure Expression Syntax

Closure expression syntax has the following general form:

{ (parameters) -> return type in
    statements
}

The parameters in closure expression syntax can be in-out parameters, but they can’t have a default value. Variadic parameters can be used if we name the variadic parameter. Tuples can also be used as parameter types and return types.

The example below shows a closure expression version of the backward(_:_:) function from above:

reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in
    return s1 > s2
})

We are aware that the declaration of parameters and return type for this inline closure is identical to the declaration from the backward(_:_:) function. In both cases, it is written as (s1: String, s2: String) -> Bool. However, for the inline closure expression, the parameters and return type are written inside the curly braces, not outside of them.

The start of the closure’s body is introduced by the in keyword. This keyword indicates that the definition of the closure’s parameters and return type has finished, and the body of the closure is about to begin.

Inferring Type From Context

Because the sorting closure is passed as an argument to a method, Swift can infer the types of its parameters and the type of the value it returns. The sorted(by:) method is being called on an array of strings, so its argument must be a function of type (String, String) -> Bool. This means that the (String, String) and Bool types don’t need to be written as part of the closure expression’s definition. Because all of the types can be inferred, the return arrow (->) and the parentheses around the names of the parameters can also be omitted:

reversedNames = names.sorted(by: { s1, s2 in return s1 > s2 } )

It is always possible to infer the parameter types and return type when passing a closure to a function or method as an inline closure expression. As a result, we never need to write an inline closure in its fullest form when the closure is used as a function or method argument.

In the case of the sorted(by:) method, the purpose of the closure is clear from the fact that sorting is taking place, and it is safe for a reader to assume that the closure is likely to be working with String values, because it is assisting with the sorting of an array of strings.

Implicit Returns from Single-Expression Closures

Single-expression closures can implicitly return the result of their single expression by omitting the return keyword from their declaration, as in this version of the previous example:

reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } )

Here, the function type of the sorted(by:) method’s argument makes it clear that a Bool value must be returned by the closure. Because the closure’s body contains a single expression (s1 > s2) that returns a Bool value, there’s no ambiguity, and the return keyword can be omitted.

Shorthand Argument Names

Swift automatically provides shorthand argument names to inline closures, which can be used to refer to the values of the closure’s arguments by the names $0$1$2, and so on.

If we use these shorthand argument names within our closure expression, we can omit the closure’s argument list from its definition, and the number and type of the shorthand argument names will be inferred from the expected function type. The in keyword can also be omitted, because the closure expression is made up entirely of its body:

reversedNames = names.sorted(by: { $0 > $1 } )

Here, $0 and $1 refer to the closure’s first and second String arguments.

Operator Methods

This is an even shorter way to write the closure expression above. Swift’s String type defines its string-specific implementation of the greater-than operator (>) as a method that has two parameters of type String, and returns a value of type Bool. This exactly matches the method type needed by the sorted(by:) method. Therefore, we can simply pass in the greater-than operator, and Swift will infer that we want to use its string-specific implementation:

reversedNames = names.sorted(by: >)

Trailing Swift Closures

If we need to pass a closure expression to a function as the function’s final argument and the closure expression is long, it can be useful to write it as a trailing closure instead. We write a trailing closure after the function call’s parentheses, even though the trailing closure is still an argument to the function.When we use the trailing closure syntax, we don’t write the argument label for the first closure as part of the function call.

A function call can include multiple trailing closures; however, the first few examples below use a single trailing closure.

func someFunctionThatTakesAClosure(closure: () -> Void) {
    // function body goes here
}

// Here's how you call this function without using a trailing closure:

someFunctionThatTakesAClosure(closure: {
    // closure's body goes here
})

// Here's how you call this function with a trailing closure instead:

someFunctionThatTakesAClosure() {
    // trailing closure's body goes here
}

The string-sorting closure from the Closure Expression Syntax section above can be written outside of the sorted(by:) method’s parentheses as a trailing closure:

reversedNames = names.sorted() { $0 > $1 }

If a closure expression is provided as the function’s or method’s only argument and we provide that expression as a trailing closure, we don’t need to write a pair of parentheses () after the function or method’s name when we call the function:

reversedNames = names.sorted { $0 > $1 }

Trailing closures are most useful when the closure is sufficiently long that it is not possible to write it inline on a single line.

Example

If a function takes multiple closures, we omit the argument label for the first trailing closure and we label the remaining trailing closures. For example, the function below loads a picture for a photo gallery:

func loadPicture(from server: Server, completion: (Picture) -> Void, onFailure: () -> Void) {
    if let picture = download("photo.jpg", from: server) {
        completion(picture)
    } else {
        onFailure()
    }
}

When we call this function to load a picture, we provide two closures. The first closure is a completion handler that displays a picture after a successful download. The second closure is an error handler that displays an error to the user.

loadPicture(from: someServer) { picture in
    someView.currentPicture = picture
} onFailure: {
    print("Couldn't download the next picture.")
}

In this example, the loadPicture(from:completion:onFailure:) function dispatches its network task into the background, and calls one of the two completion handlers when the network task finishes. Writing the function this way lets us cleanly separate the code that’s responsible for handling a network failure from the code that updates the user interface after a successful download, instead of using just one closure that handles both circumstances.

Capturing Values In Swift Closures

A closure can capture constants and variables from the surrounding context in which it is defined. The closure can then refer to and modify the values of those constants and variables from within its body, even if the original scope that defined the constants and variables no longer exists.

In Swift, the simplest form of a closure that can capture values is a nested function, written within the body of another function. A nested function can capture any of its outer function’s arguments and can also capture any constants and variables defined within the outer function.

Example

Here’s an example of a function called makeIncrementer, which contains a nested function called incrementer. The nested incrementer() function captures two values, runningTotal and amount, from its surrounding context. After capturing these values, incrementer is returned by makeIncrementer as a closure that increments runningTotal by amount each time it is called.

Code Syntax 1: makeIncrementer() function

func makeIncrementer(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementer() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return incrementer
}

The return type of makeIncrementer is () -> Int. This means that it returns a function, rather than a simple value. The function it returns has no parameters, and returns an Int value each time it is called.

The makeIncrementer(forIncrement:) function defines an integer variable called runningTotal, to store the current running total of the incrementer that will be returned. This variable is initialized with a value of 0.

The makeIncrementer(forIncrement:) function has a single Int parameter with an argument label of forIncrement, and a parameter name of amount. The argument value passed to this parameter specifies how much runningTotal should be incremented by each time the returned incrementer function is called. The makeIncrementer function defines a nested function called incrementer, which performs the actual incrementing. This function simply adds amount to runningTotal, and returns the result.

Code Syntax 2: incrementer() function

When considered in isolation, the nested incrementer() function might seem unusual:

func incrementer() -> Int {
    runningTotal += amount
    return runningTotal
}

The incrementer() function doesn’t have any parameters, and yet it refers to runningTotal and amount from within its function body. It does this by capturing a reference to runningTotal and amount from the surrounding function and using them within its own function body. Capturing by reference ensures that runningTotal and amount don’t disappear when the call to makeIncrementer ends, and also ensures that runningTotal is available the next time the incrementer function is called.

Code Syntax 3: makeIncrementer() function usage

Here’s an example of makeIncrementer usage is :

let incrementByTen = makeIncrementer(forIncrement: 10)

This example sets a constant called incrementByTen to refer to an incrementer function that adds 10 to its runningTotal variable each time it is called. Calling the function multiple times shows this behavior in action:

incrementByTen()
// returns a value of 10
incrementByTen()
// returns a value of 20
incrementByTen()
// returns a value of 30

If we create a second incrementer, it will have its own stored reference to a new, separate runningTotal variable:

let incrementBySeven = makeIncrementer(forIncrement: 7)
incrementBySeven()
// returns a value of 7

Calling the original incrementer (incrementByTen) again continues to increment its own runningTotal variable, and does not affect the variable captured by incrementBySeven:

incrementByTen()
// returns a value of 40

We are aware that Swift may instead capture and store a copy of a value as an optimization, if that value is not mutated by a closure, and if the value is not mutated after the closure is created.

Swift also handles all memory management involved in disposing of variables when they are no longer needed.

If we assign a closure to a property of a class instance, and the closure captures that instance by referring to the instance or its members, we will create a strong reference cycle between the closure and the instance. Swift uses capture lists to break these strong reference cycles.

Swift Closures As Reference Types

In the example above, incrementBySeven and incrementByTen are constants, but the closures these constants refer to are still able to increment the runningTotal variables that they have captured. This is because functions and closures are reference types.

Whenever we assign a function or a closure to a constant or a variable, we are actually setting that constant or variable to be reference to the function or closure.

Example

In the example above, it is the choice of closure that incrementByTen refers to that is constant, and not the contents of the closure itself.

This also means that if we assign a closure to two different constants or variables, both of those constants or variables refer to the same closure.

let alsoIncrementByTen = incrementByTen
alsoIncrementByTen()
// returns a value of 50

incrementByTen()
// returns a value of 60

The example above shows that calling alsoIncrementByTen is the same as calling incrementByTen. Because both of them refer to the same closure, they both increment and return the same running total.

Escaping Swift Closures

A closure is said to escape a function when the closure is passed as an argument to the function, but is called after the function returns. When we declare a function that takes a closure as one of its parameters, we can write @escaping before the parameter’s type to indicate that the closure is allowed to escape.

One way that a closure can escape is by being stored in a variable that’s defined outside the function.

Example

As an example, many functions that start an asynchronous operation take a closure argument as a completion handler. The function returns after it starts the operation, but the closure isn’t called until the operation is completed—the closure needs to escape, to be called later.

Code Syntax 1 : someFunctionWithEscapingClosure() function

var completionHandlers = [() -> Void]()
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
    completionHandlers.append(completionHandler)
}

The someFunctionWithEscapingClosure(_:) function takes a closure as its argument and adds it to an array that’s declared outside the function. If we didn’t mark the parameter of this function with @escaping, we would get a compile-time error.

An escaping closure that refers to self needs special consideration if self refers to an instance of a class. Capturing self in an escaping closure makes it easy to accidentally create a strong reference cycle.

Normally, a closure captures variables implicitly by using them in the body of the closure, but in this case we need to be explicit. If we want to capture self, write self explicitly when we use it, or include self in the closure’s capture list. Writing self explicitly lets we express our intent, and reminds us to confirm that there isn’t a reference cycle.

Code Syntax 2 : doSomething() function

For example, in the code below, the closure passed to someFunctionWithEscapingClosure(_:) refers to self explicitly. In contrast, the closure passed to someFunctionWithNonescapingClosure(_:) is a non-escaping closure, which means it can refer to self implicitly.

func someFunctionWithNonescapingClosure(closure: () -> Void) {
    closure()
}

class SomeClass {
    var x = 10
    func doSomething() {
        someFunctionWithEscapingClosure { self.x = 100 }
        someFunctionWithNonescapingClosure { x = 200 }
    }
}

let instance = SomeClass()
instance.doSomething()
print(instance.x)
// Prints "200"

completionHandlers.first?()
print(instance.x)
// Prints "100"

Here’s a version of doSomething() that captures self by including it in the closure’s capture list, and then refers to self implicitly:

class SomeOtherClass {
    var x = 10
    func doSomething() {
        someFunctionWithEscapingClosure { [self] in x = 100 }
        someFunctionWithNonescapingClosure { x = 200 }
    }
}

If self is an instance of a structure or an enumeration, we can always refer to self implicitly. However, an escaping closure can’t capture a mutable reference to self when self is an instance of a structure or an enumeration. Structures and enumerations don’t allow shared mutability.

struct SomeStruct {
    var x = 10
    mutating func doSomething() {
        someFunctionWithNonescapingClosure { x = 200 }  // Ok
        someFunctionWithEscapingClosure { x = 100 }     // Error
    }
}

The call to the someFunctionWithEscapingClosure function in the example above is an error because it’s inside a mutating method, so self is mutable. That violates the rule that escaping closures can’t capture a mutable reference to self for structures.

Auto-closures

An auto-closure is a closure that is automatically created to wrap an expression that’s being passed as an argument to a function. It doesn’t take any arguments, and when it’s called, it returns the value of the expression that’s wrapped inside of it. This syntactic convenience lets us omit braces around a function’s parameter by writing a normal expression instead of an explicit closure. It’s common to call functions that take auto-closures, but it’s not common to implement that kind of function.

For example, the assert(condition:message:file:line:) function takes an auto-closure for its condition and message parameters; its condition parameter is evaluated only in debug builds and its message parameter is evaluated only if condition is false.

An auto-closure lets us delay evaluation, because the code inside isn’t run until we call the closure. Delaying evaluation is useful for code that has side effects or is computationally expensive, because it lets us control when that code is evaluated.

Code Syntax 1 : Closure delays evaluation

The code below shows how a closure delays evaluation.

var customersInLine = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
print(customersInLine.count)
// Prints "5"

let customerProvider = { customersInLine.remove(at: 0) }
print(customersInLine.count)
// Prints "5"

print("Now serving \(customerProvider())!")
// Prints "Now serving Chris!"
print(customersInLine.count)
// Prints "4"

Even though the first element of the customersInLine array is removed by the code inside the closure, the array element isn’t removed until the closure is actually called. If the closure is not called, the expression inside the closure is not evaluated. It means the array element is not removed. We are aware that the type of customerProvider is not String but () -> String — a function with no parameters that returns a string.

Code Syntax 2 : Closure as an argument to a function

We can get the same behavior of delayed evaluation when we pass a closure as an argument to a function.

// customersInLine is ["Alex", "Ewa", "Barry", "Daniella"]
func serve(customer customerProvider: () -> String) {
    print("Now serving \(customerProvider())!")
}
serve(customer: { customersInLine.remove(at: 0) } )
// Prints "Now serving Alex!"

The serve(customer:) function in the listing above takes an explicit closure that returns a customer’s name. The version of serve(customer:) below performs the same operation but, instead of taking an explicit closure, it takes an auto-closure by marking its parameter’s type with the @autoclosure attribute. Now we can call the function as if it took a String argument instead of a closure. The argument is automatically converted to a closure, because the customerProvider parameter’s type is marked with the @autoclosure attribute.

// customersInLine is ["Ewa", "Barry", "Daniella"]
func serve(customer customerProvider: @autoclosure () -> String) {
    print("Now serving \(customerProvider())!")
}
serve(customer: customersInLine.remove(at: 0))
// Prints "Now serving Ewa!"

If we want an auto-closure that is allowed to escape, use both the @autoclosure and @escaping attributes.

// customersInLine is ["Barry", "Daniella"]
var customerProviders: [() -> String] = []
func collectCustomerProviders(_ customerProvider: @autoclosure @escaping () -> String) {
    customerProviders.append(customerProvider)
}
collectCustomerProviders(customersInLine.remove(at: 0))
collectCustomerProviders(customersInLine.remove(at: 0))

print("Collected \(customerProviders.count) closures.")
// Prints "Collected 2 closures."
for customerProvider in customerProviders {
    print("Now serving \(customerProvider())!")
}
// Prints "Now serving Barry!"
// Prints "Now serving Daniella!"

In the code above, instead of calling the closure passed to it as its customerProvider argument, the collectCustomerProviders(_:) function appends the closure to the customerProviders array. The array is declared outside the scope of the function, which means the closures in the array can be executed after the function returns. As a result, the value of the customerProvider argument must be allowed to escape the function’s scope.

That’s all about in this article.

Related Other Articles / Posts

Conclusion

In this article, we understood Swift Closures in iOS. This article reviewed Swift Closures related concepts (like Closure Expressions, Trailing Closures, Capturing Values, Closure as Reference Types and Auto-closures) in iOS with an authentic example.

Thanks for reading! I hope you enjoyed and learned about Swift Closures Concepts in iOS. Reading is one thing, but the only way to master it is to do it yourself.

Please follow and subscribe us on this blog and support us in any way possible. Also like and share the article with others for spread valuable knowledge.

You can find Other articles of CoolmonkTechie as below link :

You can also follow other website and tutorials of iOS as below links :

If you have any comments, questions, or think I missed something, feel free to leave them below in the comment box.

Thanks again Reading. HAPPY READING!!???

Android – An Overview Of Strict Mode

Hello Readers, CoolMonkTechie heartily welcomes you in this article (An Overview Of Strict Mode).

In this article, we will learn about Strict Mode in Android. Performing any kind of long blocking operations or disk IO operations on the Android Main thread can cause ANR (Application Not Responding) issues. We may not even realise that we have a potential ANR until it is too late and is already in our user’s hands. most of the cases, the library or framework which we are using in our application, will not allow us to perform disk operations on the main thread (Room for instance, makes it explicit when we want to turn it off).

So, how do we know and correct our mistakes done during android application development when the libraries or frameworks don’t explicitly prevent this kind of operation?

Android provides a Strict Mode developer tool for that.

To understand about the Strict Mode, we cover the below topics as below :

  • Overview
  • Strict Mode Policies
  • Different Ways to Notify Strict Mode
  • Enabling Strict Mode
  • Recommendations

A famous quote about learning is :

“If you live long enough, you’ll make mistakes. But if you learn from them, you’ll be a better person.

So Let’s begin.

Overview

Strict Mode is a developer tool which detects things we might be doing by accident and brings them to our attention so we can fix them.

Best practice in Android says “keeping the disk and network operations off from the main thread makes applications much smoother and more responsive”. So StrictMode is use to catch the coding issues such as disk I/O or network access on the application’s main thread i.e. UI thread. By keeping our application’s main thread responsive, we also prevent ANR dialogs from being shown to users.

This is a debugging tool introduced in Android 2.3 (API level 9) but more features were added in Android 3.0.

StrictMode Policies

Strict Mode has two types of policies and each policy has various rules. Each policy also has various methods of showing when a rule is violated.

Thread Policy

Thread policies are focused on the things which is not recommended to do in main thread like disk or network operations. The Thread policy can monitor following violations:

  • Disk Reads
  • Disk Writes
  • Network access
  • Resource Mismatch
  • Custom Slow Code

VM Policy

VM policies are focused on memory leaks because of bad coding practices like forgot to close the SQLite cursor or leaks in Activities. The VM policy can monitor following violation:

  • Activity leaks
  • SQLite objects leaks
  • Closable objects leaks
  • Registration objects leaks
  • Class instance limit
  • File URL exposure

Different Ways to Notify Strict Mode

There are variety of different ways by which user/developer get to know when a rule you set has been violated. In terms of Strict Mode, it is known as Penalty.

Some of methods are listed below:

  • penaltyDeath(): Crash the whole process on violation.
  • penaltyDeathOnNetwork(): Crash the whole process on any network usage.
  • penaltyDialog(): Show an annoying dialog to the developer on detected violations.
  • penaltyFlashScreen(): Flash the screen during a violation.
  • penaltyLog(): Log detected violations to the system log.

Enabling Strict Mode

To enable and configure the Strict Mode in our application, we require to use setThreadPolicy() and setVmPolicy() methods of Strict Mode. It is a good practice to set policies either in Application , Activity or other application component’s Application.onCreate() method:

override fun onCreate() {
        if (BuildConfig.DEBUG){
            StrictMode.setThreadPolicy(
                StrictMode.ThreadPolicy.Builder()
                    .detectDiskReads()
                    .detectDiskWrites()
                    .detectNetwork()
                    .penaltyLog()
                    .build()
            )
            StrictMode.setVmPolicy(
                StrictMode.VmPolicy.Builder()
                    .detectAll()
                    .penaltyLog()
                    .build()
            )
        }
        super.onCreate()
    }

Now, we can decide what should happen when a violation is detected like in the above example we have used only penaltyLog() for Thread Policy but in the VM Policy we used penaltyLog() as well as penaltyDeath() to notify. We can watch the output of adb logcat while we use our application to see the violations as they happen.

Here is the example of penaltyLog() showing the logs which explains Strict Mode is warning us that we are using disk write operation on the main thread.

DEBUG/StrictMode(3134): StrictMode policy violation; ~duration=319 ms: android.os.StrictMode$StrictModeDiskWriteViolation: policy=31 violation=1
DEBUG/StrictMode(3134):     at android.os.StrictMode$AndroidBlockGuardPolicy.onWriteToDisk(StrictMode.java:1041)
DEBUG/StrictMode(3134):     at android.database.sqlite.SQLiteStatement.acquireAndLock(SQLiteStatement.java:219)
DEBUG/StrictMode(3134):     at android.database.sqlite.SQLiteStatement.executeUpdateDelete(SQLiteStatement.java:83)
DEBUG/StrictMode(3134):     at android.database.sqlite.SQLiteDatabase.updateWithOnConflict(SQLiteDatabase.java:1829)
DEBUG/StrictMode(3134):     at android.database.sqlite.SQLiteDatabase.update(SQLiteDatabase.java:1780)
DEBUG/StrictMode(3134):     at com.test.data.MainActivity.update(MainActivity.java:87)

Recommendations

If we find violations that we feel are problematic, there are a variety of tools to help solve them: threads, HandlerAsyncTaskIntentService, etc. But don’t feel compelled to fix everything that Strict Mode finds. In particular, many cases of disk access are often necessary during the normal activity lifecycle. Use Strict Mode to find things we did by accident. Network requests on the UI thread are almost always a problem, though.

It is not a security mechanism and is not guaranteed to find all disk or network accesses. While it does propagate its state across process boundaries when doing Binder calls, it’s still ultimately a best effort mechanism. Notably, disk or network access from JNI calls won’t necessarily trigger it.

Many of violations are not related to our application. We want to suppress these violations. For example- DiskRead checking (or suppress any other checking of StrictMode that is it violating). Here, we want to do following things in function:

  • Turn off the Strict Mode checking
  • Running the function or the parameterized block of code
  • Turn on the original Strict Mode checking

The function looks like the below:

fun permitDiskReads(func: () -> Any?) : Any? {
    if (BuildConfig.DEBUG) {
        val oldThreadPolicy = StrictMode.getThreadPolicy()
        StrictMode.setThreadPolicy(
                StrictMode.ThreadPolicy.Builder(oldThreadPolicy)
                .permitDiskReads().build())
        val anyValue = func()
        StrictMode.setThreadPolicy(oldThreadPolicy)

        return anyValue
    } else {
        return func()
    }
}

The above example, we are just suppressing the detectDiskReads(), we could perform other suppression if required. it‘s not only running the function, but returning Any value (i.e. nothing or something if we don’t know what Any means) the function might return.

This is useful when the code that we want to suppress the check might be a function that returns something. For example, we have a SampleManager.getInstance() that also have some disk reads violation we want to suppress. So we could do as below:

val sampleManager = 
    permitDiskReads { SampleManager.getInstance() } as SampleManager

That’s all about in this article.

Conclusion

In this article, we understood about about Strict Mode in Android. This article explained about Strict Mode which is a very useful tool to find and fix performance issues, object leaks, and other hard-to-find runtime issues for Android developers. We may think that we are doing everything off the main thread, but sometimes small things can creep in and cause these issues. It helps keep our applications in check and should definitely be enabled whilst developing our applications.

Thanks for reading! I hope you enjoyed and learned about Strict Mode concepts in Android. Reading is one thing, but the only way to master it is to do it yourself.

Please follow and subscribe to the blog and support us in any way possible. Also like and share the article with others for spread valuable knowledge.

You can find other articles of CoolMonkTechie as below link :

You can also follow the official website and tutorials of Android as below links :

If you have any comments, questions, or think I missed something, leave them below in the comment box.

Thanks again Reading. HAPPY READING !!???

iOS – An Overview Of Memory Safety In Swift

Hello Readers, CoolMonkTechie heartily welcomes you in this article (An Overview Of Memory Safety In Swift) .

In this article, we will learn about an overview of Memory Safety in Swift. Swift handles most memory safety automatically, to avoid conflicts. However, certain functions may cause conflicts and will either cause compile time or runtime errors. This article reviews the access conflict to memory (like In-Out Parameters, self in Methods and Properties) in swift.

A famous quote about learning is :

” One learns from books and example only that certain things can be done. Actual learning requires that you do those things.”

So Let’s begin.

Memory Safety Overview

Swift monitors risky behaviour that may occur in the code. For example, Swift ensures that variables are introduced before they’re utilized, likewise, memory isn’t accessed once its deallocated, and array indices are checked for out-of-bounds errors.

Swift also makes sure that multiple accesses to the same area of memory don’t conflict, by requiring code that modifies a location in memory to have exclusive access to that memory. Because Swift manages memory automatically, most of the time we don’t have to think about accessing memory at all. However, it’s important to understand where potential conflicts can occur, so we can avoid writing code that has conflicting access to memory. If our code does contain conflicts, we’ll get a compile-time or runtime error.

Understanding Conflicting Access to Memory

Memory access happens in our code when we do things like set the value of a variable or pass an argument to a function. For example, the following code contains both a read access and a write access:

// A write access to the memory where one is stored.
var one = 1

// A read access from the memory where one is stored.
print("We're number \(one)!")

A conflicting access to memory can occur when different parts of our code are trying to access the same location in memory at the same time. Multiple accesses to a location in memory at the same time can produce unpredictable or inconsistent behavior. In Swift, there are ways to modify a value that span several lines of code, making it possible to attempt to access a value in the middle of its own modification.

We can see a similar problem by thinking about how we update a budget that’s written on a piece of paper. Updating the budget is a two-step process: First, we add the items’ names and prices, and then we change the total amount to reflect the items currently on the list. Before and after the update, we can read any information from the budget and get a correct answer, as shown in the figure below.

Source : Swift.org – Memory Shopping

While we’re adding items to the budget, it’s in a temporary, invalid state because the total amount hasn’t been updated to reflect the newly added items. Reading the total amount during the process of adding an item gives us incorrect information.

This example also demonstrates a challenge we may encounter when fixing conflicting access to memory: There are sometimes multiple ways to fix the conflict that produce different answers, and it’s not always obvious which answer is correct. In this example, depending on whether we wanted the original total amount or the updated total amount, either $5 or $320 could be the correct answer. Before we can fix the conflicting access, we have to determine what it was intended to do.

” If we’ve written concurrent or multithreaded code, conflicting access to memory might be a familiar problem. However, the conflicting access discussed here can happen on a single thread and doesn’t involve concurrent or multithreaded code. ”

” If we have conflicting access to memory from within a single thread, Swift guarantees that we’ll get an error at either compile time or runtime. For multithreaded code, use Thread Sanitizer to help detect conflicting access across threads. “

Characteristics of Memory Access

There are three characteristics of memory access to consider in the context of conflicting access: whether the access is a read or a write, the duration of the access, and the location in memory being accessed. Specifically, a conflict occurs if we have two accesses that meet all of the following conditions:

  • At least one is a write access or a nonatomic access.
  • They access the same location in memory.
  • Their durations overlap.

The difference between a read and write access is usually obvious: a write access changes the location in memory, but a read access doesn’t. The location in memory refers to what is being accessed—for example, a variable, constant, or property. The duration of a memory access is either instantaneous or long-term.

An operation is atomic if it uses only C atomic operations; otherwise it’s nonatomic. An access is instantaneous if it’s not possible for other code to run after that access starts but before it ends. By their nature, two instantaneous accesses can’t happen at the same time. Most memory access is instantaneous. For example, all the read and write accesses in the code listing below are instantaneous:

func oneMore(than number: Int) -> Int {
    return number + 1
}

var myNumber = 1
myNumber = oneMore(than: myNumber)
print(myNumber)
// Prints "2"

However, there are several ways to access memory, called long-term accesses, that span the execution of other code. The difference between instantaneous access and long-term access is that it’s possible for other code to run after a long-term access starts but before it ends, which is called overlap. A long-term access can overlap with other long-term accesses and instantaneous accesses.

Overlapping accesses appear primarily in code that uses in-out parameters in functions and methods or mutating methods of a structure.

Conflicting Access to In-Out Parameters

In this section, we will discuss the specific kinds of Swift code that use long-term accesses. A function has long-term write access to all of its in-out parameters. The write access for an in-out parameter starts after all of the non-in-out parameters have been evaluated and lasts for the entire duration of that function call. If there are multiple in-out parameters, the write accesses start in the same order as the parameters appear.

One consequence of this long-term write access is that we can’t access the original variable that was passed as in-out, even if scoping rules and access control would otherwise permit it—any access to the original creates a conflict. For example:

var stepSize = 1

func increment(_ number: inout Int) {
    number += stepSize
}

increment(&stepSize)
// Error: conflicting accesses to stepSize

In the code above, stepSize is a global variable, and it is normally accessible from within increment(_:). However, the read access to stepSize overlaps with the write access to number.

Source : Swift.org – Memory Increment

As shown in the figure above, both number and stepSize refer to the same location in memory. The read and write accesses refer to the same memory and they overlap, producing a conflict.

One way to solve this conflict is to make an explicit copy of stepSize:

// Make an explicit copy.
var copyOfStepSize = stepSize
increment(&copyOfStepSize)

// Update the original.
stepSize = copyOfStepSize
// stepSize is now 2

When we make a copy of stepSize before calling increment(_:), it’s clear that the value of copyOfStepSize is incremented by the current step size. The read access ends before the write access starts, so there isn’t a conflict.

Another consequence of long-term write access to in-out parameters is that passing a single variable as the argument for multiple in-out parameters of the same function produces a conflict. For example:

func balance(_ x: inout Int, _ y: inout Int) {
    let sum = x + y
    x = sum / 2
    y = sum - x
}
var playerOneScore = 42
var playerTwoScore = 30
balance(&playerOneScore, &playerTwoScore)  // OK
balance(&playerOneScore, &playerOneScore)
// Error: conflicting accesses to playerOneScore

In the above code, the balance(_:_:) function modifies its two parameters to divide the total value evenly between them. Calling it with playerOneScore and playerTwoScore as arguments doesn’t produce a conflict—there are two write accesses that overlap in time, but they access different locations in memory. In contrast, passing playerOneScore as the value for both parameters produces a conflict because it tries to perform two write accesses to the same location in memory at the same time.

Because operators are functions, they can also have long-term accesses to their in-out parameters. For example, if balance(_:_:) was an operator function named <^>, writing playerOneScore <^> playerOneScore would result in the same conflict as balance(&playerOneScore, &playerOneScore).

Conflicting Access to self in Methods

A mutating method on a structure has write access to self for the duration of the method call. For example, consider a game where each player has a health amount, which decreases when taking damage, and an energy amount, which decreases when using special abilities.

struct Player {
    var name: String
    var health: Int
    var energy: Int

    static let maxHealth = 10
    mutating func restoreHealth() {
        health = Player.maxHealth
    }
}

In the restoreHealth() method above, a write access to self starts at the beginning of the method and lasts until the method returns. In this case, there’s no other code inside restoreHealth() that could have an overlapping access to the properties of a Player instance. The shareHealth(with:) method below takes another Player instance as an in-out parameter, creating the possibility of overlapping accesses.

extension Player {
    mutating func shareHealth(with teammate: inout Player) {
        balance(&teammate.health, &health)
    }
}

var oscar = Player(name: "Oscar", health: 10, energy: 10)
var maria = Player(name: "Maria", health: 5, energy: 10)
oscar.shareHealth(with: &maria)  // OK

In the example above, calling the shareHealth(with:) method for Oscar’s player to share health with Maria’s player doesn’t cause a conflict. There’s a write access to oscar during the method call because oscar is the value of self in a mutating method, and there’s a write access to maria for the same duration because maria was passed as an in-out parameter. As shown in the figure below, they access different locations in memory. Even though the two write accesses overlap in time, they don’t conflict.

Source : Swift.org – Memory Share Health

However, if we pass oscar as the argument to shareHealth(with:), there’s a conflict:

oscar.shareHealth(with: &oscar)
// Error: conflicting accesses to oscar

The mutating method needs write access to self for the duration of the method, and the in-out parameter needs write access to teammate for the same duration. Within the method, both self and teammate refer to the same location in memory—as shown in the figure below. The two write accesses refer to the same memory and they overlap, producing a conflict.

Source : Swift.org – Memory Share Health Oscar

Conflicting Access to Properties

Types like structures, tuples, and enumerations are made up of individual constituent values, such as the properties of a structure or the elements of a tuple. Because these are value types, mutating any piece of the value mutates the whole value, meaning read or write access to one of the properties requires read or write access to the whole value. For example, overlapping write accesses to the elements of a tuple produces a conflict:

var playerInformation = (health: 10, energy: 20)
balance(&playerInformation.health, &playerInformation.energy)
// Error: conflicting access to properties of playerInformation

In the example above, calling balance(_:_:) on the elements of a tuple produces a conflict because there are overlapping write accesses to playerInformation. Both playerInformation.health and playerInformation.energy are passed as in-out parameters, which means balance(_:_:) needs write access to them for the duration of the function call. In both cases, a write access to the tuple element requires a write access to the entire tuple. This means there are two write accesses to playerInformation with durations that overlap, causing a conflict.

The code below shows that the same error appears for overlapping write accesses to the properties of a structure that’s stored in a global variable.

var holly = Player(name: "Holly", health: 10, energy: 10)
balance(&holly.health, &holly.energy)  // Error

In practice, most access to the properties of a structure can overlap safely. For example, if the variable holly in the example above is changed to a local variable instead of a global variable, the compiler can prove that overlapping access to stored properties of the structure is safe:

func someFunction() {
    var oscar = Player(name: "Oscar", health: 10, energy: 10)
    balance(&oscar.health, &oscar.energy)  // OK
}

In the example above, Oscar’s health and energy are passed as the two in-out parameters to balance(_:_:). The compiler can prove that memory safety is preserved because the two stored properties don’t interact in any way.

The restriction against overlapping access to properties of a structure isn’t always necessary to preserve memory safety. Memory safety is the desired guarantee, but exclusive access is a stricter requirement than memory safety—which means some code preserves memory safety, even though it violates exclusive access to memory. Swift allows this memory-safe code if the compiler can prove that the nonexclusive access to memory is still safe. Specifically, it can prove that overlapping access to properties of a structure is safe if the following conditions apply:

  • We’re accessing only stored properties of an instance, not computed properties or class properties.
  • The structure is the value of a local variable, not a global variable.
  • The structure is either not captured by any closures, or it’s captured only by non-escaping closures.

If the compiler can’t prove the access is safe, it doesn’t allow the access.

That’s all about in this article.

Conclusion

In this article, we understood an overview of Memory Safety in Swift. This article reviewed the access conflict to memory (like In-Out Parameters, self in Methods and Properties) in swift.

Thanks for reading! I hope you enjoyed and learned about Memory Safety Concepts in Swift. Reading is one thing, but the only way to master it is to do it yourself.

Please follow and subscribe us on this blog and support us in any way possible. Also like and share the article with others for spread valuable knowledge.

You can find Other articles of CoolmonkTechie as below link :

You can also follow other website and tutorials of iOS as below links :

If you have any comments, questions, or think I missed something, feel free to leave them below in the comment box.

Thanks again Reading. HAPPY READING!!???

Android – An Overview Of Jetpack DataStore

Hello Readers, CoolMonkTechie heartily welcomes you in this article (An Overview Of Jetpack DataStore).

In this article, we will learn about Google’s new library Jetpack DataStore in Android. Jetpack DataStore is Google’s new library to persist data as key-value pairs or typed objects using protocol buffers. Using Kotlin coroutines and Flow as its foundation, it aims to replace SharedPreferences. This is part of the Jetpack suite of libraries. This article explains about Jetpack DataStore types implementations and address the limitations of the SharedPreferences API in Android.

To understand the Jetpack DataStore, we cover the below topics as below :

  • Overview
  • Limitation of SharedPreferences
  • Types of Jetpack DataStore Implementations
  • Jetpack DataStore Setup
  • Store key-value pairs with Preferences DataStore
  • Store typed objects with Proto DataStore
  • Use Jetpack DataStore in synchronous code

A famous quote about learning is :

“One learns from books and example only that certain things can be done. Actual learning requires that you do those things.”

So Let’s begin.

Overview

Jetpack DataStore is a data storage solution that allows us to store key-value pairs or typed objects with protocol buffers. DataStore uses Kotlin coroutines and Flow to store data asynchronously, consistently, and transactionally. Google introduced DataStore to address the limitations in the SharedPreferences API.

Limitation of SharedPreferences

To understand the DataStore’s advantages, we need to know about the limitations of SharedPreferences API. Even though SharedPreferences has been around since API level 1, it has drawbacks that have persisted over time:

  • SharedPreferences is not always safe call on the UI thread. It can cause junk by blocking the UI thread.
  • There is no way for SharedPreferences to signal errors except for parsing errors as runtime exceptions.
  • SharedPreferences has no support for data migration. If we want to change the type of a value, we have to write the entire logic manually.
  • SharedPreferences doesn’t provide type safety. Application will compile fine If we try to store both Booleans and Integers using the same key.

Google introduced DataStore to address the above limitations.

Types of Jetpack DataStore Implementations

DataStore provides two different implementations: Preferences DataStore and Proto DataStore.

  • Preferences DataStore: Stores and accesses data using keys. This implementation does not require a predefined schema, and it does not provide type safety. This is similar to SharedPreferences. We use this to store and retrieve primitive data types.
  • Proto DataStore: Uses protocol buffers to store custom data types. When using Proto DataStore, we need to define a schema for the custom data type.

SharedPreferences uses XML to store data. As the amount of data increases, the file size increases dramatically and it’s more expensive for the CPU to read the file.

Protocol buffers are a new way to represent structured data that’s faster and than XML and has a smaller size. They’re helpful when the read-time of stored data affects the performance of our application.

Jetpack DataStore Setup

To use Jetpack DataStore in application, we add the following dependencies to Gradle file depending on which implementation we want to use:

Datastore Typed

    // Typed DataStore (Typed API surface, such as Proto)
    dependencies {
        implementation("androidx.datastore:datastore:1.0.0")

        // optional - RxJava2 support
        implementation("androidx.datastore:datastore-rxjava2:1.0.0")

        // optional - RxJava3 support
        implementation("androidx.datastore:datastore-rxjava3:1.0.0")
    }

    // Alternatively - use the following artifact without an Android dependency.
    dependencies {
        implementation("androidx.datastore:datastore-core:1.0.0")
    }
    

Datastore Preferences

    // Preferences DataStore (SharedPreferences like APIs)
    dependencies {
        implementation("androidx.datastore:datastore-preferences:1.0.0")

        // optional - RxJava2 support
        implementation("androidx.datastore:datastore-preferences-rxjava2:1.0.0")

        // optional - RxJava3 support
        implementation("androidx.datastore:datastore-preferences-rxjava3:1.0.0")
    }

    // Alternatively - use the following artifact without an Android dependency.
    dependencies {
        implementation("androidx.datastore:datastore-preferences-core:1.0.0")
    }
    

If we use the datastore-preferences-core artifact with Proguard, we must manually add Proguard rules to our proguard-rules.pro file to keep our fields from being deleted.

Store key-value pairs with Preferences DataStore

The Preferences DataStore implementation uses the DataStore and Preferences classes to persist simple key-value pairs to disk.

Create a Preferences DataStore

// At the top level of our kotlin file:
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "settings")

Use the property delegate created by preferencesDataStore to create an instance of Datastore<Preferences>. Call it once at the top level of kotlin file, and access it through this property throughout the rest of application. This makes it easier to keep DataStore as singleton.

Read from a Preferences DataStore

val EXAMPLE_COUNTER = intPreferencesKey("example_counter")
val exampleCounterFlow: Flow<Int> = context.dataStore.data
  .map { preferences ->
    // No type safety.
    preferences[EXAMPLE_COUNTER] ?: 0
}

Because Preferences DataStore does not use a predefined schema, we must use the corresponding key type function to define a key for each value that we need to store in the DataStore<Preferences> instance.

Write to a Preferences DataStore

suspend fun incrementCounter() {
  context.dataStore.edit { settings ->
    val currentCounterValue = settings[EXAMPLE_COUNTER] ?: 0
    settings[EXAMPLE_COUNTER] = currentCounterValue + 1
  }
}

Preferences DataStore provides an edit() function that transactionally updates the data in a DataStore. The function’s transform parameter accepts a block of code where we can update the values as needed. All of the code in the transform block is treated as a single transaction.

Store typed objects with Proto DataStore

The Proto DataStore implementation uses DataStore and protocol buffers to persist typed objects to disk.

Define a schema

Proto DataStore requires a predefined schema in a proto file in the app/src/main/proto/ directory. This schema defines the type for the objects that we persist in our Proto DataStore.

syntax = "proto3";

option java_package = "com.example.application";
option java_multiple_files = true;

message Settings {
  int32 example_counter = 1;
}

The class for our stored objects is generated at compile time from the message defined in the proto file. Make sure we rebuild our project.

Create a Proto DataStore

There are two steps involved in creating a Proto DataStore to store typed objects:

  • Step 1 : Define a class that implements Serializer<T>, where T is the type defined in the proto file. This serializer class tells DataStore how to read and write data type. Make sure we include a default value for the serializer to be used if there is no file created yet.
  • Step 2 : Use the property delegate created by dataStore to create an instance of DataStore<T>, where T is the type defined in the proto file. Call this once at the top level of kotlin file and access it through this property delegate throughout the rest of application. The filename parameter tells DataStore which file to use to store the data, and the serializer parameter tells DataStore the name of the serializer class defined in step 1.
object SettingsSerializer : Serializer<Settings> {
  override val defaultValue: Settings = Settings.getDefaultInstance()

  override suspend fun readFrom(input: InputStream): Settings {
    try {
      return Settings.parseFrom(input)
    } catch (exception: InvalidProtocolBufferException) {
      throw CorruptionException("Cannot read proto.", exception)
    }
  }

  override suspend fun writeTo(
    t: Settings,
    output: OutputStream) = t.writeTo(output)
}

val Context.settingsDataStore: DataStore<Settings> by dataStore(
  fileName = "settings.pb",
  serializer = SettingsSerializer
)

Read from a Proto DataStore

We use DataStore.data to expose a Flow of the appropriate property from our stored object.

val exampleCounterFlow: Flow<Int> = context.settingsDataStore.data
  .map { settings ->
    // The exampleCounter property is generated from the proto schema.
    settings.exampleCounter
  }

Write to a Proto DataStore

Proto DataStore provides an updateData() function that transactionally updates a stored object. updateData() gives us the current state of the data as an instance of our data type and updates the data transactionally in an atomic read-write-modify operation.

suspend fun incrementCounter() {
  context.settingsDataStore.updateData { currentSettings ->
    currentSettings.toBuilder()
      .setExampleCounter(currentSettings.exampleCounter + 1)
      .build()
    }
}

Use Jetpack DataStore in synchronous code

Asynchronous API is one of the primary benefits of DataStore. It may not always be feasible to change our surrounding code to be asynchronous. This might be the case if we’re working with an existing codebase that uses synchronous disk I/O or if we have a dependency that doesn’t provide an asynchronous API.

Kotlin coroutines provide the runBlocking() coroutine builder to help bridge the gap between synchronous and asynchronous code. We can use runBlocking() to read data from DataStore synchronously. RxJava offers blocking methods on Flowable. The following code blocks the calling thread until DataStore returns data:

val exampleData = runBlocking { context.dataStore.data.first() }

Performing synchronous I/O operations on the UI thread can cause ANRs or UI junk. We can mitigate these issues by asynchronously preloading the data from DataStore:

override fun onCreate(savedInstanceState: Bundle?) {
    lifecycleScope.launch {
        context.dataStore.data.first()
        // You should also handle IOExceptions here.
    }
}

This way, DataStore asynchronously reads the data and caches it in memory. Later synchronous reads using runBlocking() may be faster or may avoid a disk I/O operation altogether if the initial read has completed.

That’s all about in this article.

Conclusion

In this article, we understood about Google’s new library Jetpack DataStore in Android. This article explained about Jetpack DataStore types implementations and address the limitations of the SharedPreferences API in Android.

Thanks for reading! I hope you enjoyed and learned about Jetpack DataStore concepts in Android. Reading is one thing, but the only way to master it is to do it yourself.

Please follow and subscribe to the blog and support us in any way possible. Also like and share the article with others for spread valuable knowledge.

You can find other articles of CoolMonkTechie as below link :

You can also follow the official website and tutorials of Android as below links :

If you have any comments, questions, or think I missed something, leave them below in the comment box.

Thanks again Reading. HAPPY READING !!???

Android – An Overview Of Application Security Best Practices

Hello Readers, CoolMonkTechie heartily welcomes you in this article (An Overview Of Application Security Best Practices).

In this article, we will learn about the best practices of Application Security in Android. By making our application more secure in android, we help preserve user trust and device integrity. This article explains about few best practices that have a significant, positive impact on our application’s security.

To understand the Application Security Best Practices, we cover the below topics as below :

  • Enforce secure communication with other applications
  • Provide the right permissions
  • Store data safely
  • Keep the services and related dependencies up-to-date

A famous quote about learning is :

“Being a student is easy. Learning requires actual work.”

So Let’s begin.

1. Enforce secure communication with other applications

When we safeguard the data that we want to exchange between our application and other applications, or between our application and a website, we improve our application’s stability and protect the data that we want to send and receive.

1.1 Use implicit intents and non-exported content providers

1.1.1 Show an application chooser

Use implicit intents to show application chooser that provides option to user to launch at least two possible applications on the device for the requested action. This allows users to transfer sensitive information to the application that they trust.

val intent = Intent(Intent.ACTION_SEND)
val possibleActivitiesList: List<ResolveInfo> =
        packageManager.queryIntentActivities(intent, PackageManager.MATCH_ALL)

// Verify that an activity in at least two applications on the user's device
// can handle the intent. Otherwise, start the intent only if an application
// on the user's device can handle the intent.
if (possibleActivitiesList.size > 1) {

    // Create intent to show chooser.
    // Title is something similar to "Share this photo with".

    val chooser = resources.getString(R.string.chooser_title).let { title ->
        Intent.createChooser(intent, title)
    }
    startActivity(chooser)
} else if (intent.resolveActivity(packageManager) != null) {
    startActivity(intent)
}

1.1.2 Apply signature-based permissions

Apply signature-based permissions while sharing data between two applications that is controlled by us. These permissions do not need user confirmation, but instead it checks that the applications accessing the data are signed using the same signing key. Hence offer more streamlined and secure user experience.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapp">
    <permission android:name="my_custom_permission_name"
                android:protectionLevel="signature" />

1.1.3 Disallow access to our application’s content providers

Unless we intend to send data from our application to a different application that we don’t own, we should explicitly disallow other developers’ apps from accessing the ContentProvider objects that our application contains. This setting is particularly important if our application can be installed on devices running Android 4.1.1 (API level 16) or lower, as the android:exported attribute of the <provider> element is true by default on those versions of Android.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapp">
    <application ... >
        <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="com.example.myapp.fileprovider"
            ...
            android:exported="false">
            <!-- Place child elements of <provider> here. -->
        </provider>
        ...
    </application>
</manifest>

1.2 Ask for credentials before showing sensitive information

When we are requesting the credentials so that we can access sensitive information or premium content in our application, ask for either a PIN/password/pattern or a biometric credential, such as using face recognition or fingerprint recognition.

1.3 Apply network security measures

Ensure network security with Security with HTTPS and SSL — For any kind of network communication we must use HTTPS (instead of plain http) with proper certificate implementation. This section describes how we can improve our application’s network security.

1.3.1 Use SSL traffic

If our application communicates with a web server that has a certificate issued by a well-known, trusted CA, the HTTPS request is very simple:

val url = URL("https://www.google.com")
val urlConnection = url.openConnection() as HttpsURLConnection
urlConnection.connect()
urlConnection.inputStream.use {
    ...
}

1.3.2 Add a network security configuration

If our application uses new or custom CAs, we can declare our network’s security settings in a configuration file. This process allows us to create the configuration without modifying any application code.

To add a network security configuration file to our application, we can follow these steps:

  1. Declare the configuration in our application’s manifest:
<manifest ... >
    <application
        android:networkSecurityConfig="@xml/network_security_config"
        ... >
        <!-- Place child elements of <application> element here. -->
    </application>
</manifest>

2. We add an XML resource file, located at res/xml/network_security_config.xml.

Specify that all traffic to particular domains should use HTTPS by disabling clear-text:

<network-security-config>
    <domain-config cleartextTrafficPermitted="false">
        <domain includeSubdomains="true">secure.example.com</domain>
        ...
    </domain-config>
</network-security-config>

During the development process, we can use the <debug-overrides> element to explicitly allow user-installed certificates. This element overrides our application’s security-critical options during debugging and testing without affecting the application’s release configuration.

The following snippet shows how to define this element in our application’s network security configuration XML file:

<network-security-config>
    <debug-overrides>
        <trust-anchors>
            <certificates src="user" />
        </trust-anchors>
    </debug-overrides>
</network-security-config>

1.3.3 Create own trust manager

Our SSL checker shouldn’t accept every certificate. We may need to set up a trust manager and handle all SSL warnings that occur if one of the following conditions applies to our use case:

  • We’re communicating with a web server that has a certificate signed by a new or custom CA.
  • That CA isn’t trusted by the device we’re using.
  • You cannot use a network security configuration.

1.4 Use WebView objects carefully

Whenever possible, we load only allowlisted content in WebView objects. In other words, the WebView objects in our application shouldn’t allow users to navigate to sites that are outside of our control. In addition, we should never enable JavaScript interface support unless we completely control and trust the content in our application’s WebView objects.

1.4.1 Use HTML message channels

If our application must use JavaScript interface support on devices running Android 6.0 (API level 23) and higher, use HTML message channels instead of communicating between a website and your app, as shown in the following code snippet:

val myWebView: WebView = findViewById(R.id.webview)

// channel[0] and channel[1] represent the two ports.
// They are already entangled with each other and have been started.
val channel: Array<out WebMessagePort> = myWebView.createWebMessageChannel()

// Create handler for channel[0] to receive messages.
channel[0].setWebMessageCallback(object : WebMessagePort.WebMessageCallback() {

    override fun onMessage(port: WebMessagePort, message: WebMessage) {
        Log.d(TAG, "On port $port, received this message: $message")
    }
})

// Send a message from channel[1] to channel[0].
channel[1].postMessage(WebMessage("My secure message"))

2. Provide the right permissions

Application should request only the minimum number of permissions necessary to function properly.

2.1 Use intents to defer permissions

It should not add a permission to complete an action that could be completed in another application. Instead, we use an intent to defer the request to a different application that already has the necessary permission.

For example, If an application requires to create a contact to a contact application, it delegates the responsibility of creating the contact to a contacts application, which has already been granted the appropriate WRITE_CONTACTS permission.

// Delegates the responsibility of creating the contact to a contacts application,
// which has already been granted the appropriate WRITE_CONTACTS permission.
Intent(Intent.ACTION_INSERT).apply {
    type = ContactsContract.Contacts.CONTENT_TYPE
}.also { intent ->
    // Make sure that the user has a contacts application installed on their device.
    intent.resolveActivity(packageManager)?.run {
        startActivity(intent)
    }
}

In addition, if our application needs to perform file-based I/O – such as accessing storage or choosing a file – it doesn’t need special permissions because the system can complete the operations on our application’s behalf. Better still, after a user selects content at a particular URI, the calling application gets granted permission to the selected resource.

2.2 Share data securely across applications

We can follow these best practices in order to share our application’s content with other applications in a more secure manner:

  • Enforce read-only or write-only permissions as needed.
  • Provide clients one-time access to data by using the FLAG_GRANT_READ_URI_PERMISSION and FLAG_GRANT_WRITE_URI_PERMISSION flags.
  • When sharing data, we use “content://” URIs, not “file://” URIs. Instances of FileProvider do this for us.

The following code snippet shows how to use URI permission grant flags and content provider permissions to display an application’s PDF file in a separate PDF Viewer application:

// Create an Intent to launch a PDF viewer for a file owned by this application.
Intent(Intent.ACTION_VIEW).apply {
    data = Uri.parse("content://com.example/personal-info.pdf")

    // This flag gives the started application read access to the file.
    addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
}.also { intent ->
    // Make sure that the user has a PDF viewer application installed on their device.
    intent.resolveActivity(packageManager)?.run {
        startActivity(intent)
    }
}

3. Store data safely

Although our application might require access to sensitive user information, our users will grant our application access to their data only if they trust that we’ll safeguard it properly.

3.1 Store private data within internal storage

We need to store all private user data within the device’s internal storage, which is sandboxed per application. Our application doesn’t need to request permission to view these files, and other applications cannot access the files. As an added security measure, when the user uninstalls an app, the device deletes all files that the app saved within internal storage.

We consider working with EncryptedFile objects if storing data is particularly sensitive or private. These objects are available from Security library instead of File objects.

For Example, one way to write data to storage demonstrates in the below code snippet:

// Although you can define your own key generation parameter specification, it's
// recommended that you use the value specified here.
val keyGenParameterSpec = MasterKeys.AES256_GCM_SPEC
val mainKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec)

// Create a file with this name, or replace an entire existing file
// that has the same name. Note that you cannot append to an existing file,
// and the file name cannot contain path separators.
val fileToWrite = "my_sensitive_data.txt"
val encryptedFile = EncryptedFile.Builder(
    File(DIRECTORY, fileToWrite),
    applicationContext,
    mainKeyAlias,
    EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
).build()

val fileContent = "MY SUPER-SECRET INFORMATION"
        .toByteArray(StandardCharsets.UTF_8)
encryptedFile.openFileOutput().apply {
    write(fileContent)
    flush()
    close()
}

Another example shows the inverse operation, reading data from storage:

// Although you can define your own key generation parameter specification, it's
// recommended that you use the value specified here.
val keyGenParameterSpec = MasterKeys.AES256_GCM_SPEC
val mainKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec)

val fileToRead = "my_sensitive_data.txt"
val encryptedFile = EncryptedFile.Builder(
    File(DIRECTORY, fileToRead),
    applicationContext,
    mainKeyAlias,
    EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
).build()

val inputStream = encryptedFile.openFileInput()
val byteArrayOutputStream = ByteArrayOutputStream()
var nextByte: Int = inputStream.read()
while (nextByte != -1) {
    byteArrayOutputStream.write(nextByte)
    nextByte = inputStream.read()
}

val plaintext: ByteArray = byteArrayOutputStream.toByteArray()

3.2 Store data in external storage based on use case

We consider external storage for large, non-sensitive files that are specific to our application, as well as files that our application shares with other applications. The specific APIs that we use depend on whether our application is designed to access app-specific files or access shared files.

3.2.1 Check availability of storage volume

When user interacts with a removable external storage device from the application, then he might remove the storage device while our app is trying to access it. We need to include logic to verify that the storage device is available.

3.2.2 Access application-specific files

If a file doesn’t contain private or sensitive information but provides value to the user only in our application, we store the file in an application-specific directory on external storage.

3.2.3 Access shared files

If our application needs to access or store a file that provides value to other applications, we can use one of the following APIs depending on our use case:

  • Media files: To store and access images, audio files, and videos that are shared between apps, use the Media Store API.
  • Other files: To store and access other types of shared files, including downloaded files, use the Storage Access Framework.

3.2.4 Check validity of data

If our application uses data from external storage, make sure that the contents of the data haven’t been corrupted or modified. Our application should also include logic to handle files that are no longer in a stable format.

We take an example of hash verifier in below code snippet:

val hash = calculateHash(stream)
// Store "expectedHash" in a secure location.
if (hash == expectedHash) {
    // Work with the content.
}

// Calculating the hash code can take quite a bit of time, so it shouldn't
// be done on the main thread.
suspend fun calculateHash(stream: InputStream): String {
    return withContext(Dispatchers.IO) {
        val digest = MessageDigest.getInstance("SHA-512")
        val digestStream = DigestInputStream(stream, digest)
        while (digestStream.read() != -1) {
            // The DigestInputStream does the work; nothing for us to do.
        }
        digest.digest().joinToString(":") { "%02x".format(it) }
    }
}

3.3 Store only non-sensitive data in cache files

To provide quicker access to non-sensitive application data, we store it in the device’s cache. For caches larger than 1 MB in size, we use getExternalCacheDir() otherwise, use getCacheDir(). Each method provides the File object that contains our application’s cached data.

Let’s take one example code snippet that shows how to cache a file that application recently downloaded:

val cacheFile = File(myDownloadedFileUri).let { fileToCache ->
    File(cacheDir.path, fileToCache.name)
}

If we use use getExternalCacheDir() to place our application’s cache within shared storage, the user might eject the media containing this storage while our application run. We should include logic to gracefully handle the cache miss that this user behavior causes.

3.4 Use SharedPreferences in private mode

When we are using getSharedPreferences() to create or access our application’s SharedPreferences objects, use MODE_PRIVATE. That way, only our application can access the information within the shared preferences file.

Moreover, EncryptedSharedPreferences should be used for more security which wraps the SharedPreferences class and automatically encrypts keys and values.

4. Keep services and dependencies up-to-date

Most applications use external libraries and device system information to complete specialized tasks. By keeping our app’s dependencies up to date, we make these points of communication more secure.

4.1 Check the Google Play services security provider

If our application uses Google Play services, make sure that it’s updated on the device where our application is installed. This check should be done asynchronously, off of the UI thread. If the device isn’t up-to-date, our application should trigger an authorization error.

4.2 Update all application dependencies

Before deploying our application, make sure that all libraries, SDKs, and other dependencies are up to date:

  • For first-party dependencies, such as the Android SDK, we use the updating tools found in Android Studio, such as the SDK Manager.
  • For third-party dependencies, we check the websites of the libraries that our app uses, and install any available updates and security patches.

That’s all about in this article.

Related Other Articles / Posts

Conclusion

In this article, we understood about the best practices of Application Security in Android. This article explained about few best practices that every mobile app developer must follow to secure the application from vulnerability. This helps us to develop the highly secure applications required to prevent valuable user information of our application and maintain the trust of our client.

Thanks for reading! I hope you enjoyed and learned about the best practices of Application Security concepts in Android. Reading is one thing, but the only way to master it is to do it yourself.

Please follow and subscribe to the blog and support us in any way possible. Also like and share the article with others for spread valuable knowledge.

You can find other articles of CoolMonkTechie as below link :

You can also follow official website and tutorials of Android as below links :

If you have any comments, questions, or think I missed something, leave them below in the comment box.

Thanks again Reading. HAPPY READING !!???

Android – How To Implement Automatic Functions Memoization Technique In Kotlin?

Hello Readers, CoolMonkTechie heartily welcomes you in this article (How To Implement Automatic Functions Memoization Technique in Kotlin ?).

In this article, we will learn about how to implement Automatic Functions Memoization Technique in Kotlin. Memoization is a technique used to optimize the program-execution speed by caching the results of expensive function calls and reusing their ready values when they are required again. Although memoization causes an obvious trade-off between memory usage and computation time, often it’s crucial to provide the desired performance. This article explains about Automatic Functions Memoization Technique work flows in Kotlin.

To understand the Automatic Functions Memoization Technique in Kotlin, we cover the below topics as below :

  • Overview
  • How to Implement Technique?
  • How Technique Works?

A famous quote about learning is :

“That is what learning is. You suddenly understand something you’ve understood all your life, but in a new way.”

So Let’s begin.

Overview

We can understand about Memoization as:

  • A technique used to optimize the program-execution speed by caching the results of expensive function calls and reusing their ready values when they are required again.
  • An obvious trade-off between memory usage and computation time, often it’s crucial to provide the desired performance. Usually, we apply this pattern to computationally-expensive functions.
  • It can help to optimize recursive functions that call themselves multiple times with the same parameters values.

Memoization can easily be added internally to function implementation. However, in this article, we are going to create a general-purpose, reusable memoization mechanism that could be applied to any function.

How to Implement Technique?

In this section, We will understand how to implement it and What steps are required for implementation.

Step 1 – Declare a Memoizer class responsible for caching the results:

class Memoizer<P, R> private constructor() { 
   private val map = ConcurrentHashMap<P, R>() 
   private fun doMemoize(function: (P) -> R):
         (P) -> R = { param: P ->
            map.computeIfAbsent(param) { param: P ->
                function(param)
                    }
             }
   companion object { 
       fun <T, U> memoize(function: (T) -> U):
       (T) -> U =
                 Memoizer<T, U>().doMemoize(function)
     }
 } 

Step 2 – Provide a memoized() extension function for the (P) -> R function type:

fun <P, R> ((P) -> R).memoized(): (P) -> R = Memoizer.memoize<P, R>(this)

How Technique Works?

The memoize() function takes an instance of a one-argument function as its argument. The Memoizer class contains the ConcurrentHashmap<P, R> instance, which is used to cache the function’s return values. The map stores functions passed to memoize() as arguments as the keys, and it puts their return values as its values.

First, the memoize() function looks up the value for a specific parameter of the function passed as an argument. If the value is present in the map, it is returned. Otherwise, the function is executed and its result is returned by memoize() and put into the map. This is achieved using the handy inline fun <K, V> ConcurrentMap<K, V>.computeIfAbsent(key: K, defaultValue: () -> V): V extension function provided by the standard library.

Additionally, we can provide an extension function, memoized(), for the Function1 type, which will allow us to apply the memoize() function directly to the function references.

Note that the under the hood functions in Kotlin are compiled to the FunctionN interface instances in the Java bytecode, where N corresponds to the number of function arguments. We can declare an extension function for a function. For example, in order to add an extension function for a function taking two arguments, (P, Q) -> R, we need to define an extension as fun <P, Q, R> Function2<P, Q, R>.myExtension(): MyReturnType.

Now, take a look at how we can benefit from the memoized() function in action. Consider a function that computes the factorial of an integer recursively:

fun factorial(n: Int): Long = if (n == 1) n.toLong() else n * factorial(n - 1)

We can apply the memoized() extension function to enable caching of the results:

val cachedFactorial = ::factorial.memoized()
println(" Execution time: " + measureNanoTime { cachedFactorial(12) } + " ns")
println(" Execution time: " + measureNanoTime { cachedFactorial(13) } + " ns")

The above code snippet gives the following output on a standard computer:

Execution time: 1547274 ns
Execution time: 24690 ns

As we can see, even though the second computation requires a higher number of recursive calls of the factorial() function, it takes much less time than the first computation.

We can implement similar automatic memoization implementations for other functions that take more than one argument. In order to declare an extension function for a function taking N arguments, we’d have to implement an extension function for the FunctionN type.

That’s all about in this article.

Related Other Articles / Posts

Conclusion

In this article, we understood about how to implement Automatic Functions Memoization Technique in Kotlin. This article explained about Automatic Functions Memoization Technique work flows in Kotlin.

Thanks for reading! I hope you enjoyed and learned about Automatic Functions Memoization Technique concepts in Kotlin. Reading is one thing, but the only way to master it is to do it yourself.

Please follow and subscribe to the blog and support us in any way possible. Also like and share the article with others for spread valuable knowledge.

You can find other articles of CoolMonkTechie as below link :

You can also follow official website and tutorials of Android as below links :

If you have any comments, questions, or think I missed something, leave them below in the comment box.

Thanks again Reading. HAPPY READING !!???

Android – How To Implement Either Monad Design Pattern in Kotlin ?

Hello Readers, CoolMonkTechie heartily welcomes you in this article (How To Implement Either Monad Design Pattern in Kotlin ?).

In this article, we will learn about how to implement Either Monad Design Pattern in Kotlin. The concept of Monad is one of the fundamental functional programming design patterns. We can understand a Monad as an encapsulation for a data type that adds a specific functionality to it or provides custom handlers for different states of the encapsulated object.

One of the most commonly used is a Maybe monad. The Maybe monad is supposed to provide information about the enclosed property presence. It can return an instance of the wrapped type whenever it’s available or nothing when it’s not. Java 8 introduced the Optional class, which is implementing the Maybe concept. It’s a great way to avoid operating on null values. This article explains about Either Monad Design Pattern work flows in Kotlin.

To understand the Either Monad Design Pattern in Kotlin, we cover the below topics as below :

  • Overview
  • Pattern Implementation Steps
  • How Pattern Works ?

A famous quote about learning is :

” The beautiful thing about learning is that nobody can take it away from you.”

So Let’s begin.

Overview

We can understand about Either Monad Design Pattern as:

  • A fundamental functional programming design patterns and,
  • Consider a Monad as an encapsulation for a data type that adds a specific functionality or provides custom handlers for different states of the encapsulated object.

However, apart from having the information about the unavailable state, we would often like to be able to provide some additional information. For example, if the server returns an empty response, it would be useful to get an error code or a message instead of the null or an empty response string. This is a scenario for another type of Monad, usually called Either, which we are going to implement in this article.

Pattern Implementation Steps

In this section, We will understand how to implement it and What steps are required for implementation.

Step 1 – Declare Either as a sealed class

sealed class Either<out E, out V>

Step 2 – Add two subclasses of Either, representing Error and Value:

sealed class Either<out L, out R> {
     data class Left<out L>(val left: L) : Either<L, Nothing>()
     data class Right<out R>(val right: R) : Either<Nothing, R>()
 }
 

Step 3 – Add factory functions to conveniently instantiate Either:

sealed class Either<out L, out R> {
     data class Left<out L>(val left: L) : Either<L, Nothing>()
     data class Right<out R>(val right: R) : Either<Nothing, R>()

     companion object {
        fun <R> right(value: R): Either<Nothing, R> = Either.Right(value) 
        fun <L> left(value: L): Either<L, Nothing> = Either.Left(value)
     }
 }

How Pattern Works ?

In order to make use of the class Either and benefit from the Either.right() and Either.left() methods, we can implement a getEither() function that will try to perform some operation passed to it as a parameter. If the operation succeeds, it is going to return the Either.Right instance holding the result of the operation, otherwise, it is going to return Either.Left, holding a thrown exception instance:

fun<V> getEither(action: () -> V): Either<Exception, V> =
         try { Either.right(action()) } catch (e: Exception) { Either.left(e) }
 

By convention, we can use the Either.Right type to provide a default value and Either.Left to handle any possible edge cases.

One essential functional programming feature the Either Monad can provide is the ability to apply functions to its values. We can simply extend the Either class with the fold() function, which can take two functions as the parameters. The first function should be applied to the Either.Left type and the second should be applied to Either.Right:

sealed class Either<out L, out R> {
     data class Left<out L>(val left: L) : Either<L, Nothing>()
     data class Right<out R>(val right: R) : Either<Nothing, R>()

 fun <T> fold(leftOp: (L) -> T, rightOp: (R) -> T): T = when (this) {
         is Left -> leftOp(this.left)
         is Right -> rightOp(this.right)
     }
 //…
 }
 

The fold() function will return a value from either the leftOp or rightOp function, whichever is used. The usage of the fold() function can be illustrated with a server-request parsing example.

Suppose we have the following types declared:

data class Response(val json: JsonObject)
data class ErrorResponse(val code: Int, val message: String)

And we have also a function responsible for delivering a backend response:

fun someGetRequest(): Either<ErrorResponse, Response> = //..
  

We can use the fold() function to handle the returned value in the right way:

someGetRequest().fold({
     showErrorInfo(it.message)
 }, {
     parseAndDisplayResults(it.json)
 })

We can also extend the Either class with other useful functions, like the ones available in the standard library for data-processing operations—mapfilter, and exists.

That’s all about in this article.

Related Other Articles / Posts

Conclusion

In this article, we understood about how to implement Either Monad Design Pattern in Kotlin. This article explained about Either Monad Design Pattern work flows in Kotlin.

Thanks for reading! I hope you enjoyed and learned about Either Monad Design Pattern concepts in Kotlin. Reading is one thing, but the only way to master it is to do it yourself.

Please follow and subscribe to the blog and support us in any way possible. Also like and share the article with others for spread valuable knowledge.

You can find other articles of CoolMonkTechie as below link :

You can also follow official website and tutorials of Android as below links :

If you have any comments, questions, or think I missed something, leave them below in the comment box.

Thanks again Reading. HAPPY READING !!???

Exit mobile version