Handling the state and events
This tutorial will help you observe and respond to changes in the state and events. In it, we will continue the development of the application we started in the previous section.
Section 1: Observing the states
When we talk about state we mean the lifecycle state of the Ads composable.
Step 1
The state of an Ad is called AdState. This is an example of how we can observe the AdState:
when (val state = adState?.state) {
is AdState.State.Error -> {
// We have an error.
}
is AdState.State.Loading -> {
// We are Caching.
}
is AdState.State.Caching -> {
// We are Caching.
}
is AdState.State.AdReadyToDisplay -> {
// Ad is ready and will be displayed.
}
else -> {}
}
Here we can see the different ad states we can observe:
- Error
- Loading
- Caching
-
AdReadyToDisplay
Step 2
Let’s add the code snippet from above to our
AdView
example:@Composable fun AdView() { val adState = rememberAdState(advertisement = viewModel.ad) Ad(adState = adState, modifier = Modifier) when (val state = adState?.state) { is AdState.State.Error -> { // We have an error. } is AdState.State.Loading -> { // We are Caching. } is AdState.State.Caching -> { // We are Caching. } is AdState.State.AdReadyToDisplay -> { // Ad is ready and will be displayed and we could additional work } else -> {} } }
We are able now to act accordingly to each AdState state.
Section 2: Handling errors during the loading and decoding
Sometimes it’s important for an app to be able to handle errors correctly. With the help of AdError, you can catch a specific error and implement the logic for handling it the way you need.
Step 1
We can observe errors in the AdSDK with AdException. An AdException holds the exception itself and the type of the error via AdError. With AdError we can observe different error types. For example lets catch a decoding error.
when(state.adException.adError) {
AdError.DECODING -> {
// Act accordingly e.g. repeat the request.
}
}
Step 2
You can catch a number of different error types, just check AdError. Let’s just log the error and have a look how our composable should look like.
@Composable
fun AdView(viewModel: MainViewModel) {
val adState = rememberAdState(advertisement = viewModel.ad)
Ad(adState = adState, modifier = Modifier)
when (val state = adState?.state) {
is AdState.State.Error -> {
when(state.adException.adError) {
AdError.DECODING -> {
Log.e("MainActivity", "Decoding error: ${state.adException.exception}")
}
}
}
is AdState.State.Loading -> {
// We are Caching.
}
is AdState.State.Caching -> {
// We are Caching.
}
is AdState.State.AdReadyToDisplay -> {
// Ad is ready and will be displayed.
}
else -> {}
}
}
Section 3: Observing the advertising events
Observe the advertising events to respond to them in the application. The SDK can send many events related to advertisements, like impressions, visibility percentages and tap events.
Step 1
With the use of the AdService we can collect all ad Event.
AdService.getInstance().eventHandler?.events?.collect { event ->
Log.d("Events", "Collected EVENT - $event")
}
Step 2
Start the event observing before the composable loads if you want to make sure you get every event. For example, we could add it in the App
class.
class App: Application() {
private val coroutineScope = CoroutineScope(Dispatchers.Default + SupervisorJob())
override fun onCreate() {
super.onCreate()
coroutineScope.launch {
val isSuccess = AdService.init("1800", applicationContext, EventHandler())
Log.d("App", "Init is success: $isSuccess")
launch {
AdService.getInstance().eventHandler?.events?.collect { event ->
Log.d("Events", "Collected EVENT - $event")
when (event.eventType) {
is EventType.Tap -> {
// Ad got tapped.
}
else -> {}
}
}
}
}
}
}
Step 3
You can observe the specific EventTypes you are interested in. For example, you can react to the tap on ads:
when(event.eventType) {
is EventType.Tap -> {
// Ad got tapped.
}
else -> {}
}
Step 4
Let’s add this to the App class as well.
class App : Application() {
private val coroutineScope = CoroutineScope(Dispatchers.Default + SupervisorJob())
override fun onCreate() {
super.onCreate()
coroutineScope.launch {
val isSuccess = AdService.init("1800", applicationContext, EventHandler())
Log.d("App", "Init is success: $isSuccess")
launch {
AdService.getInstance().eventHandler?.events?.collect { event ->
Log.d("Events", "Collected EVENT - $event")
when (event.eventType) {
is EventType.Tap -> {
// Ad got tapped.
}
else -> {}
}
}
}
}
}
}
Now we could act accordingly to a specific event in any way we wanted.