You are able to move a part of your code into another thread to offload the main thread
and avoid getting ANR, NetworkOnMainThreadException, IllegalStateException(e.g. Cannot access database on the main thread since it may potentially lock the UI for a long period of time).
There are some approaches that you should choose depends on the situation
Java Thread or Android HandlerThread
Java threads are one-time use only and die after executing its run method.
HandlerThread is a handy class for starting a new thread that has a looper.
AsyncTask is designed to be a helper class around Thread and Handler and does not constitute a generic threading framework. AsyncTasks should ideally be used for short operations (a few seconds at the most.) If you need to keep threads running for long periods of time, it is highly recommended you use the various APIs provided by the java.util.concurrent package such as Executor, ThreadPoolExecutor and FutureTask.
Thread pool implementation ThreadPoolExecutor, ScheduledThreadPoolExecutor...
ThreadPoolExecutor class that implements ExecutorService which gives fine control on the thread pool (Eg, core pool size, max pool size, keep alive time, etc.)
ScheduledThreadPoolExecutor - a class that extends ThreadPoolExecutor. It can schedule tasks after a given delay or periodically.
FutureTask performs asynchronous processing, however, if the result is not ready yet or processing has not complete, calling get() will be block the thread
AsyncTaskLoaders as they solve a lot of problems that are inherent to AsyncTask
This is the defacto choice for long running processing on Android, a good example would be to upload or download large files. The upload and download may continue even if the user exits the app and you certainly do not want to block the user from being able to use the app while these tasks are going on.
Effectively, you have to create a Service and create a job using JobInfo.Builder that specifies your criteria for when to run the service.
Library for composing asynchronous and event-based programs by using observable sequences.
Coroutines (Kotlin)
The main gist of it is, it makes asynchronous code looks so much like synchronous