How to manage tasks in Activity ?
Android manages tasks and the back stack by placing all activities started in succession in the same task, in a last in, first out stack. This works great for most apps, and you usually don’t have to worry about how your activities are associated with tasks or how they exist in the back stack.
However, you might decide that you want to interrupt the normal behavior. For example, you might want an activity in your app to begin a new task when it is started, instead of being placed within the current task. Or, when you start an activity, you might want to bring forward an existing instance of it, instead of creating a new instance on top of the back stack. Or you might want your back stack to be cleared of all activities except for the root activity when the user leaves the task.
You can do these things and more using attributes in the <activity> manifest element and flags in the intent that you pass to startActivity().</activity>
What is principle activity attribute for manage the tasks ?
These are the principal <activity> attributes that you can use to manage tasks:</activity>
How to handle affinities ?
An affinity indicates which task an activity “prefers” to belong to. By default, all the activities from the same app have an affinity for each other: they “prefer” to be in the same task.
However, you can modify the default affinity for an activity. Activities defined in different apps can share an affinity, and activities defined in the same app can be assigned different task affinities.
You can modify an activity’s affinity using the taskAffinity attribute of the <activity> element.</activity>
The taskAffinity attribute takes a string value that must be different than the default package name declared in the <manifest> element, because the system uses that name to identify the default task affinity for the app.</manifest>
The affinity comes into play in two circumstances:
How to clear the back stack ?
f the user leaves a task for a long time, the system clears the task of all activities except the root activity. When the user returns to the task, only the root activity is restored. The system behaves this way based on the assumption that after an extended amount of time users have abandoned what they were doing before and are returning to the task to begin something new.
There are some activity attributes that you can use to modify this behavior:
How to define Launch Modes ?
Launch modes let you define how a new instance of an activity is associated with the current task. You can define launch modes in two ways, described in the sections that follow:
Define launch modes using the manifest file.
When declaring an activity in your manifest file, you can specify how the activity associates with a task using the <activity> element's launchMode attribute.</activity>
There are five launch modes you can assign to the launchMode attribute:
Note: “singleTask” and “singleInstancePerTask” remove all activities that are above the starting activity from the task. For example, suppose a task consists of root activity A with activities B and C. The task is A-B-C, with C on top. An intent arrives for an activity of type A. If A’s launch mode is “singleTask” or “singleInstancePerTask”, the existing instance of A receives the intent through onNewIntent(). B and C are finished, and the task is now A.
Define launch modes using Intent flags.
When starting an activity, you can modify the default association of an activity to its task by including flags in the intent that you deliver to startActivity(). The flags you can use to modify the default behavior are the following:
This produces the same behavior as the “singleTask” launchMode value discussed in the preceding section.
This produces the same behavior as the “singleTop” launchMode value discussed in the preceding section.
There is no value for the launchMode attribute that produces this behavior.
FLAG_ACTIVITY_CLEAR_TOP is most often used in conjunction with FLAG_ACTIVITY_NEW_TASK. When used together, these flags locate an existing activity in another task and put it in a position where it can respond to the intent.
What is Android Services?
A Service is an application component that can perform long-running operations in the background. It does not provide a user interface. Once started, a service might continue running for some time, even after the user switches to another application. Additionally, a component can bind to a service to interact with it and even perform interprocess communication (IPC). For example, a service can handle network transactions, play music, perform file I/O, or interact with a content provider, all from the background.
Caution: A service runs in the main thread of its hosting process; the service does not create its own thread and does not run in a separate process unless you specify otherwise. You should run any blocking operations on a separate thread within the service to avoid Application Not Responding (ANR) errors.
Explain the type of services.
Types of Services:
These are the three different types of services:
When you use a foreground service, you must display a notification so that users are actively aware that the service is running. This notification cannot be dismissed unless the service is either stopped or removed from the foreground.
Note: The WorkManager API offers a flexible way of scheduling tasks, and is able to run these jobs as foreground services if needed. In many cases, using WorkManager is preferable to using foreground services directly.
Note: If your app targets API level 26 or higher, the system imposes restrictions on running background services when the app itself isn’t in the foreground. In most situations, for example, you shouldn’t access location information from the background. Instead, schedule tasks using WorkManager.
How to Choose between a service and a thread.
A service is simply a component that can run in the background, even when the user is not interacting with your application, so you should create a service only if that is what you need.
If you must perform work outside of your main thread, but only while the user is interacting with your application, you should instead create a new thread in the context of another application component. For example, if you want to play some music, but only while your activity is running, you might create a thread in onCreate(), start running it in onStart(), and stop it in onStop(). Also consider using thread pools and executors from the java.util.concurrent package or Kotlin coroutines instead of the traditional Thread class.
Remember that if you do use a service, it still runs in your application’s main thread by default, so you should still create a new thread within the service if it performs intensive or blocking operations.
Declare a service in the manifest.
You must declare all services in your application’s manifest file, just as you do for activities and other components.
To declare your service, add a <service> element as a child of the <application> element. Here is an example:</application></service>
<manifest … >
…
<application … >
<service></service>
…
</application>
</manifest>
What is the callback methods of services?
To create a service, you must create a subclass of Service or use one of its existing subclasses. In your implementation, you must override some callback methods that handle key aspects of the service lifecycle and provide a mechanism that allows the components to bind to the service, if appropriate. These are the most important callback methods that you should override:
If a component starts the service by calling startService() (which results in a call to onStartCommand()), the service continues to run until it stops itself with stopSelf() or another component stops it by calling stopService().
If a component calls bindService() to create the service and onStartCommand() is not called, the service runs only as long as the component is bound to it. After the service is unbound from all of its clients, the system destroys it.
What is return value constraints for onStartCommand() method?
The onStartCommand() method must return an integer. The integer is a value that describes how the system should continue the service in the event that the system kills it.
The return value from onStartCommand() must be one of the following constants:
How to manage the lifecycle of a service ?
The lifecycle of a service is much simpler than that of an activity. However, it’s even more important that you pay close attention to how your service is created and destroyed because a service can run in the background without the user being aware.
The service lifecycle—from when it’s created to when it’s destroyed—can follow either of these two paths:
These two paths aren’t entirely separate. You can bind to a service that is already started with startService(). For example, you can start a background music service by calling startService() with an Intent that identifies the music to play. Later, possibly when the user wants to exercise some control over the player or get information about the current song, an activity can bind to the service by calling bindService(). In cases such as this, stopService() or stopSelf() doesn’t actually stop the service until all of the clients unbind.
How to create bound services?
When creating a service that provides binding, you must provide an IBinder that provides the programming interface that clients can use to interact with the service. There are three ways you can define the interface:
This is the preferred technique when your service is merely a background worker for your own application. The only use case when this is not the preferred way to create your interface is if your service is used by other applications or across separate processes.
This is the simplest way to perform interprocess communication (IPC), because the Messenger queues all requests into a single thread so that you don’t have to design your service to be thread-safe.
As mentioned in the preceding section, the Messenger creates a queue of all the client requests in a single thread, so the service receives requests one at a time. If, however, you want your service to handle multiple requests simultaneously, then you can use AIDL directly. In this case, your service must be thread-safe and capable of multithreading.
To use AIDL directly, create an .aidl file that defines the programming interface. The Android SDK tools use this file to generate an abstract class that implements the interface and handles IPC, which you can then extend within your service.