Practical network for Android Developers (part 4)

Dinorah Tovar
ProAndroidDev
Published in
9 min readDec 2, 2020

--

Easy data layer for every Application

Here is the list of the blogs in this series:

Practical network for Android Developers

This is the fourth part of this series “Practical Network for Android Developers” today we are gonna discuss what is redundancy, concurrency pools, some parts of Coroutines, and the performance in OkHttp.

This part is incredibly big and I will create a second part outside this serial just to address any problem of Performance from coroutines to a network request, whatsoever, feel free to ask any question below.

Redundancy

Network redundancy is the art of adding additional instances of the devices and lines of communication, to make sure we are always available and decrease the risk of failure and reduce times.
Imagine you have one data center in the US and one user in Europe, if the user gets inside your application, we need to have a secondary data center to make sure the request is not gonna take us a long time, redundancy is the mechanism of keeping multiple data center in synchronization.
There's a couple of main architectures in the management of redundancy, and this may not be the job of a Mobile engineer but is important for handle errors

High Availability
Is a software system architecture, that uses clusters of servers that monitor one another and have failover protocols in place. If something goes wrong with one server, the backup servers take over and restart applications that were running on the failed server. The downfall here is that if they can not boot again, you are gonna end up with tons of downtimes, also, you will end up with some downtime.

Fault Tolerance
Is a hardware redundancy architecture, that mirrors applications across two or more identical systems that run in tandem. If anything goes wrong with the primary system, the secondary backup system will take over with no loss of service, this specific architecture works in the case of having any amount of downtime is unacceptable, but usually is never zero but is really close.

Everything can go wrong in here, having a redundancy plan is an important key as having a strategy that reviews existing infrastructure. After all, even the most extensive redundancies architecture won’t work at all if we have something that causes interference in the performance in the servers or something as human as losing Internet connection.
Data is the king in every app, so this data should be backed up regularly so we don’t end up with echoes in different data centers, a good data strategy should address the mapping of the best places to replicate and store data so it can be easily accessed in the event that other redundant systems fail and the main network goes down.

Usually, DevOps engineers are in charge of data centers, they conduct tests to make sure the integrity of their systems and redundant networks are alright. They can test different connections by physically disconnecting hardware to make sure failover occurs as anticipated, this can save the life of every application, and understanding it, can help to troubleshoot this before anyone else notices, as a mobile engineer I have a personal policy that I should check daily if everything is going fine with the app I'm building, cause our work as a mobile engineers does not end up when we merge our codebase, it ends when our users, make use of our product with benefits.

Concurrency

In Android, concurrency (at least for networks) depends on two parts, data transmission, and threading.
For the first one, we talk about it in the second part of this serial, specifically about the Frames that were introduced on HTTP/2 as a unit of transmission in the layer protocol, and consists of a header followed by a packet. Each frame is a series of bits generally composed of frame synchronization bits, the payload, and a frame check sequence.
For the second one, we refer to the suspendable computation API which means you can have two options, blocking and non-blocking threads.

Threads
In Mobile applications, there are tons of threads, for files, for network connection, for heavy operation, even for UI. But for this special part of this serial, the most important are two.

For the network layer, we need to make sure the request to a blocking or non-blocking moment happens on the IO thread, for example, if the network request to an API fails we will be unable to deliver the failure to the app to do some handle of the error.
If the application makes some request to a server, we need to keep the thread alive for an answer, even if is a failure, we need to hold that thread until either the bytes arrive, the stream is closed, or a timeout pass, if the thread is dead, we can not control anything of the frames that have arrived, we are in a death valley, if the thread is death also your answer is, we need to keep alive the caller thread and this is known as the Application/Writer thread.

This does not happen with a socket, Sockets are permanent, when you get continuous data from the server, the thread that will handle the response may not be alive, but the server will be sending data and the application will be reading and writing, and probably will be off doing presentation-layer things and the thread that will receive data may be not available and we need to buffer the data, once the views on the application are ready for dispatch we get the incoming data and the application layer populates the view. So we have a dedicated thread for every socket that just reads frames and dispatches them, this is called Reader thread, they are complex, cause we need to make sure to not have a deadlock connection, if we do this we can hold up the entire operation, even the connection.

Pools
In databases and network request we can have multiple connections, this set is known as connection pools, they handle the creation and handle the interactions of the connections, usually, this is an expensive job, for example in OkHttp, the library make sure to reuse the existing connection to avoid latency, depending on the HTTP version we may have some differences on the latency use of the connection.

The main job of an OkHttpClient is to know all references to all open connections, cause they will be reuse to handle the following requests.

Coroutines
Concurrency in Android means handle threads for operations, without blocking the user actions and make delimitations for the saturation the user is seeing it, let’s revisit this diagram.

For example, our user will make a Click or a Scroll and we need to make a push data from the server, in this space-time, the UI Thread should be available for the user, and the push of the data should happen in a Secondary Thread that can wait for the launch and the response of the data, once we get the response, we can push the update to the UI Thread and the user could keep interacting with the application

This process of having a Secondary Thread can be handle in multiple ways, using for example RxJava that help us for composing asynchronous and event-based programs by using observables, but today we are gonna talk about Coroutines that is a concurrency design pattern that you can use on Android to simplify code that executes asynchronously.

Mostly a coroutine is a light-weight thread. They are launched with a specific context builder of some type of Scope. In the code above we are launching a new coroutine in the GlobalScope, meaning that the lifetime of the new coroutine is limited only by the lifetime of the whole application.

On Android you can have:

  • CoroutineScope Space for manages one or more related coroutines, this Scope should be canceled once the coroutine is no longer in use, we can not keep it alive, this also applies for RxJava, the process should be canceled if we don’t we may have huge problems of memory leaks.
  • launch is a function that creates a coroutine and dispatches the execution of its function body to the corresponding dispatcher.
  • Dispatchers.IO indicates that this coroutine should be executed on a thread reserved for IO operations, there are more dispatchers, like Main, Default, or Undefined, all of them for multiple different things, from using CPU to Run Test.

We are not going over the process to add coroutines to your Android application, whatsoever if you have any question about it please ask them below this post, but they pretty much follow this suspendable pattern

  • launch we already said some things about launch, but is also important to know that this function will be the main path where the process begins
  • suspend is a keyword for a suspendable function that can be a network request, this network request will go to a server and the coroutine will await the response
  • Response<T> the response of the request will arrive and the result can be a Success or an Error (SocketTimeOut, IOException, etc…)
  • Deliver we need to do something with the result that may or may not be related to the UI, but this pretty much ends the process of the coroutine.

Performance

Performance is everything on Android, even has to do with the JVM, minor things like not dismissing the Coroutines after using it can give us troubles of memory, CPU, and only the process of creating an OkHttpClient can give us a huge millisecond of retention.

We need to create our OkHttpClient and officially we need to have only ONE ☝ client on the lifetime of the whole application, cause every time we create a new instance of it, we create a new connection pool, cache, and interceptors, this will lead us to inefficient use of memory, resources and probably will lead to a huge amount of wasted memory in the app.
To keep available we may have to do some tricks, like adding some Singleton or using Dependency Injection to make it easy to collect, we can also make sure that it does not take a lot of time starting using some delegation pattern, like Lazy, like in the example below

If you are using Retrofit to handle your OkHttpClient and Dagger, you may want to revisit one solution proposed by Zac Sweers in his talk “Dagger Party Tricks” at Droidcon NYC 2019 in this talk Zac Sweers mentions how to manage and simplify some start-up times using Dagger with an incredible example of Retrofit, Cache and OkHttpClient.

This is all for this part of the post. For the last part, we will discuss Testing, Mock, and Integration for Network requests!

If you need help:

I’m always happy to help, you can find me here:
Medium as Dinorah Tovar
Twitter as @ddinorahtovar
StackOverflow as Dinorah Tovar

Happy Coding! 👩🏻‍💻

--

--

Google Developer Expert on Android | Doing Kotlin | Making Software 24/7 | Kotlin Multiplatform | She/Her | Opinions are my own, and not my employer