# Live Updates for the Android SDK

Integrate Live Updates into your Android app to display real-time updates in notifications, widgets, or within your app. {{< badge "axp" >}}


For the push API method, see the [Android Live Updates](https://www.airship.com/docs/guides/messaging/features/android-live-updates/) messaging guide. See also the [Android Live Updates](https://www.airship.com/docs/guides/features/messaging/live-activities-updates/) feature guide.

## Installation

Include the Live Updates module in your app's dependencies:


#### Gradle Kotlin


**app build.gradle.kts**


```kotlin
dependencies {
    val airshipVersion = "androidSdkVersion"

    implementation("com.urbanairship.android:urbanairship-live-update:$airshipVersion")
}
```



#### Gradle Groovy


**app build.gradle**


```groovy
dependencies {
    def airshipVersion = "androidSdkVersion"

    implementation "com.urbanairship.android:urbanairship-live-update:$airshipVersion"
}
```




## Creating a handler

The Airship SDK supports two types of Live Update handlers:

* `NotificationLiveUpdateHandler` — Displays a notification with a custom layout, with content updated by the Live Update.
* `CustomLiveUpdateHandler` — Receives Live Update events and provides flexibility to display content using a custom implementation. This can be used to power home screen widgets, views embedded in the app, and more.

Each handler type has two different interfaces that may be implemented, to support suspending or callback-based code:

* `SuspendLiveUpdateNotificationHandler`
* `CallbackLiveUpdateNotificationHandler`
* `SuspendLiveUpdateCustomHandler`
* `CallbackLiveUpdateCustomHandler`

The following `SampleLiveUpdateHandler` reads content from the Live Update payload and displays scores for a sports game in a custom notification layout, using `RemoteViews`:


#### Kotlin


```kotlin
class SampleLiveUpdateHandler : SuspendLiveUpdateNotificationHandler() {
    override suspend fun onUpdate(
        context: Context,
        event: LiveUpdateEvent,
        update: LiveUpdate
    ): LiveUpdateResult<NotificationCompat.Builder> {

        // Read content_state fields from the Live Update payload
        val teamOneScore = update.content.opt("team_one_score").getInt(0).toString()
        val teamTwoScore = update.content.opt("team_two_score").getInt(0).toString()
        val statusUpdate = update.content.opt("status_update").optString()

        // Expanded notification layout
        val bigLayout = RemoteViews(context.packageName, R.layout.sports_big).apply {
            setTextViewText(R.id.teamOneScore, teamOneScore)
            setTextViewText(R.id.teamTwoScore, teamTwoScore)
            setTextViewText(R.id.statusUpdate, statusUpdate)
        }

        // Collapsed notification layout
        val smallLayout = RemoteViews(context.packageName, R.layout.sports_small).apply {
            setTextViewText(R.id.teamOneScore, teamOneScore)
            setTextViewText(R.id.teamTwoScore, teamTwoScore)
        }

        // Create the notification builder
        val builder = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID)
            .setSmallIcon(R.drawable.ic_notification)
            .setPriority(NotificationCompat.PRIORITY_HIGH)
            .setCategory(NotificationCompat.CATEGORY_EVENT)
            .setStyle(NotificationCompat.DecoratedCustomViewStyle())
            .setCustomContentView(smallLayout)
            .setCustomBigContentView(bigLayout)

        // Return 'ok' with the notification builder.
        // The Airship SDK will handle posting the notification.
        // Returning LiveUpdateResult.cancel() will end the Live Update and dismiss the notification.
        return LiveUpdateResult.ok(builder)
    }

    companion object {
        private const val NOTIFICATION_CHANNEL_ID = "sports"
    }
}
```



#### Java


```java
public class SampleLiveUpdateHandler extends CallbackLiveUpdateNotificationHandler() {
    @Override
    public void onUpdate(
        Context context,
        LiveUpdateEvent event,
        LiveUpdate update,
        LiveUpdateResultCallback<NotificationCompat.Builder> callback
    ) {
        // Read content_state fields from the Live Update payload
        int teamOneScore = update.getContent().optInt("team_one_score", 0);
        int teamTwoScore = update.getContent().optInt("team_two_score", 0);
        String statusUpdate = update.getContent().optString("status_update");

        // Expanded notification layout
        RemoteViews bigLayout = new RemoteViews(context.getPackageName(), R.layout.sports_big);
        bigLayout.setTextViewText(R.id.teamOneScore, String.valueOf(teamOneScore));
        bigLayout.setTextViewText(R.id.teamTwoScore, String.valueOf(teamTwoScore));
        bigLayout.setTextViewText(R.id.statusUpdate, statusUpdate);

        // Collapsed notification layout
        RemoteViews smallLayout = new RemoteViews(context.getPackageName(), R.layout.sports_small);
        smallLayout.setTextViewText(R.id.teamOneScore, String.valueOf(teamOneScore));
        smallLayout.setTextViewText(R.id.teamTwoScore, String.valueOf(teamTwoScore));

        // Create the notification builder
        NotificationCompat.Builder builder = new NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID)
            .setSmallIcon(R.drawable.ic_notification)
            .setPriority(NotificationCompat.PRIORITY_HIGH)
            .setCategory(NotificationCompat.CATEGORY_EVENT)
            .setStyle(new NotificationCompat.DecoratedCustomViewStyle())
            .setCustomContentView(smallLayout)
            .setCustomBigContentView(bigLayout);

        // Return 'ok' with the notification builder.
        // The Airship SDK will handle posting the notification.
        // Returning LiveUpdateResult.cancel() will end the Live Update and dismiss the notification.
        callback.onResult(LiveUpdateResult.ok(builder));
    }

    private static final String NOTIFICATION_CHANNEL_ID = "sports";
}
```




### Registering a handler

Handlers must be registered with `LiveUpdateManager` in order to receive Live Update events. This should be done *once* after `takeOff`.

In your `Autopilot` class, or in `Application.onCreate`, register the types.


#### Kotlin


```kotlin
class SampleAutopilot : Autopilot() {

    override fun onAirshipReady(context: Context) {

        Airship.liveUpdateManager.register(
            type = "notification",
            handler = SampleLiveUpdateHandler()
        )
    }
}
```



#### Java


```java
public class SampleAutopilot extends Autopilot() {

    @Override
    public void onAirshipReady(Context context) {
        LiveUpdateManager.shared().register("notification", new SampleLiveUpdateHandler());
    }
}
```




> **Note:** The `type` used above, `"notification"`, is used to map Live Update events to the corresponding handler in your app.
> The value can be any string that is unique across all handlers registered by an app. This also allows a single handler to manage multiple Live Updates that each have a unique `name`.


### Starting Live Updates

Live Updates can be started from within the app.


#### Kotlin


```kotlin
Airship.liveUpdateManager.start(
    name = "sports-game-123",
    type = "notification",
    content = jsonMapOf(
        "team_one_score" to 0,
        "team_two_score" to 0,
        "status_update" to "Game started!"
    )
)
```



#### Java


```java
Map<String, Object> content = new HashMap<>();
content.put("team_one_score", 0);
content.put("team_two_score", 0);
content.put("status_update", "Game started!");

LiveUpdateManager.shared().start(
    "sports-game-123",
    "notification",
    content
);
```




### Updating Live Updates

Live Updates can be updated from within the app.


#### Kotlin


```kotlin
Airship.liveUpdateManager.update(
    name = "sports-game-123",
    content = jsonMapOf(
        "team_one_score" to 3,
        "team_two_score" to 0,
        "status_update" to "Game started!"
    )
)
```



#### Java


```java
Map<String, Object> content = new HashMap<>();
content.put("team_one_score", 3);
content.put("team_two_score", 0);
content.put("status_update", "Game started!");

LiveUpdateManager.shared().update(
    "sports-game-123",
    content
);
```




### Ending Live Updates

You can end a Live Update from within the app.


#### Kotlin


```kotlin
Airship.liveUpdateManager.stop(
    name = "sports-game-123",
    content = jsonMapOf(
        "team_one_score" to 9,
        "team_two_score" to 6,
        "status_update" to "Game over!"
    )
)
```



#### Java


```java
Map<String, Object> content = new HashMap<>();
content.put("team_one_score", 9);
content.put("team_two_score", 6);
content.put("status_update", "Game over!");

LiveUpdateManager.shared().stop(
    "sports-game-123",
    content
);
```




### Clearing all active Live Updates

During development, it can be useful to reset Live Update tracking on app launch. This allows any Live Updates to be started fresh, even if they were already started during a previous launch. To end all currently active Live Updates, call the `clearAll()` method on `LiveUpdateManager`.


#### Kotlin


```kotlin
Airship.liveUpdateManager.clearAll()
```



#### Java


```java
LiveUpdateManager.shared().clearAll();
```



