Thursday, August 31, 2017
Wednesday, August 30, 2017
Polymorphism With Protocols in Elixir
Polymorphism is an important concept in programming, and novice programmers usually learn about it during the first months of studying. Polymorphism basically means that you can apply a similar operation to entities of different types. For instance, the count/1 function can be applied both to a range and to a list:
Enum.count(1..3) Enum.count([1,2,3])
How is that possible? In Elixir, polymorphism is achieved by using an interesting feature called a protocol, which acts like a contract. For each data type you wish to support, this protocol must be implemented.
All in all, this approach is not revolutionary, as it is found in other languages (like Ruby, for example). Still, protocols are really convenient, so in this article we will discuss how to define, implement and work with them while exploring some examples. Let's get started!
Brief Introduction to Protocols
So, as already mentioned above, a protocol has some generic code and relies on the specific data type to implement the logic. This is reasonable, because different data types may require different implementations. A data type can then dispatch on a protocol without worrying about its internals.
Elixir has a bunch of built-in protocols, including Enumerable
, Collectable
, Inspect
, List.Chars
, and String.Chars
. Some of them will be discussed later in this article. You may implement any of these protocols in your custom module and get a bunch of functions for free. For instance, having implemented Enumerable, you'll get access to all the functions defined in the Enum module, which is quite cool.
If you have come from the wondrous Ruby world full of objects, classes, fairies and dragons, you'll have met a very similar concept of mixins. For example, if you ever need to make your objects comparable, simply mix a module with the corresponding name into the class. Then just implement a spaceship <=>
method and all instances of the class will get all methods like >
and <
for free. This mechanism is somewhat similar to protocols in Elixir. Even if you have never met this concept before, believe me, it is not that complex.
Okay, so first things first: the protocol must be defined, so let's see how it can be done in the next section.
Defining a Protocol
Defining a protocol does not involve any black magic—in fact, it is very similar to defining modules. Use defprotocol/2 to do it:
defprotocol MyProtocol do end
Inside the protocol's definition you place functions, just like with modules. The only difference is that these functions have no body. It means that the protocol only defines an interface, a blueprint that should be implemented by all the data types that wish to dispatch on this protocol:
defprotocol MyProtocol do def my_func(arg) end
In this example, a programmer needs to implement the my_func/1
function to successfully utilize MyProtocol
.
If the protocol is not implemented, an error will be raised. Let's return to the example with the count/1
function defined inside the Enum
module. Running the following code will end up with an error:
Enum.count 1 # ** (Protocol.UndefinedError) protocol Enumerable not implemented for 1 # (elixir) lib/enum.ex:1: Enumerable.impl_for!/1 # (elixir) lib/enum.ex:146: Enumerable.count/1 # (elixir) lib/enum.ex:467: Enum.count/1
It means that the Integer
does not implement the Enumerable
protocol (what a surprise) and, therefore, we cannot count integers. But the protocol actually can be implemented, and this is easy to achieve.
Implementing a Protocol
Protocols are implemented using the defimpl/3 macro. You specify which protocol to implement and for which type:
defimpl MyProtocol, for: Integer def my_func(arg) do IO.puts(arg) end end
Now you can make your integers countable by partly implementing the Enumerable
protocol:
defimpl Enumerable, for: Integer do def count(_arg) do {:ok, 1} # integers always contain one element end end Enum.count(100) |> IO.puts # => 1
We will discuss the Enumerable
protocol in more detail later in the article and implement its other function as well.
As for the type (passed to the for
), you may specify any built-in type, your own alias or a list of aliases:
defimpl MyProtocol, for: [Integer, List] do end
On top of that, you may say Any
:
defimpl MyProtocol, for: Any def my_func(_) do IO.puts "Not implemented!" end end
This will act like a fallback implementation, and an error will not be raised if the protocol is not implemented for some type. In order for this to work, set the @fallback_to_any
attribute to true
inside your protocol (otherwise the error will still be raised):
defprotocol MyProtocol do @fallback_to_any true def my_func(arg) end
You can now utilize the protocol for any supported type:
MyProtocol.my_func(5) # simply prints out 5 MyProtocol.my_func("test") # prints "Not implemented!"
A Note About Structs
The implementation for a protocol can be nested inside a module. If this module defines a struct, you don't even need to specify for
when calling defimpl
:
defmodule Product do defstruct title: "", price: 0 defimpl MyProtocol do def my_func(%Product{title: title, price: price}) do IO.puts "Title #{title}, price #{price}" end end end
In this example, we define a new struct called Product
and implement our demo protocol. Inside, simply pattern-match the title and price and then output a string.
Remember, however, that an implementation does have to be nested inside a module—it means that you can easily extend any module without accessing its source code.
Example: String.Chars Protocol
Okay, enough with abstract theory: let's have a look at some examples. I am sure you have employed the IO.puts/2 function quite extensively to output debugging info to the console when playing around with Elixir. Surely, we can output various built-in types easily:
IO.puts 5 IO.puts "test" IO.puts :my_atom
But what happens if we try to output our Product
struct created in the previous section? I will place the corresponding code inside the Main
module because otherwise you'll get an error saying that the struct is not defined or accessed in the same scope:
defmodule Product do defstruct title: "", price: 0 end defmodule Main do def run do %Product{title: "Test", price: 5} |> IO.puts end end Main.run
Having run this code, you'll get an error:
(Protocol.UndefinedError) protocol String.Chars not implemented for %Product{price: 5, title: "Test"}
Aha! It means that the puts
function relies on the built-in String.Chars protocol. As long as it is not implemented for our Product
, the error is being raised.
String.Chars
is responsible for converting various structures to binaries, and the only function that you need to implement is to_string/1, as stated by the documentation. Why don't we implement it now?
defmodule Product do defstruct title: "", price: 0 defimpl String.Chars do def to_string(%Product{title: title, price: price}) do "#{title}, $#{price}" end end end
Having this code in place, the program will output the following string:
Test, $5
Which means that everything is working just fine!
Example: Inspect Protocol
Another very common function is IO.inspect/2 to get information about a construct. There is also an inspect/2 function defined inside the Kernel
module—it performs inspection according to the Inspect built-in protocol.
Our Product
struct can be inspected right away, and you'll get some brief information about it:
%Product{title: "Test", price: 5} |> IO.inspect # or: %Product{title: "Test", price: 5} |> inspect |> IO.puts
It will return %Product{price: 5, title: "Test"}
. But, once again, we can easily implement the Inspect
protocol that requires only the inspect/2 function to be coded:
defmodule Product do defstruct title: "", price: 0 defimpl Inspect do def inspect(%Product{title: title, price: price}, _) do "That's a Product struct. It has a title of #{title} and a price of #{price}. Yay!" end end end
The second argument passed to this function is the list of options, but we are not interested in them.
Example: Enumerable Protocol
Now let's see a slightly more complex example while talking about the Enumerable protocol. This protocol is employed by the Enum module, which presents us with such convenient functions as each/2 and count/1 (without it, you would have to stick with plain old recursion).
Enumerable defines three functions that you have to flesh out in order to implement the protocol:
- count/1 returns the enumerable's size.
- member?/2 checks whether the enumerable contains an element.
- reduce/3 applies a function to each element of the enumerable.
Having all those functions in place, you'll get access to all the goodies provided by the Enum
module, which is a really good deal.
As an example, let's create a new struct called Zoo
. It will have a title and a list of animals:
defmodule Zoo do defstruct title: "", animals: [] end
Each animal will also be represented by a struct:
defmodule Animal do defstruct species: "", name: "", age: 0 end
Now let's instantiate a new zoo:
defmodule Main do def run do my_zoo = %Zoo{ title: "Demo Zoo", animals: [ %Animal{species: "tiger", name: "Tigga", age: 5}, %Animal{species: "horse", name: "Amazing", age: 3}, %Animal{species: "deer", name: "Bambi", age: 2} ] } end end Main.run
So we have a "Demo Zoo" with three animals: a tiger, a horse, and a deer. What I'd like to do now is add support for the count/1 function, which will be used like this:
Enum.count(my_zoo) |> IO.inspect
Let's implement this functionality now!
Implementing the Count Function
What do we mean when saying "count my zoo"? It sounds a bit strange, but probably it means counting all the animals that live there, so the implementation of the underlying function will be quite simple:
defmodule Zoo do defstruct title: "", animals: [] defimpl Enumerable do def count(%Zoo{animals: animals}) do {:ok, Enum.count(animals)} end end end
All we do here is rely on the count/1 function while passing a list of animals to it (because this function supports lists out of the box). A very important thing to mention is that the count/1
function must return its result in the form of a tuple {:ok, result}
as dictated by the docs. If you return only a number, an error ** (CaseClauseError) no case clause matching
will be raised.
That's pretty much it. You can now say Enum.count(my_zoo)
inside the Main.run
, and it should return 3
as a result. Good job!
Implementing Member? Function
The next function the protocol defines is the member?/2
. It should return a tuple {:ok, boolean}
as a result that says whether an enumerable (passed as the first argument) contains an element (the second argument).
I want this new function to say whether a particular animal lives in the zoo or not. Therefore, the implementation is pretty simple as well:
defmodule Zoo do defstruct title: "", animals: [] defimpl Enumerable do # ... def member?(%Zoo{title: _, animals: animals}, animal) do {:ok, Enum.member?(animals, animal)} end end end
Once again, note that the function accepts two arguments: an enumerable and an element. Inside we simply rely on the member?/2
function to search for an animal in the list of all animals.
So now we run:
Enum.member?(my_zoo, %Animal{species: "tiger", name: "Tigga", age: 5}) |> IO.inspect
And this should return true
as we indeed have such an animal in the list!
Implementing the Reduce Function
Things get a bit more complex with the reduce/3
function. It accepts the following arguments:
- an enumerable to apply the function to
- an accumulator to store the result
- the actual reducer function to apply
What's interesting is that the accumulator actually contains a tuple with two values: a verb and a value: {verb, value}
. The verb is an atom and may have one of the following three values:
:cont
(continue):halt
(terminate):suspend
(temporarily suspend)
The resulting value returned by the reduce/3
function is also a tuple containing the state and a result. The state is also an atom and may have the following values:
:done
(processing is done, that's the final result):halted
(processing was stopped because the accumulator contained the:halt
verb):suspended
(processing was suspended)
If the processing was suspended, we should return a function representing the current state of the processing.
All these requirements are nicely demonstrated by the implementation of the reduce/3
function for the lists (taken from the docs):
def reduce(_, {:halt, acc}, _fun), do: {:halted, acc} def reduce(list, {:suspend, acc}, fun), do: {:suspended, acc, &reduce(list, &1, fun)} def reduce([], {:cont, acc}, _fun), do: {:done, acc} def reduce([h | t], {:cont, acc}, fun), do: reduce(t, fun.(h, acc), fun)
We can use this code as an example and code our own implementation for the Zoo
struct:
defmodule Zoo do defstruct title: "", animals: [] defimpl Enumerable do def reduce(_, {:halt, acc}, _fun), do: {:halted, acc} def reduce(%Zoo{animals: animals}, {:suspend, acc}, fun) do {:suspended, acc, &reduce(%Zoo{animals: animals}, &1, fun)} end def reduce(%Zoo{animals: []}, {:cont, acc}, _fun), do: {:done, acc} def reduce(%Zoo{animals: [head | tail]}, {:cont, acc}, fun) do reduce(%Zoo{animals: tail}, fun.(head, acc), fun) end end end
In the last function clause, we take the head of the list containing all animals, apply the function to it, and then perform reduce
against the tail. When there are no more animals left (the third clause), we return a tuple with the state of :done
and the final result. The first clause returns a result if the processing was halted. The second clause returns a function if the :suspend
verb was passed.
Now, for example, we can calculate the total age of all our animals easily:
Enum.reduce(my_zoo, 0, fn(animal, total_age) -> animal.age + total_age end) |> IO.puts
Basically, now we have access to all the functions provided by the Enum
module. Let's try to utilize join/2:
Enum.join(my_zoo) |> IO.inspect
However, you'll get an error saying that the String.Chars
protocol is not implemented for the Animal
struct. This is happening because join
tries to convert each element to a string, but cannot do it for the Animal
. Therefore, let's also implement the String.Chars
protocol now:
defmodule Animal do defstruct species: "", name: "", age: 0 defimpl String.Chars do def to_string(%Animal{species: species, name: name, age: age}) do "#{name} (#{species}), aged #{age}" end end end
Now everything should work just fine. Also, you may try to run each/2 and display individual animals:
Enum.each(my_zoo, &(IO.puts(&1)))
Once again, this works because we have implemented two protocols: Enumerable
(for the Zoo
) and String.Chars
(for the Animal
).
Conclusion
In this article, we have discussed how polymorphism is implemented in Elixir using protocols. You have learned how to define and implement protocols, as well as utilize built-in protocols: Enumerable
, Inspect
, and String.Chars
.
As an exercise, you can try to empower our Zoo
module with the Collectable protocol so that the Enum.into/2 function can be properly utilized. This protocol requires the implementation of only one function: into/2, which collects values and returns the result (note that it also has to support the :done
, :halt
and :cont
verbs; the state should not be reported). Share your solution in the comments!
I hope you have enjoyed reading this article. If you have any questions left, don't hesitate to contact me. Thank you for the patience, and see you soon!
Tuesday, August 29, 2017
Monday, August 28, 2017
Set Up a React Environment, Part 1
React is a JavaScript library for building user interfaces (UI). It's maintained and developed by Facebook, and is one of the most popular tools for creating web apps today.
However, it's had a bit of a reputation for not being very user friendly to set up a React app, particularly for beginners. The problem stems from when React first became popular, and the standard method of creating a React app involved complex manual configuration of a whole host of setup files.
A lot of tutorials intended to help beginners get started with React introduced different approaches, and tools, to set up a working app. Even with subtle differences between suggested build methods, confusion was inevitable.
To be able to successfully set up a React app via manual configuration requires a good understanding of multiple different technologies.
This flexibility in setup is actually a great thing. You have complete freedom to choose the specific tools you want to build your React app, and configure them exactly as required.
Once comfortable with these tools, you'll have the confidence to use them to their full potential and create in-depth complex apps. Until then, there still remains an entry barrier to a lot of developers who haven't necessarily got experience with the command-line tools needed to create React apps.
To help alleviate this frustration, this tutorial series focuses on various methods for setting up React apps. We'll start with the most basic approach and then build up to more complex setups. Let's kick things off, though, by clarifying in more detail the types of React setup we'll be covering.
What We'll Be Covering
By the end of this tutorial series, you'll be able to set up React apps in four main ways:
- using an online code editor (CodePen)
- basic manual setup, without Node.js or npm
- using create-react-app
- full manual setup and configuration
The first method demonstrates how to use an online code editor such as CodePen to set up a React app very quickly. Using this method, you'll be coding your first app literally in seconds!
Then, we'll move on to setting up React in a local development environment, starting with directly adding scripts to an HTML file using no build tools whatsoever. The next two setup methods focus on how you'd set up a typical React app in your day-to-day development.
As you'll see, using the create-react-app tool makes it extremely easy to spin up React apps with just a single command! Finally, we cover how to set up a React app via the command line completely from scratch, the old-school way.
Each setup method has its place, and there's no single 'better' approach, just alternatives depending on your needs.
React is a fantastic library to build web apps with, and it's a lot of fun too! Let's take a look now at the tutorial prerequisites to make sure you're up to speed.
Prerequisites
The simplest method for setting up a React app requires nothing more than an internet connection. However, as we progress to more complex setups, we'll be moving towards setting up a React app completely from scratch. Therefore, some knowledge of the following topics is recommended.
Command Line
Windows, macOS, and Linux all provide access to command-line tools. These are used heavily in modern web development for completing complex tasks quickly and efficiently. If you don't have any experience working with the command line to perform operations such as managing files/folders, installing tools, running scripts, and so on, then it would be worth your time at least learning the basics.
Node.js and NPM
If you've been doing web development for any amount of time then chances are you've at least heard of Node.js and npm. Node.js was originally created to run JavaScript on the server but is also now widely used for developing web apps, simplifying and automating common tasks, all under a single environment.
There are literally hundreds of thousands of Node.js modules available, and npm was introduced as a dedicated package manager to help install, organize, and manage all the various modules in your web app. Since npm is bundled with Node.js, all you need to do is install the latest version of Node.js on your system to make it available via your command line.
JavaScript
A reasonable level of JavaScript is required to set up and develop React apps. Otherwise, you'll most certainly struggle at some point to create React apps of any depth or complexity. This includes some features of ES6 such as arrow functions, classes, and modules. I recommend brushing up on your JavaScript skills if necessary before attempting to develop a React app.
React
This tutorial series focuses on setting up React apps rather than developing them, and so we won't be delving too deeply into React specific topics such as components, props, and state. It's a good idea, though, to have some basic knowledge of what these are, so in the next section we'll be covering the basic features of React and exploring how all the parts fit together to form a working app.
Structure of a React App
Before we dive into our first setup method, let's take a quick tour of React itself.
At its core there are three fundamental features of React that most apps are comprised of. These are:
- components
- props
- state
These are the key features you need to master in order to write effective React apps. Once you've reached that stage, you'll be very well prepared to dive much deeper into React and develop more complex apps.
You might be pleasantly surprised to find that React components, props, and state are not that difficult to get your head around. My personal experience was that the React setup process was more difficult than learning React itself!
Components
The building blocks of any React app are components. Think of them as reusable blocks of code which encapsulate markup, behaviour, and styles. They can also be nested inside each other, which makes them highly reusable. For example, you might have a <Book />
component which represents data and UI associated with a single book. You could then also have a <BookIndex />
component which renders out multiple <Book />
components, and so on.
To make constructing components easier, JSX was created to give components an HTML-like structure. If you're familiar with HTML or XML then you'll be right at home using JSX to build components. It's worth noting that you are not required to use JSX at all in React, but it's now become the accepted standard way to define components.
Props
Props allow you to pass information between components. And in React, information can only be passed via props from parent components to child components.
If you choose to use JSX in your component definitions (and I highly recommend you do) then defining props on a component is remarkably similar to adding HTML attributes. This is one of the reasons JSX is so popular! Being able to use HTML-like syntax for React components and props makes it very easy to quickly scaffold out your app.
Let's take a closer look at our <BookIndex />
React component example and see how we can define it with multiple nested child <Book />
components. At the same time, we'll pass down information to each individual <Book />
component from <BookIndex />
.
First, here's the <BookIndex />
component definition:
class BookIndex extends React.Component { render() { return ( <div className="books"> <h2>List of all books</h2> <Book title="Through the Looking-Glass" author="Lewis Carroll" published="1871" /> <Book title="The Time Machine" author="H. G. Wells" published="1895" /> <Book title="A Tale of Two Cities" author="Charles Dickens" published="1859" /> </div> ) } }
Then, inside each <Book />
component, we can access passed-in props like this:
class Book extends React.Component { render() { return ( <div className="book"> <h2>{this.props.title}</h2> <p>Author: {this.props.author}</p> <p>Published: {this.props.published}</p> </div> ) } }
If the above syntax for creating React components looks strange, don't worry—it's pretty straightforward. An ES6 class extends the base component class, and then a (required) render method handles the output of the component.
State
State enables us to keep track of all the data in a React app. We need to be able to update the UI whenever something changes, and state handles this for us. Whenever state is changed, React is smart enough to know which parts of your app need updating. This makes React very fast as it will only update the parts that have changed.
State is typically applied to the top-level component in your React app, so that it's available to every child component to consume state data as necessary.
That's it for our whirlwind tour of React. It's by no means comprehensive, and there's a lot more you need to learn before you can create fully fledged complex apps, but understanding components, props, and state will give you a solid head-start.
Conclusion
In this tutorial, we laid the groundwork for learning how to set up a React environment. The rest of this tutorial series focuses on the specific methods needed to do this. We'll cover setup methods ranging from very simple to more complex methods requiring manual configuration.
In the next tutorial, we'll start by taking a look at using CodePen, an online code editor, to set up a React app in just a few mouse clicks. This is by far the simplest and quickest way to get coding in React!
Friday, August 25, 2017
Kotlin From Scratch: Ranges and Collections
Kotlin is a modern programming language that compiles to Java bytecode. It is free and open source, and promises to make coding for Android even more fun.
In the previous article in this series, you learned about nullability, loops, and conditions in Kotlin. In this tutorial, we'll continue to learn the language by looking at the ranges and collections API in Kotlin.
1. Ranges
A Range in Kotlin is a unique type that defines a start value and an end value. In other words, it is an interval between a start and an end value. Ranges in Kotlin are closed, meaning that the start value and end value are included in the range.
We'll now look at the different ways of creating ranges in Kotlin.
The ..
Operator
val oneToFive = 1..5
In the code above, we have created a closed range. This variable oneToFive
will include the following values: 1, 2, 3, 4, 5. We can loop over it using the for
loop construct.
for (n in oneToFive) { print(n) }
The code above can be shortened to:
for (n in 1..5) { print(n) }
We can also create a range of characters:
val aToZ = "a".."z"
The variable aToZ
will have all the letters in the English alphabet.
The rangeTo()
Function
The ..
operator can be replaced with the rangeTo()
extension function to create a range. For example, we can also do this 1.rangeTo(5)
and it would still have the same results as using the ..
operator as discussed earlier.
val oneToFive: IntRange = 1.rangeTo(5)
The downTo()
Function
This is another extension function that will create a range starting from a given number down to another one.
val fiveToOne = 5.downTo(1)
We can modify the range using the step()
function. This will modify the delta between each element in the range.
val oneToTenStep = 1..10 step 2 // 1, 3, 5, 7, 9
The code above will contain odd numbers between 1 and 10.
The in
Operator
The in
operator is used to ascertain whether a value is present in a given range.
if (5 in 1..10) { print("Yes 5 is in the range") // prints "Yes 5 is in the range" }
In the code above, we checked to see if 5 is in the range 1..10 using the in
operator. We can also do the opposite by using !n
to check if 5 is not in the range.
2. Collections
Collections are used to store groups of related objects in memory. In a collection, we can retrieve, store or organize the objects. Kotlin provides its collections API as a standard library built on top of the Java Collections API. (We'll discuss interfaces in Kotlin in a future post.)
You should note that these interfaces are linked to their implementation at compile time. You can't see the implementation source code in Kotlin, because the collections are actually implemented by the standard Java Collections such as ArrayList
, Maps
, HashMap
, Sets
, HashSet
, List
and so on. To really understand the collections API in Kotlin, you'll need to be familiar with these basic classes and interfaces in Java.
In this section, we'll learn about the List
, Set
and Map
collections in Kotlin. (If you want a refresher on arrays in Kotlin, kindly visit the first tutorial in this series.)
Kotlin's collections give us the ability to achieve a lot with just a little code—unlike in Java, which seems to need a lot of code to achieve a little! Kotlin has two variants of collections: mutable and immutable. A mutable collection provides us with the ability to modify a collection by either adding, removing or replacing an element. Immutable collections cannot be modified and don't have these helper methods.
Note that the addition, removal or replacement of an element in an immutable collection is possible via operator functions (we'll get to that shortly), but these will end up creating a new collection.
The Iterable
Interface
The Kotlin Iterable
interface is at the top of the collections class hierarchy. This interface enables collections to be represented as a sequence of elements (which can be iterated over, naturally).
public interface Iterable<out T> { public abstract operator fun iterator(): Iterator<T> }
The Collection
Interface
The Kotlin Collection
interface extends the Iterable
interface. The Collection
interface is immutable. In other words, you have read-only access to collections. The Set
and List
interfaces (more about these shortly) in Kotlin extend this interface.
Some of the functions and properties available in the Collection
interface are:
size
: this property returns the size of the collection.isEmpty()
: returns true if the collection is empty or false otherwise.contains(element: E)
: returns true if the element specified in the argument is present in the collection.containsAll(element: Collection<E>)
: returns true if the element in the collection passed as argument is present in the collection.
public interface Collection<out E> : Iterable<E> { public val size: Int public fun isEmpty(): Boolean public operator fun contains(element: @UnsafeVariance E): Boolean override fun iterator(): Iterator<E> public fun containsAll(elements: Collection<@UnsafeVariance E>): Boolean }
The MutableIterable
Interface
This interface in Kotlin gives us a specialized mutable iterator from the parent Iterable
interface.
public interface MutableIterable<out T> : Iterable<T> { override fun iterator(): MutableIterator<T> }
The MutableCollection
Interface
The MutableCollection
interface in Kotlin is a specialized interface that enables collections to be mutable. In other words, add and remove operations can be performed on a given collection. This interface extends both the Collection
interface and the MutableIterable
interface already discussed above. The MutableSet
and MutableList
interfaces (we'll get to them shortly) in Kotlin extend this interface. The functions available in this interface—apart from the ones available in its parents—are:
add(element: E)
: adds the element passed as an argument to the collection and returns true if successful or false if the collection does not support duplicates and the element is already present.remove(element: E)
: removes the element passed as an argument from the collection. Returns true if successful or false if it was not present in the collection.addAll(elements: Collection<E>)
: adds all the elements in the collection passed as arguments to the collection. Returns true if successful or false if nothing was added.removeAll(elements: Collection<E>)
: removes all of the elements present in the collection passed as arguments. Returns true if successful or false if nothing was removed.retainAll(elements: Collection<E>)
: retains only the elements present in the collections passed as arguments. Returns true if successful or false if nothing was retained.clear()
: removes all elements from this collection.
public interface MutableCollection<E> : Collection<E>, MutableIterable<E> { override fun iterator(): MutableIterator<E> public fun add(element: E): Boolean public fun remove(element: E): Boolean public fun addAll(elements: Collection<E>): Boolean public fun removeAll(elements: Collection<E>): Boolean public fun retainAll(elements: Collection<E>): Boolean public fun clear(): Unit }
Now you have learned about the top interfaces in the collection class hierarchy in Kotlin, let's now look into how Kotlin handles collections such as Lists, Sets and Maps in the remaining part of the tutorial.
Lists
A list is an ordered collection of elements. This is a popular collection that is widely used. Let's look at different ways of creating a list in Kotlin.
Using the listOf()
Function
In Kotlin, we can create an immutable (read-only) list using the listOf()
helper function from the Kotlin standard library. This function returns a Kotlin List
interface type.
var numbers: List<Int> = listOf(1, 2, 3, 4, 5) var names: List<String> = listOf("Chike", "Nnamdi", "Mgbemena") for (name in names) { println(name) }
Running the code above will print:
Chike Nnamdi Mgbemena
Moreover, we can pass values of different types into the listOf()
as arguments and the result will still work—it will be a list of mixed type.
var listMixedTypes = listOf("Chike", 1, 2.445, 's') // will still compile
Using the emptyList()
Function
This function just creates an empty immutable list and returns a Kotlin List
interface type.
val emptyList: List<String> = emptyList<String>()
Using the listOfNotNull()
Function
This function creates a new immutable list containing only elements that are not null. Notice that this function returns a Kotlin List
interface type also.
val nonNullsList: List<String> = listOfNotNull(2, 45, 2, null, 5, null)
The List
interface from the Kotlin standard library extends only the Collection
interface. In other words, its only parent is the Collection
interface. It overrides all the functions in the parent interface to cater for its special needs and also defines its own functions, such as:
get(index: Int)
: a function operator that returns the element at the specified index.indexOf(element: E)
: returns the index of the first occurrence of the element passed as an argument in the list, or -1 if none is found.lastIndexOf(element: E)
: returns the index of the last occurrence of the element passed as an argument in the list, or -1 if none is found.listIterator()
: returns a list iterator over the elements in the list.subList(fromIndex: Int, toIndex: Int)
: returns a list that contains the portion of the list between the specified start and end indices.
println(names.size) // 3 println(names.get(0)) // "Chike" println(names.indexOf("Mgbemena")) // 2 println(names.contains("Nnamdi")) // 'true'
Using the arrayListOf()
Function
This creates a mutable list and returns a Java ArrayList
type.
val stringList: ArrayList<String> = arrayListOf<String>("Hello", "You", "There")
Using the mutableListOf()
Function
To add, remove or replace values in a list, we need to make the list a mutable one. We can convert an immutable list to a mutable one by calling the function toMutableList()
on the list. However, note that this method will create a new list.
var mutableNames1 = names.toMutableList() mutableNames1.add("Ruth") // now mutable and added "Ruth" to list
To create a mutable list of a certain type from scratch, e.g. String
, we use mutableListOf<String>()
, while for mixed types we can just use the mutableListOf()
function instead.
// a mutable list of a certain type e.g. String val mutableListNames: MutableList<String> = mutableListOf<String>("Josh", "Kene", "Sanya") mutableListNames.add("Mary") mutableListNames.removeAt(1) mutableListNames[0] = "Oluchi" // replaces the element in index 0 with "Oluchi" // a mutable list of mixed types val mutableListMixed = mutableListOf("BMW", "Toyota", 1, 6.76, 'v')
Any of these functions will return a MutableList
Kotlin interface type. This interface extends both the MutableCollection
and List
interfaces discussed earlier in this section. The MutableList
interface adds methods for the retrieval or substitution of an item based upon its position:
set(index: Int, element: E)
: substitutes an element in the list with another element. This returns the element previously at the specified position.add(index: Int, element: E)
: inserts an element at the specified index.removeAt(index: Int)
: gets rid of the element at a particular index.
val mutableListFood: MutableList<String> = mutableListOf<String>("Rice & stew", "Jollof rice", "Eba & Egusi", "Fried rice") mutableListFood.remove("Fried rice") mutableListFood.removeAt(0) mutableListFood.set(0, "Beans") mutableListFood.add(1, "Bread & tea") for (foodName in mutableListFood) { println(foodName) }
Running the code above, we produce the following result:
Beans Bread & tea Eba & Egusi
Note that all these functions create a Java ArrayList
behind the scenes.
Sets
A set is an unordered collection of unique elements. In other words, it can't have any duplicates! Let's look at some of the different ways of creating a set in Kotlin. Each of these creates a different data structure, each of which is optimized for a certain kind of task.
Using the setOf()
Function
To create an immutable (read-only) set in Kotlin, we can use the function setOf()
, which returns a Kotlin Set
interface type.
// creates a immutable set of mixed types val mixedTypesSet = setOf(2, 4.454, "how", "far", 'c') // will compile var intSet: Set<Int> = setOf(1, 3, 4) // only integers types allowed
Note that the Kotlin Set
interface extends only the Kotlin Collection
interface and overrides all the properties available in its parent.
Using the hashSetOf()
Function
Using the hashSetOf()
function creates a Java HashSet
collection which stores elements in a hash table. Because this function returns a Java HashSet
type, we can add, remove, or clear elements in the set. In other words, it's mutable.
val intsHashSet: java.util.HashSet<Int> = hashSetOf(1, 2, 6, 3) intsHashSet.add(5) intsHashSet.remove(1)
Using the sortedSetOf()
Function
Using the sortedSetOf()
function creates a Java TreeSet
collection behind the scenes, which orders elements based on their natural ordering or by a comparator. This set is also mutable.
val intsSortedSet: java.util.TreeSet<Int> = sortedSetOf(4, 1, 7, 2) intsSortedSet.add(6) intsSortedSet.remove(1) intsSortedSet.clear()
Using the linkedSetOf()
Function
This function returns a Java LinkedHashSet
type. This mutable set maintains a linked list of the entries in the set, in the order in which they were inserted.
val intsLinkedHashSet: java.util.LinkedHashSet<Int> = linkedSetOf(5, 2, 7, 2, 5) // 5, 2, 7 intsLinkedHashSet.add(4) intsLinkedHashSet.remove(2) intsLinkedHashSet.clear()
Using the mutableSetOf()
Function
We can use mutableSetOf()
to create a mutable set. This function returns a Kotlin MutableSet
interface type. Behind the scenes, this function simply creates a Java LinkedHashSet
.
// creates a mutable set of int types only val intsMutableSet: MutableSet<Int> = mutableSetOf(3, 5, 6, 2, 0) intsMutableSet.add(8) intsMutableSet.remove(3)
The MutableSet
interface extends both the MutableCollection
and the Set
interfaces.
Maps
Maps associate keys to values. The keys must be unique, but the associated values don't need to be. That way, each key can be used to uniquely identify the associated value, since the map makes sure that you can't have duplicate keys in the collection. Behind the scenes, Kotlin uses the Java Map
collection to implement its map collection type.
Using the mapOf()
Function
To create an immutable or read-only Map
collection in Kotlin, we use the mapOf()
function. We create a map with this function by giving it a list of pairs—the first value is the key, and the second is the value. Calling this function returns a Kotlin Map
interface type.
val callingCodesMap: Map<Int, String> = mapOf(234 to "Nigeria", 1 to "USA", 233 to "Ghana") for ((key, value) in callingCodesMap) { println("$key is the calling code for $value") } print(callingCodesMap[234]) // Nigeria
Running the code above will produce the result:
234 is the calling code for Nigeria 1 is the calling code for USA 233 is the calling code for Ghana
Unlike the List
and Set
interfaces in Kotlin that extend the Collection
interface, the Map
interface doesn't extend any at all. Some of the properties and functions available in this interface are:
size
: this property returns the size of map collection.isEmpty()
: returns true if the map is empty or false otherwise.containsKey(key: K)
: returns true if the map contains the key in the argument.containsValue(value: V)
: returns true if the map maps one or more keys to the value passed as an argument.get(key: K)
: returns the value matching the given key or 'null' if none is found.keys
: this property returns an immutableSet
of all the keys in the map.values
: returns an immutableCollection
of all the values in the map.
Using the mutableMapOf()
Function
The mutableMapOf()
function creates a mutable map for us so that we can add and remove elements in the map. This returns a Kotlin MutableMap
interface type.
val currenciesMutableMap: MutableMap<String, String> = mutableMapOf("Naira" to "Nigeria", "Dollars" to "USA", "Pounds" to "UK") println("Countries are ${currenciesMutableMap.values}") // Countries are [Nigeria, USA, UK] println("Currencies are ${currenciesMutableMap.keys}") // Currencies are [Naira, Dollars, Pounds] currenciesMutableMap.put("Cedi", "Ghana") currenciesMutableMap.remove("Dollars")
The MutableMap
interface doesn't extend the MutableCollection
interface; it's only parent is the Map
interface. It overrides the keys
, entries
and values
properties from the parent interface in order to redefine them. Here are some of the extra functions available in the MutableMap
interface:
put(key: K, value: V)
: inserts the key, value pair into the map. This will return the previous value linked with the key or null if the key was not previously used.remove(key: K)
: removes the key and its linked value from the map.putAll
(from: Map<out K, V>)
: updates the map with all the data from the given map. New keys will be added, and existing keys will be updated with new values.clear()
: removes all elements from the map.
We can get the value for a key using the get()
function. We can also use square bracket notation as a shortcut for get()
.
print(currenciesMutableMap.get("Nigeria")) // will print Naira print(currenciesMutableMap["Nigeria"]) // will print Naira
Using the hashMapOf()
Function
Using this function returns a Java HashMap
type that is mutable. The HashMap
class uses a hash table to implement the Java Map
interface.
val personsHashMap: java.util.HashMap<Int, String> = hashMapOf(1 to "Chike", 2 to "John", 3 to "Emeka") personsHashMap.put(4, "Chuka") personsHashMap.remove(2) print(personsHashMap[1]) // will print Chike
Using the linkedHashMap()
Function
This function returns a Java LinkedHashMap
type that is mutable. The LinkedHashMap
class extends Java HashMap
and maintains a linked list of the entries in the map in the order in which they were inserted.
val postalCodesHashMap: java.util.LinkedHashMap<String, String> = linkedMapOf("NG" to "Nigeria","AU" to "Australia","CA" to "Canada") postalCodesHashMap.put("NA", "Namibia") postalCodesHashMap.remove("AU") postalCodesHashMap.get("CA") // Canada
Using the sortedMapOf()
Function
This function returns a Java SortedMap
type which is mutable. The Java SortedMap
class sees that the entries in the map are maintained in an ascending key order.
val personsSortedMap: java.util.SortedMap<Int, String> = sortedMapOf(2 to "Chike", 1 to "John", 3 to "Emeka") personsSortedMap.put(7, "Adam") personsSortedMap.remove(3)
Remember, implementation of these collection interfaces in Kotlin happens at compile time.
Collections Operation Functions
Kotlin provides us with many useful operator functions called extension functions that can be invoked on collections. Let's take a look at some of the most useful.
The last()
Function
This operator function returns the last element in a collection such as a list or set. We can also supply a predicate to search within a subset of elements.
val stringList: List<String> = listOf("in", "the", "club") print(stringList.last()) // will print "club" // given a predicate print(stringList.last{ it.length == 3}) // will print "the" val intSet: Set<Int> = setOf(3, 5, 6, 6, 6, 3) print(intSet.last()) // will print 6
The first()
Function
This operator function returns the first element when invoked on a collection such as a list or set. If a predicate is given, it then uses the predicate to restrict the operation to a subset of elements.
print(stringList.first()) // will print "in" print(intSet.first()) // will print 3
The max()
Function
Invoking this operator function on a collection such as a list or set returns the largest element, or null if no largest element is found.
val intList: List<Int> = listOf(1, 3, 4) print(intList.max()) // will print 4 print(intSet.max()) // will print 6
The drop()
Function
Calling this operator function returns a new list or set containing all elements except the first n elements.
print(stringList.drop(2)) // will print "club"
The plus()
Function
This operator function returns a collection containing all elements of the original and then the given element if it isn't already in the collection. This will end up creating a new list instead of modifying the list.
print(intList.plus(6)) // will print [1, 3, 4, 6]
The minus()
Function
The opposite of the plus()
function is the minus()
function. It returns a collection containing all elements of the original set except the given element. This also ends up creating a new list instead of altering the list.
print(intList.minus(3)) // will print [1, 4]
The average()
Function
Calling this operator function will return an average number of elements in the collection.
print(intList.average()) // will print 2.6666666666666665
Most of these extension functions are available in the Kotlin collections standard library. You are advised to check out the documentation to learn about the others.
Conclusion
In this tutorial, you learned about the range and collections API in the Kotlin programming language. In the next tutorial in the Kotlin From Scratch series, you'll be introduced to functions in Kotlin. See you soon!
To learn more about the Kotlin language, I recommend visiting the Kotlin documentation. Or check out some of our other Android app development posts here on Envato Tuts!
-
Android SDKIntroduction to Android Architecture ComponentsTin Megali
-
Machine LearningCreate Chatbots on Android With IBM WatsonAshraff Hathibelagal
-
Android SDKJava vs. Kotlin: Should You Be Using Kotlin for Android Development?Jessica Thornsby
-
Android SDKQuick Tip: Write Cleaner Code With Kotlin SAM ConversionsAshraff Hathibelagal
-
Android SDKAndroid O: Phone Number Verification With SMS TokensChike Mgbemena
How CodeIgniter's Hook System Works
As a CodeIgniter developer, sometimes you end up in a situation that requires you to alter the core of the framework or the execution flow to fulfill your custom requirements. Of course, it's never recommended to modify the core files as it makes the upgrade process cumbersome. Luckily, the CodeIgniter framework comes with the hooks system, which allows you deal with this scenario.
In this article, we'll start with an introduction to the hooks system in the CodeIgniter framework. Then, we'll discuss the different types of hooks available. And finally, we'll grab this opportunity to explore the creation of custom hooks.
Hooks: A System to Override the Core Framework
Let's have a quick look at what the official CodeIgniter documentation says about the hooks system:
CodeIgniter’s Hooks feature provides a means to tap into and modify the inner workings of the framework without hacking the core files.
Sounds pretty self-explanatory, doesn't it? In your day-to-day application development, if you ever find yourself tempted to modify the core CodeIgniter files, you should first consider the hooks system to see if it fulfills your requirements.
Let's assume that you want to build a custom performance benchmark system to monitor the application execution. You realize that the core files need to be modified in order to achieve the desired output. In that case, you could use the pre_system
and the post_system
hooks to get into the execution flow and collect the statistics as needed.
If you're aware of the event observer pattern, the concept is similar in that you listen for the system generated events, and the corresponding observer code gets executed when the observed event is triggered.
So that was a basic introduction to the hooks system in CodeIgniter. In the next section, we'll have a close look at the different hooks available for you to plug into the system.
Go Through the Different Hooks
The CodeIgniter hook system provides different hook points that you can use while implementing your custom hooks. The hook point is basically a certain state in the request execution workflow at a given time.
For example, when you implement the pre_system
hook, you know that you’re at the very beginning of the bootstrapping phase. On the other hand, if you’ve chosen the post_system
hook, you can be sure that the execution is completed and the response is already sent to the client.
In this section, we’ll go through the different hook points that are provisioned by the CodeIgniter hook system.
System Hooks
The pre_system
and the post_system
hooks fall under this category as the former one is called very early during the bootstrapping phase while the latter one is called after the page execution is completed.
I can think of a few use cases that could be achieved with system hooks:
- Benchmark
- Logging
- Rule-based redirection
- And more
Controller Hooks
There are three hooks that fall under this category, so let's go through each of them.
Pre Controller Hook
The pre_controller
hook is called just prior to the controller class being instantiated. So, if you would like to do any further checks before the controller gets called, this is the hook you're looking for.
Post Controller Constructor Hook
As the name suggests, the post_controller_constructor
hook is called immediately after the controller object is instantiated and prior to the actual method call.
At this point, you're sure that the controller is instantiated and the method is going to be called soon, so you could load any controller specific libraries here, or you could implement the controller-specific custom validation as well.
Post Controller Hook
The post_controller
hook is called after the execution of the controller method. So the stuff that you want to execute after execution of the controller should be implemented with this hook.
So that was the story of the controller specific hooks.
Overrides Hooks
Display Override Hook
According to the CodeIgniter documentation, the display_override
hook overrides the core _display
method. The core _display
method is used to send the output to the client, and thus by using the display_override
hook you could alter the way the output is sent to the user.
In fact, we'll explore this hook in detail as we move on to the next section, in which we'll discuss how to create a custom hook.
Cache Override Hook
The cache_override
hook overrides the core _display_cache
method of the Output
class. The _display_cache
method is responsible for serving the cached output, so you could use this hook should you wish to serve the page output from the different cached location just in case you've implemented a different caching mechanism.
That ends the story of different hook points in the CodeIgniter hook system. In the next section, we'll see how exactly you could take an advantage of the hook system by implementing a real-world example.
How to Create a Custom Hook
I'm sure that you've had enough theory so far, so let's get back to some practical development! In this section, we'll create a custom hook to demonstrate the concepts discussed so far in this article.
In our case, we'll use the display_override
hook that'll be responsible for the token replacement. To be more precise, we'll replace all the occurrences of [DATETIME]
with the current date. Of course, that sounds like a pretty simple use case, but you could easily extend it to be more specific as per your requirements.
By default, the hook system is disabled in the core framework, so the first thing you need to do is to enable the hook system.
Go ahead and open the configuration file application/config/config.php
.
Look for the following snippet and turn it on by changing FALSE
to TRUE
.
<?php /* |-------------------------------------------------------------------------- | Enable/Disable System Hooks |-------------------------------------------------------------------------- | | If you would like to use the 'hooks' feature you must enable it by | setting this variable to TRUE (boolean). See the user guide for details. | */ $config['enable_hooks'] = FALSE;
Now, we're ready to define our hooks. In fact, CodeIgniter already comes with the file application/config/hooks.php
that you could use should you wish to define hooks.
By default, the hooks.php
file is empty, so let's add our custom hook code to make it more meaningful.
<?php defined('BASEPATH') OR exit('No direct script access allowed'); $hook['display_override'] = array( 'class' => 'ReplaceToken', 'function' => 'replacePlaceholderCode', 'filename' => 'ReplaceToken.php', 'filepath' => 'hooks' );
The syntax of defining a custom hook is pretty simple. It's the $hook
array that holds all the hooks that need to be executed.
The key of each array entry is the name of the hook itself you're defining. When you're defining a hook, you're telling the system to execute a certain piece of code when something happens. That's exactly what needs to be supplied as a value of any hook. Let's go through each key quickly.
- The
class
key holds the name of a class that holds the code that needs to be executed. - The
function
key holds the name of the method that'll be called upon the hook execution. - The
filename
key points to the file that defines the complete hook code. - The
filepath
defines the directory path of the file declared under thefilename
key, and it's relative to theapplication
directory. Generally, it's set tohooks
, thus resulting in anapplication/hooks
structure. Of course, there's nothing stopping you from defining a completely different path if you wish to do so.
As a side note, if you don't want to create a class file, you could also supply a closure function that'll be executed when the hook is triggered.
In our case, we'll create a file ReplaceToken.php
and according to the hook definition it must be placed under the application/hooks
directory.
Go ahead and create a file application/hooks/ReplaceToken.php
with the following contents.
<?php class ReplaceToken { public function replacePlaceholderCode() { // load the instance $this->CI =& get_instance(); // get the actual output $contents = $this->CI->output->get_output(); // replace the tokens $this->CI->load->helper('date'); $contents = str_replace("[DATETIME]", standard_date(), $contents); // set the output echo $contents; return; } }
The object of our hook is to replace the [DATETIME]
placeholder with the actual date before the output of any page in our application is sent to the client.
As we've discussed earlier, the output of the page is already built by the time the display_override
hook is called. So the first thing that we would like to do is to fetch the output that's ready to be sent to the user.
// load the instance $this->CI =& get_instance(); // get the actual output $contents = $this->CI->output->get_output();
The get_instance
method is used to instantiate the application instance, and it's assigned to $this->CI
. Next, we use the get_output
method of the Output
class to fetch the response contents.
The rest is pretty simple. The [DATETIME]
placeholder needs to be replaced with the actual date. To make things easier, the date
helper is used to carry out the desired operation, and we're almost done as far as our hook logic is concerned.
// replace the tokens $this->CI->load->helper('date'); $contents = str_replace("[DATETIME]", standard_date(), $contents);
Finally, you need to echo the output as the display_override
overrides the _display
method that is used to send the output to the client. So we need to do it ourselves in this case; otherwise, it would have been handled by the core _display
method.
// set the output echo $contents; return;
In fact, that ends the story of our custom hook!
Now, let's go ahead and make a new CodeIgniter page so that we can test our custom hook. Create a controller file application/controllers/TokenExample.php
with the following contents.
<?php defined('BASEPATH') OR exit('No direct script access allowed'); class TokenExample extends CI_Controller { public function index() { $this->load->view('token_content'); } }
And here's how the associated view file application/views/token_content.php
should look.
Today's date: [DATETIME]
And that's pretty much it. Point your browser to http://your-code-igniter-site-url/TokenExample/index and you should see the expected output!
So that's the hook system at your disposal should you wish to get into the typical workflow of the CodeIgniter application. I hope that you've enjoyed the article and that it helps you in your day-to-day CodeIgniter application development.
Conclusion
Today, we went through one of the exciting built-in CodeIgniter feature—hooks. Hooks allow you to intervene in the typical request execution workflow of your CodeIgniter application.
At the beginning of the article, we discussed the basic concept of Hooks in CodeIgniter, and then we discussed the different hooks available in the system. Finally, in the last section we explored how to create a custom hook and its inner workings.
Don't hesitate to express your thoughts using the feed below. Also, if you want me to come up with any specific topics, please just let me know.
Thursday, August 24, 2017
What Are Android Intents?
Intents are a fundamental topic for Android developers. It is impossible to build Android applications without coming in contact with intents. In this tutorial, I'll teach you about intents from A to Z.
What Are Intents?
In a football match, teammates pass the ball around the field with the aim of sending it into the goal of their opponent. The ball is passed from the team's goalkeeper to their defenders. Next, it finds its way to the midfielders, and if things work out as planned, one of the strikers sends it into the net of the opponent. That's assuming the goalkeeper of the other side was not able to keep it away!
In Android, the ability to send messages around is made possible by the Intent
object. With the help of intents, Android components can request functionality from other Android components. When you open up the Instagram app on your phone and use it to take a picture, you just made use of an intent. Intents also help communicate between parts of an app; the movement from one screen (activity) to another is made possible by intents.
Look at it this way: all components (applications and screens) of the Android device are isolated. The only way they communicate with each other is through intents.
Starting Activities With Intents
As mentioned earlier, you can use intents to start different components: activities, services, and broadcast receivers.
To start an activity, you will make use of the method startActivity
(intent)
.
Here is a code snippet that demonstrates how to start another activity from an intent.
Intent numbersIntent = new Intent(MainActivity.this, NumbersActivity.class); startActivity(numbersIntent);
First, we create a new Intent
object and pass it the NumbersActivity
class. Then we start a new activity using that intent.
Types of Intents
Android supports two types of intents: explicit and implicit. When an application defines its target component in an intent, that it is an explicit intent. When the application does not name a target component, that it is an implicit intent.
Explicit Intent Example
The code snippet of code above is an example of explicit intent. Have a look at it again.
Intent numbersIntent = new Intent(MainActivity.this, NumbersActivity.class); startActivity(numbersIntent);
Here, NumbersActivity
is the target component from our MainActivity
. This means that NumbersActivity
is the defined component that will be called by the Android system. It is important to note (as in the example above), that explicit intents are typically used within an application, because that gives the developer the most control over which class will be launched.
Implicit Intent Example
Here's an implicit intent:
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.tutsplus.com")); startActivity(intent);
If you have the above code in your codebase, your application can start a browser component for a certain URL via an intent. But how does the Android system identify the components which can react to a certain intent?
A component can be registered via an intent filter for a specific action. Intent filters can be registered for components statically in the AndroidManifest.xml. Here is an example that registers a component as a web viewer:
<activity android:name=".BrowserActivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="http"/> </intent-filter> </activity>
Using Intents in an App
Let's write some code to see how it works out. In this section, you'll build a tiny app to try out both styles of intent. The app will have a little form to enter a first name and last name. When the Submit button is clicked, both of the entered values will be passed to another activity. There will also be a button to launch a browser of your choice. The chosen browser will open up http://ift.tt/1cWAN18.
Open up Android Studio and generate your MainActivity
. You can set the name of the package to com.tutsplus.code.android.droidintent.
Your MainActivity
will start with some imports and the class declaration:
package com.tutsplus.code.android.droidintent; import android.content.Intent; import android.net.Uri; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; public class MainActivity extends AppCompatActivity { }
Then you'll override the onCreate()
method to initialize the activity with any saved state and the activity layout (we'll create this later).
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // button handlers go here }
Next you'll get references to each of the buttons defined in the layout and attach a click listener to each of them.
final Button submitButton = (Button) findViewById(R.id.submit_button); submitButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { EditText firstName = (EditText) findViewById(R.id.first_name_text); EditText lastName = (EditText) findViewById(R.id.last_name_text); String firstNameString = firstName.getText().toString(); String lastNameString = lastName.getText().toString(); Intent submitIntent = new Intent(MainActivity.this, ShowActivity.class); submitIntent.putExtra("firstNameString", firstNameString); submitIntent.putExtra("lastNameString", lastNameString); startActivity(submitIntent); } });
For the Submit button, you set an OnClickListener
to trigger an action whenever the button is clicked. When a click occurs, we grab the first and last name from the view, and send them to the next activity: ShowActivity
. The target component is explicitly defined in the intent, making this an example of explicit intent.
final Button browserButton = (Button) findViewById(R.id.browser_button); browserButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://ift.tt/1pw9ugf")); startActivity(intent); } });
For the browser button, the OnClickListener
will create a new intent to launch any application that matches the filter: an ACTION_VIEW
which should handle a web URL. In other words, it launches a web browser. If you have more than one browser application installed on your device, you will be asked to select one to perform the action of opening the web site. This is an example of an implicit intent.
MainActivity
Layout
The layout for MainActivity
will be very simple for the purpose of this tutorial.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://ift.tt/nIICcg" xmlns:app="http://ift.tt/GEGVYd" xmlns:tools="http://ift.tt/LrGmb4" android:layout_width="match_parent" android:orientation="vertical" android:layout_margin="16dp" android:layout_height="match_parent" tools:context="com.tutsplus.code.android.droidintent.MainActivity"> <TextView android:id="@+id/first_name_view" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Enter first name" /> <EditText android:id="@+id/first_name_text" android:padding="8dp" android:layout_width="200dp" android:layout_height="wrap_content" /> <TextView android:id="@+id/last_name_view" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Enter last name" /> <EditText android:id="@+id/last_name_text" android:layout_height="wrap_content" android:layout_width="200dp" android:padding="8dp" /> <Button android:id="@+id/submit_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Submit"/> <Button android:id="@+id/browser_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="50dp" android:layout_marginLeft="100dp" android:text="Open Browser"/> </LinearLayout>
Here you have two TextView
and two EditText
indicating First Name and Last Name respectively. There is also a button to submit the names, and another to launch your browser.
Create the ShowActivity
To complete our app, we need to create an activity to handle the explicit intent defined above. Create a new activity called ShowActivity
. This is the activity where the result of entering the first name and last name will be shown. Here is what it should look like:
package com.tutsplus.code.android.droidintent; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.widget.TextView; public class ShowActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_show); Bundle extras = getIntent().getExtras(); String inputFirstName = extras.getString("firstNameString"); String inputLastName = extras.getString("lastNameString"); TextView showFirstName = (TextView) findViewById(R.id.show_first_name); TextView showLastName = (TextView) findViewById(R.id.show_last_name); showFirstName.setText(inputFirstName); showLastName.setText(inputLastName); } }
In this activity, you start by getting the strings passed from the MainActivity
. You can get a reference to the intent that triggered the launch of this activity with the getIntent()
function. Then you can access the strings that were passed to it using getExtras().getString()
. Finally, after getting the TextView instances from the layout, you display the values you obtained.
ShowActivity Layout
The layout for this activity is simple:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://ift.tt/nIICcg" xmlns:app="http://ift.tt/GEGVYd" xmlns:tools="http://ift.tt/LrGmb4" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="16dp" android:orientation="vertical" tools:context="com.tutsplus.code.android.droidintent.ShowActivity"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="First Name:"/> <TextView android:id="@+id/show_first_name" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Last Name:"/> <TextView android:id="@+id/show_last_name" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout>
Testing the App
Now you can build your app and try it out on your Android device!
Passing Data Using Bundles
You can also make use of Bundles when passing data via intents.
The Bundle
class allows you store complex data and supports data types such as strings, chars, boolean, integer and so on. Here is an example of how part of MainActivity.java would look if you used Bundle
.
// Creating Bundle object Bundle b = new Bundle(); // Storing data into bundle b.putString("firstNameString", firstNameString); b.putString("lastNameString", lastNameString); // Creating Intent object Intent submitIntent = new Intent(MainActivity.this, ShowActivity.class); // Storing bundle object into intent submitIntent.putExtra(b); startActivity(submitIntent);
Conclusion
In this tutorial, we got a brief introduction to using intents to create activities in Android. We looked at the difference between explicit and implicit intents, and coded a simple example that used each type.
You can read more about intents in the Android documentation. Understanding how they work is very important. As you build more apps, you will encounter lots of different kinds of Intents and ways of using them.
And in the meantime, check out some of our other posts on Android app development!
-
Android SDKIntroduction to Android Architecture ComponentsTin Megali
-
JavaAndroid Design Patterns: The Observer PatternChike Mgbemena
-
AndroidAndroid From Scratch: Building Your First Android ApplicationGianluca Segato
Wednesday, August 23, 2017
Context-Based Programming in Go
Go programs that run multiple concurrent computations in goroutines need to manage their lifetime. Runaway goroutines can get into infinite loops, deadlock other waiting goroutines, or just take too long. Ideally, you should be able to cancel goroutines or have them time out after a fashion.
Enter content-based programming. Go 1.7 introduced the context package, which provides exactly those capabilities as well as the ability to associate arbitrary values with a context that travels with the execution of requests and allows out-of-band communication and information passing.
In this tutorial, you'll learn the ins and outs of contexts in Go, when and how to use them, and how to avoid abusing them.
Who Needs a Context?
The context is a very useful abstraction. It allows you to encapsulate information that is not relevant to the core computation like request id, authorization token, and timeout. There are several benefits of this encapsulation:
- It separates the core computation parameters from the operational parameters.
- It codifies common operational aspects and how to communicate them across boundaries.
- It provides a standard mechanism to add out-of-band information without changing signatures.
The Context Interface
Here is the entire Context interface:
type Context interface { Deadline() (deadline time.Time, ok bool) Done() <-chan struct{} Err() error Value(key interface{}) interface{}
The following sections explain the purpose of each method.
The Deadline() Method
Deadline returns the time when work done on behalf of this context should be canceled. Deadline returns ok==false
when no deadline is set. Successive calls to Deadline return the same results.
The Done() Method
Done() returns a channel that's closed when work done on behalf of this context should be canceled. Done may return nil if this context can never be canceled. Successive calls to Done() return the same value.
- The context.WithCancel() function arranges for the Done channel to be closed when cancel is called.
- The context.WithDeadline() function arranges for the Done channel to be closed when the deadline expires.
- The context.WithTimeout() function arranges for the Done channel to be closed when the timeout elapses.
Done can be used in select statements:
// Stream generates values with DoSomething and sends them // to out until DoSomething returns an error or ctx.Done is // closed. func Stream(ctx context.Context, out chan<- Value) error { for { v, err := DoSomething(ctx) if err != nil { return err } select { case <-ctx.Done(): return ctx.Err() case out <- v: } } }
See this article from the Go blog for more examples of how to use a Done channel for cancelation.
The Err() Method
Err() returns nil as long as the Done channel is open. It returns Canceled
if the context was canceled or DeadlineExceeded
if the context's deadline passed or the timeout expired. After Done is closed, successive calls to Err() return the same value. Here are the definitions:
// Canceled is the error returned by Context.Err when the // context is canceled. var Canceled = errors.New("context canceled") // DeadlineExceeded is the error returned by Context.Err // when the context's deadline passes. var DeadlineExceeded error = deadlineExceededError{}
The Value() Method
Value returns the value associated with this context for a key, or nil if no value is associated with the key. Successive calls to Value with the same key return the same result.
Use context values only for request-scoped data that transitions processes and API boundaries, not for passing optional parameters to functions.
A key identifies a specific value in a Context. Functions that wish to store values in Context typically allocate a key in a global variable and use that key as the argument to context.WithValue() and Context.Value(). A key can be any type that supports equality.
Context Scope
Contexts have scopes. You can derive scopes from other scopes, and the parent scope has no access to values in derived scopes, but derived scopes have access to the parent's scopes values.
The contexts form a hierarchy. You start with context.Background() or context.TODO(). Whenever you call WithCancel(), WithDeadline(), or WithTimeout(), you create a derived context and receive a cancel func. The important thing is that when a parent context is cancelled or expired, all its derived contexts.
You should use context.Background() in the main() function, init() functions, and tests. You should use context.TODO() if you're not sure what context to use.
Note that Background and TODO are not cancellable.
Deadlines, Timeouts, and Cancellations
As you recall, WithDeadline() and WithTimeout() return contexts that get cancelled automatically, while WithCancel() returns a context and must be cancelled explicitly. All of them return a cancel function, so even if the timeout/deadline didn't expire yet, you may still cancel any derived context.
Let's examine an example. First, here is the contextDemo() function with a name and a context. It runs in an infinite loop, printing to the console its name and its context's deadline if any. Then it just sleeps for a second.
package main import ( "fmt" "context" "time" ) func contextDemo(name string, ctx context.Context) { for { if ok { fmt.Println(name, "will expire at:", deadline) } else { fmt.Println(name, "has no deadline") } time.Sleep(time.Second) } }
The main function creates three contexts:
- timeoutContext with a three-second timeout
- a non-expiring cancelContext
- deadlineContext, which is derived from cancelContext, with a deadline four hours from now
Then, it launches the contextDemo function as three goroutines. All run concurrently and print their message every second.
The main function then waits for the goroutine with the timeoutCancel to be cancelled by reading from its Done() channel (will block until it's closed). Once the timeout expires after three seconds, main() calls the cancelFunc() that cancels the goroutine with the cancelContext as well as the last goroutine with the derived four hours deadline context.
func main() { timeout := 3 * time.Second deadline := time.Now().Add(4 * time.Hour) timeOutContext, _ := context.WithTimeout( context.Background(), timeout) cancelContext, cancelFunc := context.WithCancel( context.Background()) deadlineContext, _ := context.WithDeadline( cancelContext, deadline) go contextDemo("[timeoutContext]", timeOutContext) go contextDemo("[cancelContext]", cancelContext) go contextDemo("[deadlineContext]", deadlineContext) // Wait for the timeout to expire <- timeOutContext.Done() // This will cancel the deadline context as well as its // child - the cancelContext fmt.Println("Cancelling the cancel context...") cancelFunc() <- cancelContext.Done() fmt.Println("The cancel context has been cancelled...") // Wait for both contexts to be cancelled <- deadlineContext.Done() fmt.Println("The deadline context has been cancelled...") }
Here is the output:
[cancelContext] has no deadline [deadlineContext] will expire at: 2017-07-29 09:06:02.34260363 [timeoutContext] will expire at: 2017-07-29 05:06:05.342603759 [cancelContext] has no deadline [timeoutContext] will expire at: 2017-07-29 05:06:05.342603759 [deadlineContext] will expire at: 2017-07-29 09:06:02.34260363 [cancelContext] has no deadline [timeoutContext] will expire at: 2017-07-29 05:06:05.342603759 [deadlineContext] will expire at: 2017-07-29 09:06:02.34260363 Cancelling the cancel context... The cancel context has been cancelled... The deadline context has been cancelled...
Passing Values in the Context
You can attach values to a context using the WithValue() function. Note that the original context is returned, not a derived context. You can read the values from the context using the Value() method. Let's modify our demo function to get its name from the context instead of passing it as a parameter:
func contextDemo(ctx context.Context) { deadline, ok := ctx.Deadline() name := ctx.Value("name") for { if ok { fmt.Println(name, "will expire at:", deadline) } else { fmt.Println(name, "has no deadline") } time.Sleep(time.Second) } }
And let's modify the main function to attach the name via WithValue():
go contextDemo(context.WithValue( timeOutContext, "name", "[timeoutContext]")) go contextDemo(context.WithValue( cancelContext, "name", "[cancelContext]")) go contextDemo(context.WithValue( deadlineContext, "name", "[deadlineContext]"))
The output remains the same. See the best practices section for some guidelines about using context values appropriately.
Best Practices
Several best practices have emerged around context values:
- Avoid passing function arguments in context values.
- Functions that wish to store values in Context typically allocate a key in a global variable.
- Packages should define keys as an unexported type to avoid collisions.
- Packages that define a Context key should provide type-safe accessors for the values stored using that key.
The HTTP Request Context
One of the most useful use cases for contexts is passing information along with an HTTP request. That information may include a request id, authentication credentials, and more. In Go 1.7, the standard net/http package took advantage of the context package getting "standardized" and added context support directly to the request object:
func (r *Request) Context() context.Context func (r *Request) WithContext(ctx context.Context) *Request
Now it's possible to attach a request id from the headers all the way to the final handler in a standard way. The WithRequestID() handler function extracts a request ID from the "X-Request-ID" header and generates a new context with the request id from an existing context that it uses. It then passes it to the next handler in the chain. The GetRequestID() public function provides access to handlers that may be defined in other packages.
const requestIDKey int = 0 func WithRequestID(next http.Handler) http.Handler { return http.HandlerFunc( func(rw http.ResponseWriter, req *http.Request) { // Extract request ID from request header reqID := req.Header.Get("X-Request-ID") // Create new context from request context with // the request ID ctx := context.WithValue( req.Context(), requestIDKey, reqID) // Create new request with the new context req = req.WithContext(ctx) // Let the next handler in the chain take over. next.ServeHTTP(rw, req) } ) } func GetRequestID(ctx context.Context) string { ctx.Value(requestIDKey).(string) } func Handle(rw http.ResponseWriter, req *http.Request) { reqID := GetRequestID(req.Context()) ... } func main() { handler := WithRequestID(http.HandlerFunc(Handle)) http.ListenAndServe("/", handler) }
Conclusion
Context-based programming provides a standard and well-supported way to address two common problems: managing the lifetime of goroutines and passing out-of-band information across a chain of functions.
Follow the best practices and use contexts in the right context (see what I did there?) and your code will improve considerably.