Android – How To Run Android Tasks In Background Threads ?

Hello Readers, CoolMonkTechie heartily welcomes you in this article (How To Run Android Tasks In Background Threads ?).

In this article, we will learn about how to run android tasks in background threads. All Android apps use a main thread to handle UI operations. Calling long-running operations from this main thread can lead to freezes and unresponsiveness. For example, if our app makes a network request from the main thread, our app’s UI is frozen until it receives the network response. We can create additional background threads to handle long-running operations while the main thread continues to handle UI updates.

This article shows both Kotlin and Java Programming Language developers to use of a thread pool to set up and use multiple threads in an Android app. It also explains code definitions to run on a thread and communications between one of these threads and the main thread.

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

In this example section, we will make a network request and return the result to the main thread, where the app then might display that result on the screen. Specifically, the ViewModel calls the repository layer on the main thread to trigger the network request. The repository layer is in charge of moving the execution of the network request off the main thread and posting the result back to the main thread using a callback.

To move the execution of the network request off the main thread, we need to create other threads in our app.

Creating Multiple Threads

thread pool is a managed collection of threads that runs tasks in parallel from a queue. New tasks are executed on existing threads as those threads become idle. To send a task to a thread pool, use the ExecutorService interface. Note that ExecutorService has nothing to do with Services, the Android application component.

Creating threads is expensive, so we should create a thread pool only once as our app initializes. Be sure to save the instance of the ExecutorService either in our Application class or in a dependency injection container. The following example creates a thread pool of four threads that we can use to run background tasks.

class MyApplication : Application() {
    val executorService: ExecutorService = Executors.newFixedThreadPool(4)
}

Executing In A Background Thread

Making a network request on the main thread causes the thread to wait, or block, until it receives a response. Since the thread is blocked, the OS can’t call onDraw(), and our app freezes, potentially leading to an Application Not Responding (ANR) dialog. Instead, let’s run this operation on a background thread.

First, let’s take a look at our Repository class and see how it’s making the network request:

sealed class Result<out R> {
    data class Success<out T>(val data: T) : Result<T>()
    data class Error(val exception: Exception) : Result<Nothing>()
}

class LoginRepository(private val responseParser: LoginResponseParser) {
    private const val loginUrl = "https://example.com/login"

    // Function that makes the network request, blocking the current thread
    fun makeLoginRequest(
        jsonBody: String
    ): Result<LoginResponse> {
        val url = URL(loginUrl)
        (url.openConnection() as? HttpURLConnection)?.run {
            requestMethod = "POST"
            setRequestProperty("Content-Type", "application/json; charset=utf-8")
            setRequestProperty("Accept", "application/json")
            doOutput = true
            outputStream.write(jsonBody.toByteArray())

            return Result.Success(responseParser.parse(inputStream))
        }
        return Result.Error(Exception("Cannot open HttpURLConnection"))
    }
}

makeLoginRequest() is synchronous and blocks the calling thread. To model the response of the network request, we have our own Result class.

The ViewModel triggers the network request when the user taps, for example, on a button:

class LoginViewModel(
    private val loginRepository: LoginRepository
) {
    fun makeLoginRequest(username: String, token: String) {
        val jsonBody = "{ username: \"$username\", token: \"$token\"}"
        loginRepository.makeLoginRequest(jsonBody)
    }
}

With the previous code, LoginViewModel is blocking the main thread when making the network request. We can use the thread pool that we’ve instantiated to move the execution to a background thread. First, following the principles of dependency injectionLoginRepository takes an instance of Executor as opposed to ExecutorService because it’s executing code and not managing threads:

class LoginRepository(
    private val responseParser: LoginResponseParser
    private val executor: Executor
) { ... }

The Executor’s execute() method takes a Runnable. A Runnable is a Single Abstract Method (SAM) interface with a run() method that is executed in a thread when invoked.

Let’s create another function called makeLoginRequest() that moves the execution to the background thread and ignores the response for now:

class LoginRepository(
    private val responseParser: LoginResponseParser
    private val executor: Executor
) {

    fun makeLoginRequest(jsonBody: String) {
        executor.execute {
            val ignoredResponse = makeSynchronousLoginRequest(url, jsonBody)
        }
    }

    private fun makeSynchronousLoginRequest(
        jsonBody: String
    ): Result<LoginResponse> {
        ... // HttpURLConnection logic
    }
}

Inside the execute() method, we create a new Runnable with the block of code, we want to execute in the background thread—in our case, the synchronous network request method. Internally, the ExecutorService manages the Runnable and executes it in an available thread.

In Kotlin, we can use a lambda expression to create an anonymous class that implements the SAM interface.

Considerations

Any thread in our app can run in parallel to other threads, including the main thread, so we should ensure that our code is thread-safe. Notice that in our example that we avoid writing to variables shared between threads, passing immutable data instead. This is a good practice, because each thread works with its own instance of data, and we avoid the complexity of synchronization.

If we need to share state between threads, we must be careful to manage access from threads using synchronization mechanisms such as locks. In general we should avoid sharing mutable state between threads whenever possible.

Communicating With The Main Thread

In the previous step, we ignored the network request response. To display the result on the screen, LoginViewModel needs to know about it. We can do that by using callbacks.

The function makeLoginRequest() should take a callback as a parameter so that it can return a value asynchronously. The callback with the result is called whenever the network request completes or a failure occurs. In Kotlin, we can use a higher-order function.

class LoginRepository(
    private val responseParser: LoginResponseParser
    private val executor: Executor
) {

    fun makeLoginRequest(
        jsonBody: String,
        callback: (Result<LoginResponse>) -> Unit
    ) {
        executor.execute {
            try {
                val response = makeSynchronousLoginRequest(jsonBody)
                callback(response)
            } catch (e: Exception) {
                val errorResult = Result.Error(e)
                callback(errorResult)
            }
        }
    }
    ...
}

The ViewModel needs to implement the callback now. It can perform different logic depending on the result:

class LoginViewModel(
    private val loginRepository: LoginRepository
) {
    fun makeLoginRequest(username: String, token: String) {
        val jsonBody = "{ username: \"$username\", token: \"$token\"}"
        loginRepository.makeLoginRequest(jsonBody) { result ->
            when(result) {
                is Result.Success<LoginResponse> -> // Happy path
                else -> // Show error in UI
            }
        }
    }
}

In this example, the callback is executed in the calling thread, which is a background thread. This means that we cannot modify or communicate directly with the UI layer until we switch back to the main thread.

To communicate with the View from the ViewModel layer, use LiveData as recommended in the updated app architecture. If the code is being executed on a background thread, we can call MutableLiveData.postValue() to communicate with the UI layer.

Using Handlers

We can use a Handler to enqueue an action to be performed on a different thread. To specify the thread on which to run the action, construct the Handler using a Looper for the thread. A Looper is an object that runs the message loop for an associated thread. Once we’ve created a Handler, we can then use the post(Runnable) method to run a block of code in the corresponding thread.

Looper includes a helper function, getMainLooper(), which retrieves the Looper of the main thread. We can run code in the main thread by using this Looper to create a Handler. As this is something we might do quite often, we can also save an instance of the Handler in the same place we saved the ExecutorService:

class MyApplication : Application() {
    val executorService: ExecutorService = Executors.newFixedThreadPool(4)
    val mainThreadHandler: Handler = HandlerCompat.createAsync(Looper.getMainLooper())
}

It’s a good practice to inject the handler to the Repository, as it gives us more flexibility. For example, in the future we might want to pass in a different Handler to schedule tasks on a separate thread. If we’re always communicating back to the same thread, we can pass the Handler into the Repository constructor, as shown in the following example.

class LoginRepository(
    ...
    private val resultHandler: Handler
) {

    fun makeLoginRequest(
        jsonBody: String,
        callback: (Result<LoginResponse>) -> Unit
    ) {
          executor.execute {
              try {
                  val response = makeSynchronousLoginRequest(jsonBody)
                  resultHandler.post { callback(response) }
              } catch (e: Exception) {
                  val errorResult = Result.Error(e)
                  resultHandler.post { callback(errorResult) }
              }
          }
    }
    ...
}

Alternatively, if we want more flexibility, we can pass in a Handler to each function:

class LoginRepository(...) {
    ...
    fun makeLoginRequest(
        jsonBody: String,
        resultHandler: Handler,
        callback: (Result<LoginResponse>) -> Unit
    ) {
        executor.execute {
            try {
                val response = makeSynchronousLoginRequest(jsonBody)
                resultHandler.post { callback(response) }
            } catch (e: Exception) {
                val errorResult = Result.Error(e)
                resultHandler.post { callback(errorResult) }
            }
        }
    }
}

In this example, the callback passed into the Repository’s makeLoginRequest call is executed on the main thread. That means we can directly modify the UI from the callback or use LiveData.setValue() to communicate with the UI.

Configuring A Thread Pool

We can create a thread pool using one of the Executor helper functions with predefined settings, as shown in the previous example code. Alternatively, if we want to customize the details of the thread pool, we can create an instance using ThreadPoolExecutor directly. We can configure the following details:

  • Initial and maximum pool size
  • Keep alive time and time unit. Keep alive time is the maximum duration that a thread can remain idle before it shuts down.
  • An input queue that holds Runnable tasks. This queue must implement the BlockingQueue interface. To match the requirements of our app, we can choose from the available queue implementations.

Here’s an example that specifies thread pool size based on the total number of processor cores, a keep alive time of one second, and an input queue.

class MyApplication : Application() {
    /*
     * Gets the number of available cores
     * (not always the same as the maximum number of cores)
     */
    private val NUMBER_OF_CORES = Runtime.getRuntime().availableProcessors()

    // Instantiates the queue of Runnables as a LinkedBlockingQueue
    private val workQueue: BlockingQueue<Runnable> =
            LinkedBlockingQueue<Runnable>()

    // Sets the amount of time an idle thread waits before terminating
    private const val KEEP_ALIVE_TIME = 1L
    // Sets the Time Unit to seconds
    private val KEEP_ALIVE_TIME_UNIT = TimeUnit.SECONDS
    // Creates a thread pool manager
    private val threadPoolExecutor: ThreadPoolExecutor = ThreadPoolExecutor(
            NUMBER_OF_CORES,       // Initial pool size
            NUMBER_OF_CORES,       // Max pool size
            KEEP_ALIVE_TIME,
            KEEP_ALIVE_TIME_UNIT,
            workQueue
    )
}

Concurrency Libraries

It’s important to understand the basics of threading and its underlying mechanisms. There are, however, many popular libraries that offer higher-level abstractions over these concepts and ready-to-use utilities for passing data between threads. These libraries include Guava and RxJava for the Java Programming Language users and coroutines, which we recommend for Kotlin users.

In practice, we should pick the one that works best for our app and our development team, though the rules of threading remain the same.

That’s all about in this article.

Related Other Articles / Posts

Conclusion

In this article, we understood about how to run android tasks in background threads. This article showed both Kotlin and Java Programming Language developers to use of a thread pool to set up and use multiple threads in an Android app. It also explained code definitions to run on a thread and communications between one of these threads and the main thread.

Thanks for reading! I hope you enjoyed and learned about Running Android Tasks In Background Threads concepts. 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 Apply Background Processing In Android Application?

Hello Readers, CoolMonkTechie heartily welcomes you in this article (How To Apply Background Processing In Android Application?).

In this article, we will learn about how to apply background processing in android application. Processing data in the background is an important part of creating an Android application. Therefore, it is both responsive for our users as well as a good citizen on the Android platform. This article explains the below points :

  • what qualifies as background work,
  • defines background task categories,
  • provides us with criteria to categorize our tasks, and
  • recommends APIs that we should use to execute them.

A famous quote about learning is :

Learn as though you would never be able to master it; hold it as though you would be in fear of losing it.

So Let’s begin.

Background Processing Principle

In general, any task that takes more than a few milliseconds should be delegated to a background thread. Common long-running tasks include things like decoding a bitmap, accessing storage, working on a machine learning (ML) model, or performing network requests.

Background Work Definition

An app is considered to be running in the background as long as each of the following conditions are satisfied:

  • None of the app’s activities are currently visible to the user.
  • The app isn’t running any foreground services that started while an activity from the app was visible to the user.

Otherwise, the app is considered to be running in the foreground.

Sometimes, after a foreground service starts while an activity from the app is visible to the user, the user navigates away from the app, such as returning to the home screen. In this situation, the app is considered to be running in the foreground even after the user navigates away from the app.

Common Background Tasks

The following list shows common tasks that an app manages while it runs in the background:

  • Our app registers a broadcast receiver in the manifest file.
  • Existing app schedules a repeating alarm using Alarm Manager.
  • Currently used app schedules a background task, either as a worker using Work Manager or a job using Job Scheduler.

Categories of Background Tasks

Background tasks fall into one of the following main categories:

  • Immediate
  • Deferred
  • Exact

To categorize a task, we need answer the following questions:

Does the task need to complete while the user is interacting with the application?

If so, this task should be categorized for immediate execution. If not, proceed to the second question.

Does the task need to run at an exact time?

If we do need to run a task at an exact time, categorize the task as exact.

Most tasks don’t need to be run at an exact time. Tasks generally allow for slight variations in when they run that are based on conditions such as network availability and remaining battery. Tasks that don’t need to be run at an exact time should be categorized as deferred.

After getting the answer, we traverse the corresponding decision tree which helps us decide best category for our background task.

Source : Android Developers – Task Category Decision Tree

Recommended Solutions

The following sections describe recommended solutions for each background task type.

Immediate Tasks

We recommend Kotlin coroutines for tasks that should end when the user leaves a certain scope or finishes an interaction. Many Android KTX libraries contain ready-to-use coroutine scopes for common app components like ViewModel and common application lifecycles.

Threading on Android is the recommended options for Java programming language users.

For tasks that should be executed immediately and need continued processing, even if the user puts the application in background or the device restarts, we recommend using WorkManager and its support for long-running tasks.

In specific cases, such as with media playback or active navigation, we might want to use foreground Services directly.

Deferred Tasks

A task can deferred if:

  • it is not directly connected to a user interaction and,
  • it can run at any time in the future.

The recommended solution for deferred tasks is WorkManager.

WorkManager makes it easy to schedule deferrable, asynchronous tasks that are expected to run even if the app exits or the device restarts.

Exact Tasks

We can use AlarmManager if task that needs to be executed at an exact point in time.

That’s all about in this article.

Related Other Articles / Posts

Conclusion

In this article, we understood about how to apply background processing in android application. Processing data in the background is an important part of creating an Android application. We can use WorkManager for Immediate and deferred task and continued processing while AlarmManager for Exact Tasks. This article reviewed background work definitions and qualifies, common categories and recommended solutions for background processing tasks in android.

Thanks for reading! I hope you enjoyed and learned about Background Processing 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 !!???

iOS – How To Select The Best Method Of Scheduling Background Runtime In iOS ?

Hello Readers, CoolMonkTechie heartily welcomes you in this article (How To Select The Best Method Of Scheduling Background Runtime In iOS ?).

In this article, We will understand how to select the best method of scheduling background runtime for our app in iOS. Selecting the right strategies for our app in iOS depends on how it functions in the background.

A famous quote about Learning is :

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


So Let’s begin.


Overview

If our app needs computing resources to complete tasks when it’s not running in the foreground, we can select from a number of strategies to obtain background runtime. Selecting the right strategies for our app depends on how it functions in the background.

Some apps perform work for a short time while in the foreground and must continue uninterrupted if they go to the background. Other apps defer that work to perform in the background at a later time or even at night while the device charges. And some apps need background processing time at varied and unpredictable times, such as when an external event or message arrives.


Different Methods Of Scheduling Background Runtime

In this section, we select one or more methods for our app based on how you schedule activity in the background.


1. Continue Foreground Work in the Background

The system may place apps in the background at any time. If our app performs critical work that must continue while it runs in the background, use beginBackgroundTask(withName:expirationHandler:) to alert the system. Consider this approach if our app needs to finish sending a message or complete saving a file.

The system grants our app a limited amount of time to perform its work once it enters the background. Don’t exceed this time, and use the expiration handler to cover the case where the time has depleted to cancel or defer the work.

Once our work completes, call endBackgroundTask(_:) before the time limit expires so that our app suspends properly. The system terminates our app if we fail to call this method.

If the task is one that takes some time, such as downloading or uploading files, use URLSession.


2. Defer Intensive Work

To preserve battery life and performance, we can schedule backgrounds tasks for periods of low activity, such as overnight when the device charges. Use this approach when our app manages heavy workloads, such as training machine learning models or performing database maintenance.

Schedule these types of background tasks using BGProcessingTask, and the system decides the best time to launch our background task.


3. Update Our App’s Content

Our app may require short bursts of background time to perform content refresh or other work; for example, our app may fetch content from the server periodically, or regularly update its internal state. In this situation, use BGAppRefreshTask by requesting BGAppRefreshTaskRequest.

The system decides the best time to launch our background task, and provides our app up to 30 seconds of background runtime. Complete our work within this time period and call setTaskCompleted(success:), or the system terminates our app. 


4. Wake Our App with a Background Push

Background pushes silently wake our app in the background. They don’t display an alert, play a sound, or badge our app’s icon. If our app obtains content from a server infrequently or at irregular intervals, use background pushes to notify our app when new content becomes available. A messaging app with a muted conversation might use a background push solution, and so might an email app that process incoming mail without alerting the user.

When sending a background push, set content-available: to 1 without alertsound, or badge. The system decides when to launch the app to download the content. To ensure our app launches, set apns-priority to 5, and apns-push-type to background.

Once the system delivers the remote notification with application(_:didReceiveRemoteNotification:fetchCompletionHandler:), our app has up to 30 seconds to complete its work. One our app performs the work, call the passed completion handler as soon as possible to conserve power. If we send background pushes more frequently than three times per hour, the system imposes rate limitations.


5. Request Background Time and Notify the User

If our app needs to perform a task in the background and show a notification to the user, use a Notification Service Extension. For example, an email app might need to notify a user after downloading a new email. Subclass UNNotificationServiceExtension and bundle the system extension with our app. Upon receiving a push notification, our service extension wakes up and obtains background runtime through didReceive(_:withContentHandler:).

When our extension completes its work, it must call the content handler with the content we want to deliver to the user. Our extension has a limited amount of time to modify the content and execute the contentHandler block.

That’s all about in this article.


Conclusion

In this article, We understood how to select the best method of scheduling background runtime in iOS.

Thanks for reading ! I hope you enjoyed and learned about selecting best method for scheduling background runtime concept 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 !!???

Exit mobile version