---
source_url: https://www.pubnub.com/docs/sdks/android/api-reference/publish-and-subscribe
title: Publish/Subscribe API for Android SDK
updated_at: 2026-06-18T11:26:44.790Z
---

> Documentation Index
> For a curated overview of PubNub documentation, see: https://www.pubnub.com/docs/llms.txt
> For the full list of all documentation pages, see: https://www.pubnub.com/docs/llms-full.txt


# Publish/Subscribe API for Android SDK

:::warning Unsupported docs
PubNub no longer maintains Android SDK docs, but our [Java SDK](https://www.pubnub.com/docs/sdks/java) or [Kotlin SDK](https://www.pubnub.com/docs/sdks/kotlin) are fully compatible with the Android platform and you can use them to build mobile apps, ensuring stable software development.
:::

The foundation of the PubNub service is the ability to send a message and have it delivered anywhere in less than 30 ms. Send a message to just one other person, or broadcast to thousands of subscribers at once.

For higher-level conceptual details on publishing and subscribing, refer to [Connection Management](https://www.pubnub.com/docs/general/setup/connection-management) and to [Publish Messages](https://www.pubnub.com/docs/general/messages/publish).

## Publish

The `publish()` function is used to send a message to all subscribers of a channel. To publish a message you must first specify a valid `publishKey` at initialization. A successfully published message is replicated across the PubNub Real-Time Network and sent simultaneously to all subscribed clients on a channel.

Secure messages with TLS/SSL by setting `ssl` to `true` during initialization.

##### Publish anytime

It's not required to be subscribed to a channel in order to publish to that channel.

##### Message data

The message can contain any JavaScript Object Notation (JSON)-serializable data (objects, arrays, integers, strings). Avoid Android-specific classes or functions. Strings can include any UTF‑8 characters.

:::warning Don't JSON serialize
It is important to note that you should not JSON serialize when sending signals/messages via PUBNUB. Why? Because the serialization is done for you automatically. Instead just pass the full object as the message payload. PubNub takes care of everything for you.
:::

##### Message size

The maximum message size is 32 KiB, including the channel name and the escaped characters. Aim for under 1,800 bytes for optimal performance.

If the message you publish exceeds the configured size, you will receive the following message:

##### Message too large error

```java
["PUBLISHED",[0,"Message Too Large","13524237335750949"]]
```

For further details, check [Calculating Message Payload Size Before Publish](https://support.pubnub.com/hc/en-us/articles/360051495932-Calculating-Message-Payload-Size-Before-Publish).

:::tip Need larger messages?
Our platform is optimized for payloads up to 32 KiB. PubNub supports larger messages, but increasing the limit requires a verification of compatibility with your use case.
Talk to [our team](https://www.pubnub.com/company/contact-sales/) to discuss increasing the message size limit for your use case.
:::

##### Message publish rate

You can publish as fast as bandwidth allows. There is a soft throughput limit because messages may drop if subscribers can't keep up.

For example, if 200 messages are published simultaneously before a subscriber has had a chance to receive any messages, the subscriber may not receive the first 100 messages because the message queue has a limit of only 100 messages stored in memory.

##### Publishing to multiple channels

It is not possible to publish a message to multiple channels simultaneously. The message must be published to one channel at a time.

##### Publishing messages reliably

There are some best practices to ensure messages are delivered when publishing to a channel:

* Publish to any given channel in a serial manner (not concurrently).
* Check that the return code is success (for example, [1,"Sent","136074940..."])
* Publish the next message only after receiving a success return code.
* If a failure code is returned ([0,"blah","<timetoken>"]), retry the publish.
* Avoid exceeding the in-memory queue's capacity of 100 messages. An overflow situation (aka missed messages) can occur if slow subscribers fail to keep up with the publish pace in a given period of time.
* Throttle publish bursts in accordance with your app's latency needs, for example, Publish no faster than 5 msgs per second to any one channel.

### Method(s)

To `Publish a message` you can use the following method(s) in the Android SDK:

```java
this.pubnub.publish()
    .message(Object)
    .channel(String)
    .shouldStore(Boolean)
    .meta(Object)
    .queryParam(HashMap)
    .usePOST(Boolean)
    .ttl(Integer);
```

| Parameter | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| message | Object | Yes |  | The payload. |
| channel | String | Yes |  | Destination of the `message`. |
| shouldStore | Boolean | Optional | `account default` | Store in history. If `shouldStore` is not specified, then the history configuration on the key is used. |
| meta | Object | Optional | `Not set` | `Meta` data object which can be used with the filtering ability. |
| queryParam | HashMap<string,string> | Optional | `Not set` | One or more query parameters to be passed to the server, for analytics purposes. Overridden in case of conflicts with reserved PubNub parameters, such as `uuid` or `instance_id`. Accessible from your PubNub Dashboard, and never returned in server responses. |
| usePOST | Boolean | Optional | `false` | Use POST to `publish`. |
| ttl | Integer | Optional |  | Set a per message time to live in Message Persistence. If shouldStore = true, and ttl = 0, the message is stored with no expiry time., If shouldStore = true and ttl = X (X is an Integer value), the message is stored with an expiry time of X hours unless you have message retention set to Unlimited on your keyset configuration in the Admin Portal., If shouldStore = false, the ttl parameter is ignored., If ttl is not specified, then expiration of the message defaults back to the expiry value for the key. |
| sync | Command | Optional |  | Block the thread, exception thrown if something goes wrong. |
| async | PNCallback | Optional |  | `PNCallback` of type `PNPublishResult` |

### Sample code

#### Publish a message to a channel

```java
JsonObject position = new JsonObject();
position.addProperty("lat", 32L);
position.addProperty("lng", 32L);

System.out.println("before pub: " + position);
pubnub.publish()
    .message(position)
    .channel("my_channel")
    .async(new PNCallback<PNPublishResult>() {
        @Override
        public void onResponse(PNPublishResult result, PNStatus status) {
            // handle publish result, status always present, result if successful
            // status.isError() to see if error happened
            if(!status.isError()) {
                System.out.println("pub timetoken: " + result.getTimetoken());
            }
            System.out.println("pub status code: " + status.getStatusCode());
        }
    });
```

:::note Subscribe to the channel
Before running the above publish example, either using the [Debug Console](https://www.pubnub.com/docs/console/) or in a separate script running in a separate terminal window, [subscribe to the same channel](#subscribe) that is being published to.
:::

### Returns

The `publish()` operation returns a `PNPublishResult` which contains the following operations:

| Method | Description |
| --- | --- |
| `getTimetoken()`Type: Long | Returns a `long` representation of the timetoken when the message was published. |

### Other examples

#### Publish with metadata

```java
pubnub.publish()
    .message(Arrays.asList("hello", "there"))
    .channel("suchChannel")
    .shouldStore(true)
    .meta(<Object>) // optional meta data object which can be used with the filtering ability.
    .usePOST(true)
    .async(new PNCallback<PNPublishResult>() {
        @Override
        public void onResponse(PNPublishResult result, PNStatus status) {
            // handle publish result, status always present, result if successful
            // status.isError to see if error happened
        }
    });
```

#### Publishing JsonObject (Google GSON)

```java
JsonObject position = new JsonObject();
position.addProperty("lat", 32L);
position.addProperty("lng", 32L);

System.out.println("before pub: " + position);
pubnub.publish()
    .message(position)
    .channel("my_channel")
    .async(new PNCallback<PNPublishResult>() {
        @Override
        public void onResponse(PNPublishResult result, PNStatus status) {
            // handle publish result, status always present, result if successful
            // status.isError() to see if error happened
            if(!status.isError()) {
                System.out.println("pub timetoken: " + result.getTimetoken());
            }
            System.out.println("pub status code: " + status.getStatusCode());
        }
    });
```

#### Publishing JsonArray (Google GSON)

```java
JsonArray position = new JsonArray();
position.add(32L);

System.out.println("before pub: " + position);
pubnub.publish()
    .message(position)
    .channel("my_channel")
    .async(new PNCallback<PNPublishResult>() {
        @Override
        public void onResponse(PNPublishResult result, PNStatus status) {
            //  handle publish result, status always present, result if successful
            //  status.isError to see if error happened
            if(!status.isError()) {
                System.out.println("pub timetoken: " + result.getTimetoken());
            }
            System.out.println("pub status code: " + status.getStatusCode());
        }
    });
```

#### Publishing JSONObject (org.json)

```java
JSONObject position = new JSONObject();
position.put("lat", 32L);
position.put("lng", 32L);

System.out.println("before pub: " + position);
pubnub.publish()
    .message(toMap(position))
    .channel("my_channel")
    .async(new PNCallback<PNPublishResult>() {
        @Override
        public void onResponse(PNPublishResult result, PNStatus status) {
            // handle publish result, status always present, result if successful
            // status.isError to see if error happened
            if(!status.isError()) {
                System.out.println("pub timetoken: " + result.getTimetoken());
            }
            System.out.println("pub status code: " + status.getStatusCode());
        }
    });
```

##### Helper Functions

```java
public static Map<String, Object> toMap(JSONObject object) throws JSONException {
    Map<String, Object> map = new HashMap<>();

    Iterator<String> keysItr = object.keys();
    while(keysItr.hasNext()) {
        String key = keysItr.next();
        Object value = object.get(key);

        if(value instanceof JSONArray) {
            value = toList((JSONArray) value);
        }

        else if(value instanceof JSONObject) {
            value = toMap((JSONObject) value);
        }
        map.put(key, value);
    }
    return map;
}

public static List<Object> toList(JSONArray array) throws JSONException {
    List<Object> list = new ArrayList<>();
    for(int i = 0; i < array.length(); i++) {
        Object value = array.get(i);
        if(value instanceof JSONArray) {
            value = toList((JSONArray) value);
        }

        else if(value instanceof JSONObject) {
            value = toMap((JSONObject) value);
        }
        list.add(value);
    }
    return list;
}
```

#### Publishing JSONArray (org.json)

```java
JSONArray position = new JSONArray();
position.put(32L);

System.out.println("before pub: " + position);
pubnub.publish()
    .message(toList(position))
    .channel("my_channel")
    .async(new PNCallback<PNPublishResult>() {
        @Override
        public void onResponse(PNPublishResult result, PNStatus status) {
            //  handle publish result, status always present, result if successful
            //  status.isError to see if error happened
            if(!status.isError()) {
                System.out.println("pub timetoken: " + result.getTimetoken());
            }
            System.out.println("pub status code: " + status.getStatusCode());
        }
    });
```

##### Helper Functions

```java
public static List<Object> toList(JSONArray array) throws JSONException {
    List<Object> list = new ArrayList<>();
    for(int i = 0; i < array.length(); i++) {
        Object value = array.get(i);
        if(value instanceof JSONArray) {
            value = toList((JSONArray) value);
        }

        else if(value instanceof JSONObject) {
            value = toMap((JSONObject) value);
        }
        list.add(value);
    }
    return list;
}
```

#### Store the published message for 10 hours

```java
PNPublishResult result = pubnub.publish()
                                .channel("coolChannel")
                                .message("test")
                                .shouldStore(true)
                                .ttl(10)
                                .sync();
```

## Fire

The fire endpoint allows the client to send a message to Functions Event Handlers and [Illuminate](https://www.pubnub.com/docs/illuminate/business-objects/external-data-sources). These messages will go directly to any Event Handlers registered on the channel that you fire to and will trigger their execution. The content of the fired request will be available for processing within the Event Handler. The message sent via `fire()` isn't replicated, and so won't be received by any subscribers to the channel. The message is also not stored in history.

### Method(s)

To `Fire a message` you can use the following method(s) in the Android SDK:

```java
this.pubnub.fire()
    .message(Object)
    .channel(String)
    .meta(Object)
    .usePOST(Boolean);
```

| Parameter | Description |
| --- | --- |
| `message` *Type: ObjectDefault: n/a | The payload. |
| `channel` *Type: StringDefault: n/a | Destination of the `message`. |
| `meta`Type: ObjectDefault: `Not set` | `Meta` data object which can be used with the filtering ability. |
| `usePOST`Type: BooleanDefault: `false` | Use POST to `publish`. |
| `sync`Type: CommandDefault: n/a | Block the thread, exception thrown if something goes wrong. |
| `async`Type: PNCallbackDefault: n/a | `PNCallback` of type `PNPublishResult` |

### Sample code

#### Fire a message to a channel

```java
pubnub.fire()
    .message(Arrays.asList("hello", "there"))
    .channel("my_channel")
    .usePOST(true)
    .async(new PNCallback<PNPublishResult>() {
        @Override
        public void onResponse(PNPublishResult result, PNStatus status) {
            if (status.isError()) {
                // something bad happened.
                System.out.println("error happened while publishing: " + status.toString());
            } else {
                System.out.println("publish worked! timetoken: " + result.getTimetoken());
            }
        }
    });
```

## Signal

The `signal()` function is used to send a signal to all subscribers of a channel.

By default, signals are limited to a message payload size of `64` bytes. This limit applies only to the payload, and not to the URI or headers. If you require a larger payload size, please [contact support](https://www.pubnub.com/docs/mailto:support@pubnub.com).

### Method(s)

To `Signal a message` you can use the following method(s) in the Android SDK:

```java
this.pubnub.signal()
    .message(Object)
    .channel(String);
```

| Parameter | Description |
| --- | --- |
| `message` *Type: Object | The payload which will be serialized and sent. |
| `channel` *Type: String | The `channel` which the signal will be sent to. |
| `sync`Type: PNPublishResult | Executes the call. Blocks the thread, exception is thrown if something goes wrong. |
| `async`Type: PNCallback`<PNPublishResult>` | Executes the call asynchronously. |

### Sample code

#### Signal a message to a channel

```java
pubnub.signal()
    .message("Hello everyone!")
    .channel("bar")
    .async(new PNCallback<PNPublishResult>() {
        @Override
        public void onResponse(PNPublishResult pnPublishResult, PNStatus pnStatus) {
            if (pnStatus.isError()) {
                Long timetoken = pnPublishResult.getTimetoken(); // signal message timetoken
            } else {
                pnStatus.getErrorData().getThrowable().printStackTrace();
            }
        }
    });
```

### Response

The `signal()` operation returns a `PNPublishResult` object which contains the following operations:

| Method | Description |
| --- | --- |
| `getTimetoken()`Type: Long | Returns a `long` representation of the timetoken when the signal was published. |

## Subscribe

The subscribe function creates an open TCP socket to PubNub and begins listening for messages and events on a specified entity or set of entities. To subscribe successfully, you must configure the appropriate `subscribeKey` at [initialization](https://www.pubnub.com/docs/sdks/kotlin/api-reference/configuration#initialization).

:::tip Conceptual overview
For more general information about subscriptions, refer to [Subscriptions](https://www.pubnub.com/docs/general/channels/subscribe).
:::

Entities are [first-class citizens](https://en.wikipedia.org/wiki/First-class_citizen) that provide access to their encapsulated APIs. You can subscribe using the PubNub client object or directly on a specific entity:

* [Channel](#create-channels)
* [ChannelGroup](#create-channel-groups)
* [UserMetadata](#create-user-metadata)
* [ChannelMetadata](#create-channel-metadata)

A newly subscribed client receives messages after the `subscribe()` call completes. You can configure [retryConfiguration](https://www.pubnub.com/docs/sdks/kotlin/api-reference/configuration) to automatically attempt to reconnect if a client gets disconnected.

### Subscription scope

Subscription objects provide an interface to attach listeners for various real-time update types. Your app receives messages and events via those event listeners. Two types of subscriptions are available:

* [Subscription](#create-a-subscription), created from an entity with a scope of only that entity (for example, a particular channel)
* [SubscriptionSet](#create-a-subscription-set), created from the PubNub client with a global scope (for example, all subscriptions created on a single `pubnub` object ). A subscription set can have one or more subscriptions.

The event listener is a single point through which your app receives all the messages, signals, and events in the entities you subscribed to. For information on adding event listeners, refer to [Event listeners](#event-listeners).

### Create a subscription

:::note Managing subscription lifecycle
The `Subscription` object implements the [AutoCloseable](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-auto-closeable/#kotlin.AutoCloseable) interface to help you release resources by unsubscribing and removing all listeners. Always call `Subscription.close()` when you no longer need this `Subscription`.
:::

An entity-level `Subscription` allows you to receive messages and events for only that entity for which it was created. Using multiple entity-level `Subscription`s is useful for handling various message/event types differently in each channel.

```kotlin
// Entity-based, local-scoped

// Specify the channel for subscription
val myChannel = pubnub.channel("channelName")

// Create subscription options, if any
val options = SubscriptionOptions.receivePresenceEvents()

// Return a Subscription object that is used to establish the subscription
val subscription = myChannel.subscription(options)

// Activate the subscription to start receiving events
subscription.subscribe()
```

| Parameter | Description |
| --- | --- |
| `options`Type: `SubscriptionOptions` | `Subscription` [behavior configuration](#subscriptionoptions). Use `null` for no specific options. |

### Create a subscription set

:::note Managing subscription lifecycle
The `SubscriptionSet` object implements the [AutoCloseable](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-auto-closeable/#kotlin.AutoCloseable) interface to help you release resources by unsubscribing and removing all listeners. Always call `SubscriptionSet.close()` when you no longer need this `SubscriptionSet`.
:::

A client-level `SubscriptionSet` allows you to receive messages and events for all entities in the set. A single `SubscriptionSet` is useful for similarly handling various message/event types in each channel.

```kotlin
// client-based, general-scoped

fun subscriptionSetOf(
        channels: Set<String> = emptySet(),
        channelGroups: Set<String> = emptySet(),
        options: SubscriptionOptions = EmptyOptions
    ): SubscriptionSet
```

| Parameter | Description |
| --- | --- |
| → `channels`Type: `Set<String>` | Set of channel names to subscribe to. Use an empty set for no channels. |
| → `channelGroups`Type: `Set<String>` | Set of channel group names to subscribe to. Use an empty set for no channel groups. |
| → `options`Type: `SubscriptionOptions` | Additional subscription configuration to define the subscription behavior. If you don't set any options, `EmptyOptions` is used by default. |

:::tip Add/remove sets
You can add and remove subscription sets to create new sets. Refer to the [Other examples](#other-examples-1) section for more information.
:::

#### SubscriptionOptions

`SubscriptionOptions` is a class designed to configure subscription behaviors with optional modifiers. When no specific options are required, `EmptyOptions` is set by default.

The class includes:

| Option | Description |
| --- | --- |
| `receivePresenceEvents()` | Enables receiving presence events for the subscription. It's not required and should be included only when presence information is needed. |
| `filter(predicate: (PNEvent) -> Boolean)` | Allows for custom filtering of events delivered to the subscription based on the provided predicate. Useful for event-specific handling. |

### Method(s)

`Subscription` and `SubscriptionSet` use the same methods to subscribe:

* [Subcribe](#subscribe-1)
* [Subscribe with timetoken](#subscribe-with-timetoken)

#### Subscribe

To subscribe, you can use the following method:

```kotlin
// For subscription
subscription.subscribe()
// For subscription set
subscriptionSet.subscribe()
```

##### Sample code

```kotlin
// Step 1: Create a subscription set
val subscriptionSet = pubnub.subscriptionSetOf(
    // Specify channels with default options
    channels = setOf("my_channel", "other_channel"),
)

// Step 2: Subscribe using the subscription set
subscriptionSet.subscribe()
```

##### Other examples

###### Create a subscription set from 2 individual subscriptions

```kotlin
// Create subscriptions
val subscription1 = pubnub.channel("channelName").subscription()
val subscription2 = pubnub.channelGroup("channelGroup").subscription()

// Combine into a subscription set
val subscriptionSet = subscription1 + subscription2
```

##### Returns

The `subscribe()` method doesn't have a return value.

#### Subscribe with timetoken

:::warning Impact on other subscriptions
Subscribing with a timetoken affects all other subscriptions because it overwrites the timetoken in the single PubNub server connection in the SDK. However, those other subscriptions will not deliver messages older than ones that were already delivered - after receiving an event, a subscription only gets future events, ignoring those before or at the time of the last event received.
:::

To subscribe to real-time updates from a given timetoken, use the following method:

```kotlin
subscriptionSet.subscribe(SubscriptionCursor(timetoken = yourTimeToken))
```

| Parameter | Description |
| --- | --- |
| `cursor` *Type: `SubscriptionCursor` | Cursor from which to return any available cached messages. `SubscriptionCursor` would typically include a `timetoken` (long integer) representing the point in time from which to receive updates. |

##### Sample code

```kotlin
// Define the channels to subscribe to
val channels = setOf("my_channel", "other_channel")

// Create a subscription set with specified channels and subscription options
val subscriptionSet = pubnub.subscriptionSetOf(channels, options)

// Define the timetoken for where the subscription should start
val yourTimeToken = 100000000000L // Directly using Long type

// Subscribe to the created SubscriptionSet with the desired timetoken
subscriptionSet.subscribe(SubscriptionCursor(timetoken = yourTimeToken))
```

##### Returns

The method for subscribing with a timetoken doesn't have a return value.

## Entities

Entities are subscribable objects for which you can receive real-time updates (messages, events, etc).

* [Channel](#create-channels)
* [ChannelGroup](#create-channel-groups)
* [UserMetadata](#create-user-metadata)
* [ChannelMetadata](#create-channel-metadata)

### Create channels

This method returns one local `Channel` entity.

```kotlin
pubnub.channel(name: String): Channel
```

| Parameter | Description |
| --- | --- |
| `name` *Type: `String` | The name of a single [channel](https://www.pubnub.com/docs/general/channels/overview) to create a channel entity for. |

#### Sample code

```kotlin
val singleChannel = pubnub.channel("myChannel")
```

### Create channel groups

This method returns one local `ChannelGroup` entity.

```kotlin
pubnub.channelGroup(name: String): ChannelGroup
```

| Parameter | Description |
| --- | --- |
| `name` *Type: `String` | The name of a single [channel group](https://www.pubnub.com/docs/general/channels/subscribe#channel-groups) to create an entity for. |

#### Sample code

```kotlin
val myChannelGroup = pubnub.channelGroup("myGroup")
```

### Create channel metadata

This method returns one local `ChannelMetadata` entity.

```kotlin
pubnub.channelMetadata(id: String): ChannelMetadata
```

| Parameter | Description |
| --- | --- |
| `id` *Type: `String` | The String identifier for a single [channel metadata](https://www.pubnub.com/docs/general/metadata/channel-metadata) object to create a subscription of. |

#### Sample code

```kotlin
val metadata = pubnub.channelMetadata("myChannel")
```

### Create user metadata

This method returns one local `UserMetadata` entity.

```kotlin
pubnub.userMetadata(userId: String): UserMetadata
```

| Parameter | Description |
| --- | --- |
| `userId` *Type: `String` | The String identifier for a single user metadata object to manage user information. |

#### Sample code

```kotlin
val userMetadata = pubnub.userMetadata("userId1")
```

## Event listeners

Messages and events are received in your app using a listener. This listener allows a single point to receive all messages, signals, and events.

You can attach listeners to the instances of [Subscription](#create-a-subscription), [SubscriptionSet](#create-a-subscription-set), and, in the case of the connection status, the PubNub client.

### Add listeners

You can add listeners for various types of updates related to your subscription. You can implement listeners for general updates (that handle multiple event types at once) or choose listeners dedicated to specific event types such as `Message` or `File`.

#### Handle multiple event types

##### Method(s)

```kotlin
fun addListener(listener: EventListener)
```

##### Sample code

```kotlin
// Create a subscription to a specific channel
val subscription = pubnub.channel("my_channel").subscription()

// Add a listener to the subscription for handling various event types
subscription.addListener(object : EventListener {
    override fun message(pubnub: PubNub, message: PNMessageResult) {
        // Log or process message
        println("Message: ${message.message}")
    }
    
    override fun signal(pubnub: PubNub, signal: PNSignalResult) {
        // Handle signals
        println("Signal: ${signal.message}")
    }
    
    override fun messageAction(pubnub: PubNub, messageAction: PNMessageActionResult) {
        // Handle message reactions
        println("Message Reaction: ${messageAction.data}")
    }
    
    override fun file(pubnub: PubNub, file: PNFileEventResult) {
        // Handle file events
        println("File: ${file.file.name}")
    }
    
    override fun objects(pubnub: PubNub, obj: PNObjectEventResult) {
        // Handle metadata updates
        println("App Context: ${obj.event}")
    }
    
    override fun presence(pubnub: PubNub, presence: PNPresenceEventResult) {
        // Handle presence updates
        println("Presence: ${presence.uuid} - ${presence.event}")
    }
})

// Activate the subscription to start receiving events
subscription.subscribe()

// Print a status when successfully subscribed
println("Subscribed to channel 'my_channel'")
```

#### Handle one event type

#### Method(s)

You can also directly register listeners for specific event types on the subscription object by assigning lambda expressions. This method allows you to handle events such as messages, signals, message reactions, files, objects, and presence.

Using this method, you cannot have multiple listeners attached to the same event type. Assigning a new listener with this method overwrites the previous one.

##### Sample code

```kotlin
subscription.onMessage = { message ->
    /* Handle message */
}

subscription.onSignal = { signal ->
    /* Handle signal */
}

subscription.onMessageAction = { messageAction ->
    /* Handle message reaction */
}

subscription.onFile = { file ->
    /* Handle file event */
}

subscription.onObjects = { obj ->
    /* Handle metadata updates */
}

subscription.onPresence = { presence ->
    /* Handle presence updates */
}
```

##### Remove event listener

To remove the listener for a specific event, assign `null` to it.

```kotlin
subscription.onMessage = null
```

### Add connection status listener

Use the `StatusListener` interface with your `PubNub` instance to add a listener dedicated to connection status updates.

:::warning Client scope
This listener is only available on the PubNub object.
:::

#### Method(s)

```kotlin
pubnub.addListener(object : StatusListener() {
    override fun status(pubnub: PubNub, status: PNStatus) {
        // Handle connection status updates
        println("Connection Status: ${status.category}")
    }
})
```

#### Sample code

```kotlin
// Adding the status listener to the PubNub client
pubnub.addListener(object : StatusListener() {
    override fun status(pubnub: PubNub, status: PNStatus) {
        // This block is executed asynchronously for each status update
        println("Connection Status: ${status.category}")
    }
})
```

#### Returns

This method returns the subscription status.

When you initialized your PubNub client with [enableEventEngine](https://www.pubnub.com/docs/sdks/kotlin/api-reference/configuration#configuration) set to `true` (default option), the SDK will emit various statuses depending on your client network connection.

If you use the deprecated methods for subscribing and had `enableEventEngine` set to `false`, the status list the SDK emits is different.

To help you adjust your app code, see the [Status Events for Subscribe](https://www.pubnub.com/docs/sdks/kotlin/status-events#subscribe) for the exact mapping between the current and deprecated Kotlin SDK statuses.

For more generic information, head to [SDK Connection Lifecycle](https://www.pubnub.com/docs/general/setup/connection-management#sdk-connection-lifecycle).

## Unsubscribe

Stop receiving real-time updates from a [Subscription](#create-a-subscription) or a [SubscriptionSet](#create-a-subscription-set).

### Method(s)

```kotlin
// For subscription
subscription.unsubscribe()
// For subscription set
subscriptionSet.unsubscribe()
```

### Sample code

```kotlin
// Subscribe to a channel
subscription.subscribe()

// Unsubscribe from that channel
subscription.unsubscribe()
```

### Returns

None

## Unsubscribe all

Stop receiving real-time updates from all listeners and remove the entities associated with them.

:::warning Client scope
This method is only available on the PubNub object.
:::

### Method(s)

```kotlin
pubnub.unsubscribeAll()
```

### Sample code

```kotlin
// Subscribe to channels
pubnub.subscribe(channels = setOf("my_channel", "other_channel"))

// Subscribe to a channel group
pubnub.subscribe(channelGroups = setOf("my_channel_group"))

// Later, when you want to unsubscribe from all subscriptions
pubnub.unsubscribeAll()
```

### Returns

None

## Subscribe (old)

:::warning Not recommended
The use of this method is discouraged. Use [Subscribe](#subscribe) instead.
:::

This function causes the client to create an open TCP socket to the PubNub Real-Time Network and begin listening for messages on a specified `channel`. To subscribe to a `channel` the client must send the appropriate `subscribeKey` at initialization.

By default a newly subscribed client will only receive messages published to the channel after the `subscribe()` call completes. If a client gets disconnected from a channel, it can automatically attempt to reconnect to that `channel` and retrieve any available messages that were missed during that period. This can be achieved by setting `setReconnectionPolicy` to `PNReconnectionPolicy.LINEAR`, when [initializing](https://www.pubnub.com/docs/sdks/android/api-reference/configuration#initialization) the client.

:::warning Unsubscribing from all channels
**Unsubscribing** from all channels, and then **subscribing** to a new channel Y is not the same as subscribing to channel Y and then unsubscribing from the previously-subscribed channel(s). Unsubscribing from all channels resets the last-received `timetoken` and thus, there could be some gaps in the subscription that may lead to message loss.
:::

#### Method(s)

To `Subscribe to a channel` you can use the following method(s) in the Android SDK:

```java
pubnub.subscribe()
    .channels(Array)
    .channelGroups(Arrays)
    .withTimetoken(Long)
    .withPresence()
    .execute();
```

| Parameter | Description |
| --- | --- |
| `channels`Type: Array | Subscribe to `channels`, Either `channel` or `channelGroup` is required |
| `channelGroups`Type: Array | Subscribe to `channel groups`, Either `channel` or `channelGroup` is required |
| `withTimetoken`Type: Long | Pass a `timetoken` |
| `withPresence()`Type: Command | Also subscribe to related presence information |
| `execute()` *Type: Command | Command that will `execute` `subscribe`. |

#### Sample code

Subscribe to a channel:

```java
pubnub.subscribe()
    .channels(Arrays.asList("my_channel")) // subscribe to channels
    .execute();
```

:::note Event listeners
The response of the call is handled by adding a Listener. Please see the [Listeners section](#event-listeners) for more details. Listeners should be added before calling the method.
:::

#### Returns

:::note PNMessageResult
`PNMessageResult` is returned in the [Listeners](#event-listeners).
:::

The `subscribe()` operation returns a `PNStatus` which contains the following operations:

| Method | Description |
| --- | --- |
| `getCategory()`Type: Enum of type `PNStatusCategory`. | See the [Android SDK listener categories](https://www.pubnub.com/docs/sdks/android/status-events). |
| `isError()`Type: Boolean | Is `true` in case of an error. |

The `subscribe()` operation returns a `PNMessageResult` for messages which contains the following operations:

| Method | Description |
| --- | --- |
| `getMessage()`Type: JsonElement | The message sent on the `channel`. |
| `getSubscription()`Type: String | The `channel group` or wildcard subscription match (if exists). |
| `getChannel()`Type: String | The `channel` for which the message belongs. |
| `getTimetoken()`Type: Long | `Timetoken` for the message. |
| `getUserMetadata()`Type: Object | User `metadata`. |

The `subscribe()` operation returns a `PNPresenceEventResult` from presence which contains the following operations:

| Method | Description |
| --- | --- |
| `getEvent()`Type: String | Events like `join`, `leave`, `timeout`, `state-change`, `interval`. |
| `getUuid()`Type: String | `UUID` for the event. |
| `getTimestamp()`Type: Long | `Timestamp` for the event. |
| `getOccupancy()`Type: Int | Current `occupancy`. |
| `getState()`Type: JsonElement | `State` of the `UUID`. |
| `getSubscription()`Type: String | The `channel group` or wildcard subscription match (if exists). |
| `getChannel()`Type: String | The `channel` for which the message belongs. |
| `getTimetoken()`Type: Long | `Timetoken` of the message. |
| `getUserMetadata()`Type: Object | User `metadata`. |

The `subscribe()` operation returns a `PNSignalResult` for signals which contains the following operations:

| Method | Description |
| --- | --- |
| `getMessage()`Type: JsonElement | The signal sent on the `channel`. |
| `getSubscription()`Type: String | The `channel group` or wildcard subscription match (if exists). |
| `getChannel()`Type: String | The `channel` for which the signal belongs. |
| `getTimetoken()`Type: Long | `Timetoken` for the signal. |
| `getUserMetadata()`Type: Object | User `metadata`. |

#### Other examples

##### Basic subscribe with logging

```java
PNConfiguration pnConfiguration = new PNConfiguration();
// subscribeKey from admin panel
pnConfiguration.setSubscribeKey("my_subkey"); // required
// publishKey from admin panel (only required if publishing)
pnConfiguration.setPublishKey("my_pubkey");
pnConfiguration.setLogVerbosity(PNLogVerbosity.BODY);
PubNub pubnub = new PubNub(pnConfiguration);

pubnub.subscribe()
    .channels(Arrays.asList("my_channel")) // subscribe to channels information
    .execute();
```

##### Subscribing to multiple channels

It's possible to subscribe to more than one channel using the [Multiplexing](https://www.pubnub.com/docs/general/channels/subscribe#channel-multiplexing) feature. The example shows how to do that using an array to specify the channel names.

:::note Alternative subscription methods
You can also use [Wildcard Subscribe](https://www.pubnub.com/docs/general/channels/subscribe#wildcard-subscribe) and [Channel Groups](https://www.pubnub.com/docs/general/channels/subscribe#channel-groups) to subscribe to multiple channels at a time. To use these features, the *Stream Controller* add-on must be enabled on your keyset in the [Admin Portal](https://admin.pubnub.com).
:::

```java
pubnub.subscribe()
    .channels(Arrays.asList("my_channel1","my_channel2" )) // subscribe to channels information
    .execute();
```

##### Subscribing to a Presence channel

:::warning Requires Message Persistence
This method requires that Message Persistence is [enabled](https://support.pubnub.com/hc/en-us/articles/360051974791-How-do-I-enable-add-on-features-for-my-keys-) for your key in the [Admin Portal](https://admin.pubnub.com/).
:::

For any given channel there is an associated Presence channel. You can subscribe directly to the channel by appending `-pnpres` to the channel name. For example the channel named `my_channel` would have the presence channel named `my_channel-pnpres`. Presence data can be observed inside the `SubscribeCallback#message(PubNub, PNMessageResult)` callback.

```java
pubnub.subscribe()
    .channels(Arrays.asList("my_channel")) // subscribe to channels
    .withPresence() // also subscribe to related presence information
    .execute();
```

##### Sample Responses

###### Join event

```java
if (presence.getEvent().equals("join")) {
    presence.getUuid(); // 175c2c67-b2a9-470d-8f4b-1db94f90e39e
    presence.getTimestamp(); // 1345546797
    presence.getOccupancy(); // 2
}
```

###### Leave event

```java
if (presence.getEvent().equals("leave")) {
    presence.getUuid(); // 175c2c67-b2a9-470d-8f4b-1db94f90e39e
    presence.getTimestamp(); // 1345546797
    presence.getOccupancy(); // 2
}
```

##### Timeout event

```java
if (presence.getEvent().equals("timeout")) {
    presence.getUuid(); // 175c2c67-b2a9-470d-8f4b-1db94f90e39e
    presence.getTimestamp(); // 1345546797
    presence.getOccupancy(); // 2
}
```

##### State change event

```json
{
    "action": "state-change",
    "uuid": "76c2c571-9a2b-d074-b4f8-e93e09f49bd",
    "timestamp": 1345549797,
    "data": {
        "isTyping": true
    }
}
```

##### Interval event

```java
if (presence.getEvent().equals("interval")) {
    presence.getUuid(); // 175c2c67-b2a9-470d-8f4b-1db94f90e39e
    presence.getTimestamp(); // 1345546797
    presence.getOccupancy(); // 2
}
```

When a channel is in interval mode with `presence_deltas` `pnconfig` flag enabled, the interval message may also include the following fields which contain an array of changed UUIDs since the last interval message. This settings can be altered in the [Admin Portal](https://admin.pubnub.com)

* joined
* left
* timedout

For example, this interval message indicates there were 2 new UUIDs that joined and 1 timed out UUID since the last interval:

```java
if (presence.getEvent().equals("interval")) {
    presence.getTimestamp(); // <unix timestamp>
    presence.getOccupancy(); // <# users in channel>
    presence.getJoin(); // ["uuid1", "uuid2"]
    presence.getTimeout(); // ["uuid3"]
}
```

If the full interval message is greater than `30 KB` (since the max publish payload is `∼32 KiB`), none of the extra fields will be present. Instead there will be a `here_now_refresh` boolean field set to `true`. This indicates to the user that they should do a `hereNow` request to get the complete list of users present in the channel.

```java
if (presence.getEvent().equals("interval")) {
    presence.getTimestamp(); // <unix timestamp>
    presence.getOccupancy(); // <# users in channel>
    presence.getHereNowRefresh() // true
}
```

##### Wildcard subscribe to channels

:::note Requires Stream Controller add-on
This method requires that the *Stream Controller* add-on is enabled for your key in the [Admin Portal](https://admin.pubnub.com/) (with Enable Wildcard Subscribe checked). Read the [support page](https://support.pubnub.com/hc/en-us/articles/360051974791-How-do-I-enable-add-on-features-for-my-keys-) on enabling add-on features on your keys.
:::

Wildcard subscribes allow the client to subscribe to multiple channels using wildcard. For example, if you subscribe to `a.*` you will get all messages for `a.b`, `a.c`, `a.x`. The wildcarded `*` portion refers to any portion of the channel string name after the `dot (.)`.

```java
pubnub.subscribe()
    .channels(Arrays.asList("foo.*")) // subscribe to channels information
    .execute();
```

:::note Wildcard grants and revokes
Only one level (`a.*`) of wildcarding is supported. If you grant on `*` or `a.b.*`, the grant will treat `*` or `a.b.*` as a single channel named either `*` or `a.b.*`. You can also revoke permissions from multiple channels using wildcards but only if you previously granted permissions using the same wildcards. Wildcard revokes, similarly to grants, only work one level deep, like `a.*`.
:::

##### Subscribing with state

:::warning Requires Presence
This method requires that the Presence add-on is [enabled](https://support.pubnub.com/hc/en-us/articles/360051974791-How-do-I-enable-add-on-features-for-my-keys-) for your key in the [Admin Portal](https://admin.pubnub.com/).
:::

:::note Required UUID
Always set the `UUID` to uniquely identify the user or device that connects to PubNub. This `UUID` should be persisted, and should remain unchanged for the lifetime of the user or the device. If you don't set the `UUID`, you won't be able to connect to PubNub.
:::

```java
PNConfiguration pnConfiguration = new PNConfiguration();
pnConfiguration.setSubscribeKey("demo");
pnConfiguration.setPublishKey("demo");

class complexData {
    String fieldA;
    int fieldB;
}

PubNub pubnub= new PubNub(pnConfiguration);

pubnub.addListener(new SubscribeCallback() {
    @Override
    public void status(PubNub pubnub, PNStatus status) {
        if (status.getCategory() == PNStatusCategory.PNConnectedCategory){
            complexData data = new complexData();
            data.fieldA = "Awesome";
            data.fieldB = 10;
            pubnub.setPresenceState()
                .channels(Arrays.asList("awesomeChannel"))
                .channelGroups(Arrays.asList("awesomeChannelGroup"))
                .state(data).async(new PNCallback<PNSetStateResult>() {
                    @Override
                    public void onResponse(PNSetStateResult result, PNStatus status) {
                        // handle set state response
                    }
                });
        }
    }

    @Override
    public void message(PubNub pubnub, PNMessageResult message) {

    }

    @Override
    public void presence(PubNub pubnub, PNPresenceEventResult presence) {

    }
});

pubnub.subscribe().channels(Arrays.asList("awesomeChannel"));
```

##### Subscribe to a channel group

:::note Requires Stream Controller add-on
This method requires that the *Stream Controller* add-on is enabled for your key in the [Admin Portal](https://admin.pubnub.com/). Read the [support page](https://support.pubnub.com/hc/en-us/articles/360051974791-How-do-I-enable-add-on-features-for-my-keys-) on enabling add-on features on your keys.
:::

```java
pubnub.subscribe()
    .channels(Arrays.asList("ch1", "ch2")) // subscribe to channels
    .channelGroups(Arrays.asList("cg1", "cg2")) // subscribe to channel groups
    .withTimetoken(1337L) // optional, pass a timetoken
    .withPresence() // also subscribe to related presence information
    .execute();
```

##### Subscribe to the Presence channel of a channel group

:::note Requires Stream Controller and Presence add-ons
This method requires both the *Stream Controller* and *Presence* add-ons are enabled for your key in the [Admin Portal](https://admin.pubnub.com/). Read the [support page](https://support.pubnub.com/hc/en-us/articles/360051974791-How-do-I-enable-add-on-features-for-my-keys-) on enabling add-on features on your keys.
:::

```java
pubnub.subscribe()
    .channelGroups(Arrays.asList("cg1", "cg2")) // subscribe to channel groups
    .withTimetoken(1337L) // optional, pass a timetoken
    .withPresence() // also subscribe to related presence information
    .execute();
```

#### Event listeners

You can be notified of connectivity status, message and presence notifications via the listeners.

Listeners should be added before calling the method.

##### Add listeners

```java
pubnub.addListener(new SubscribeCallback() {
    // PubNub status
    @Override
    public void status(PubNub pubnub, PNStatus status) {
        switch (status.getOperation()) {
            // combine unsubscribe and subscribe handling for ease of use
            case PNSubscribeOperation:
            case PNUnsubscribeOperation:
                // Note: subscribe statuses never have traditional errors,
                // just categories to represent different issues or successes
                // that occur as part of subscribe
                switch (status.getCategory()) {
                    case PNConnectedCategory:
                        // No error or issue whatsoever.
                    case PNReconnectedCategory:
                        // Subscribe temporarily failed but reconnected.
                        // There is no longer any issue.
                    case PNDisconnectedCategory:
                        // No error in unsubscribing from everything.
                    case PNUnexpectedDisconnectCategory:
                        // Usually an issue with the internet connection.
                        // This is an error: handle appropriately.
                    case PNAccessDeniedCategory:
                        // Access Manager does not allow this client to subscribe to this
                        // channel and channel group configuration. This is
                        // another explicit error.
                    default:
                        // You can directly specify more errors by creating
                        // explicit cases for other error categories of
                        // `PNStatusCategory` such as `PNTimeoutCategory` or
                        // `PNMalformedFilterExpressionCategory` or
                        // `PNDecryptionErrorCategory`.
                }

            case PNHeartbeatOperation:
                // Heartbeat operations can in fact have errors, so it's important to check first for an error.
                // For more information on how to configure heartbeat notifications through the status
                // PNObjectEventListener callback, refer to
                // /docs/sdks/android/api-reference/configuration#configuration_basic_usage
                if (status.isError()) {
                    // There was an error with the heartbeat operation, handle here
                } else {
                    // heartbeat operation was successful
                }
            default: {
                // Encountered unknown status type
            }
        }
    }

    // Messages
    @Override
    public void message(PubNub pubnub, PNMessageResult message) {
        String messagePublisher = message.getPublisher();
        System.out.println("Message publisher: " + messagePublisher);
        System.out.println("Message Payload: " + message.getMessage());
        System.out.println("Message Subscription: " + message.getSubscription());
        System.out.println("Message Channel: " + message.getChannel());
        System.out.println("Message timetoken: " + message.getTimetoken());
    }

    // Presence
    @Override
    public void presence(@NotNull PubNub pubnub, @NotNull PNPresenceEventResult presence) {
        System.out.println("Presence Event: " + presence.getEvent());
        // Can be join, leave, state-change or timeout

        System.out.println("Presence Channel: " + presence.getChannel());
        // The channel to which the message was published

        System.out.println("Presence Occupancy: " + presence.getOccupancy());
        // Number of users subscribed to the channel

        System.out.println("Presence State: " + presence.getState());
        // User state

        System.out.println("Presence UUID: " + presence.getUuid());
        // UUID to which this event is related

        presence.getJoin();
        // List of users that have joined the channel (if event is 'interval')

        presence.getLeave();
        // List of users that have left the channel (if event is 'interval')

        presence.getTimeout();
        // List of users that have timed-out off the channel (if event is 'interval')

        presence.getHereNowRefresh();
        // Indicates to the client that it should call 'hereNow()' to get the
        // complete list of users present in the channel.
    }

    // Signals
    @Override
    public void signal(PubNub pubnub, PNSignalResult pnSignalResult) {
        System.out.println("Signal publisher: " + signal.getPublisher());
        System.out.println("Signal payload: " + signal.getMessage());
        System.out.println("Signal subscription: " + signal.getSubscription());
        System.out.println("Signal channel: " + signal.getChannel());
        System.out.println("Signal timetoken: " + signal.getTimetoken());
    }

    // Message reactions
    @Override
    public void messageAction(PubNub pubnub, PNMessageActionResult pnActionResult) {
        PNMessageAction pnMessageAction = pnActionResult.getAction();
        System.out.println("Message reaction type: " + pnMessageAction.getType());
        System.out.println("Message reaction value: " + pnMessageAction.getValue());
        System.out.println("Message reaction uuid: " + pnMessageAction.getUuid());
        System.out.println("Message reaction actionTimetoken: " + pnMessageAction.getActionTimetoken());
        System.out.println("Message reaction messageTimetoken: " + pnMessageAction.getMessageTimetoken());]
        System.out.println("Message reaction subscription: " + pnActionResult.getSubscription());
        System.out.println("Message reaction channel: " + pnActionResult.getChannel());
        System.out.println("Message reaction timetoken: " + pnActionResult.getTimetoken());
    }

    // files
    @Override
    public void file(PubNub pubnub, PNFileEventResult pnFileEventResult) {
        System.out.println("File channel: " + pnFileEventResult.getChannel());
        System.out.println("File publisher: " + pnFileEventResult.getPublisher());
        System.out.println("File message: " + pnFileEventResult.getMessage());
        System.out.println("File timetoken: " + pnFileEventResult.getTimetoken());
        System.out.println("File file.id: " + pnFileEventResult.downloadFile().getId());
        System.out.println("File file.name: " + pnFileEventResult.downloadFile().getName());
        System.out.println("File file.url: " + pnFileEventResult.downloadFile().getUrl());
    }
});
```

##### Remove listeners

```java
SubscribeCallback subscribeCallback = new SubscribeCallback() {
    @Override
    public void status(PubNub pubnub, PNStatus status) {

    }

    @Override
    public void message(PubNub pubnub, PNMessageResult message) {

    }

    @Override
    public void presence(PubNub pubnub, PNPresenceEventResult presence) {

    }

    @Override
    public void signal(PubNub pubnub, PNSignalResult pnSignalResult) {

    }

    @Override
    public void messageAction(PubNub pubnub, PNMessageActionResult pnActionResult) {

    }

    @Override
    public void user(PubNub pubnub, PNUserResult pnUserResult) {

    }

    @Override
    public void space(PubNub pubnub, PNSpaceResult pnSpaceResult) {

    }

    @Override
    public void membership(PubNub pubnub, PNMembershipResult pnMembershipResult) {

    }

    @Override
    public void file(PubNub pubnub, PNFileEventResult pnFileEventResult) {

    }

};

pubnub.addListener(subscribeCallback);

// some time later
pubnub.removeListener(subscribeCallback);
```

##### Handling disconnects

```java
SubscribeCallback subscribeCallback = new SubscribeCallback() {
    @Override
    public void status(PubNub pubnub, PNStatus status) {
        if (status.getCategory() == PNStatusCategory.PNUnexpectedDisconnectCategory) {
            // internet got lost, do some magic and call reconnect when ready
            pubnub.reconnect();
        } else if (status.getCategory() == PNStatusCategory.PNTimeoutCategory) {
            // do some magic and call reconnect when ready
            pubnub.reconnect();
        } else {
            log.error(status);
        }
    }

    @Override
    public void message(PubNub pubnub, PNMessageResult message) {

    }

    @Override
    public void presence(PubNub pubnub, PNPresenceEventResult presence) {

    }
};

pubnub.addListener(subscribeCallback);
```

##### Listener status events

| Category | Description |
| --- | --- |
| `PNNetworkUpCategory` | The SDK detected that the network is online. |
| `PNNetworkDownCategory` | The SDK announces this when a connection isn't available, or when the SDK isn't able to reach PubNub servers. |
| `PNNetworkIssuesCategory` | A subscribe event experienced an exception when running. The SDK isn't able to reach PubNub servers. This may be due to many reasons, such as: the machine or device isn't connected to the internet; the internet connection has been lost; your internet service provider is having trouble; or, perhaps the SDK is behind a proxy. |
| `PNReconnectedCategory` | The SDK was able to reconnect to PubNub. |
| `PNConnectedCategory` | SDK subscribed with a new mix of channels. This is fired every time the channel or channel group mix changes. |
| `PNAccessDeniedCategory` | Access Manager permission failure. |
| `PNMalformedResponseCategory` | JSON parsing crashed. |
| `PNBadRequestCategory` | The server responded with a bad response error because the request is malformed. |
| `PNDecryptionErrorCategory` | If using decryption strategies and the decryption fails. |
| `PNTimeoutCategory` | Failure to establish a connection to PubNub due to a timeout. |
| `PNRequestMessageCountExceedCategory` | The SDK announces this error if `requestMessageCountThreshold` is set, and the number of messages received from PubNub (in-memory cache messages) exceeds the threshold. |
| `PNUnknownCategory` | Returned when the subscriber gets a non-200 HTTP response code from the server. |

## Unsubscribe (old)

:::warning Not recommended
The use of this method is discouraged. Use [Unsubscribe](#unsubscribe) instead.
:::

When subscribed to a single channel, this function causes the client to issue a `leave` from the `channel` and close any open socket to the PubNub Network. For multiplexed channels, the specified `channel`(s) will be removed and the socket remains open until there are no more channels remaining in the list.

:::warning Unsubscribing from all channels
**Unsubscribing** from all channels, and then **subscribing** to a new channel Y is not the same as subscribing to channel Y and then unsubscribing from the previously-subscribed channel(s). Unsubscribing from all channels resets the last-received `timetoken` and thus, there could be some gaps in the subscription that may lead to message loss.
:::

#### Method(s)

To `Unsubscribe from a channel` you can use the following method(s) in the Android SDK:

```java
pubnub.unsubscribe()
    .channels(Array)
    .channelGroups(Array)
    .execute();
```

| Parameter | Description |
| --- | --- |
| `channels`Type: Array | Unsubscribe to `channels`, Either `channel` or `channelGroup` is required |
| `channelGroups`Type: Array | Unsubscribe to channel groups, Either `channel` or `channelGroup` is required |
| `execute()` *Type: Command | Command that will `execute` `unsubscribe`. |

#### Sample code

Unsubscribe from a channel:

```java
pubnub.unsubscribe()
    .channels(Arrays.asList("my_channel"))
    .execute();
```

:::note Event listeners
The response of the call is handled by adding a Listener. Please see the [Listeners section](#event-listeners) for more details. Listeners should be added before calling the method.
:::

#### Response

The output below demonstrates the response to a successful call:

```java
@Override
public void presence(PubNub pubnub, PNPresenceEventResult presence) {
    if (presence.getEvent().equals("leave")) {
        presence.getTimestamp(); // 1345546797
        presence.getOccupancy(); // 2
        presence.getUuid(); // left_uuid
    }
}
```

#### Other examples

##### Unsubscribing from multiple channels

:::note Requires Stream Controller add-on
This method requires that the *Stream Controller* add-on is enabled for your key in the [Admin Portal](https://admin.pubnub.com/). Read the [support page](https://support.pubnub.com/hc/en-us/articles/360051974791-How-do-I-enable-add-on-features-for-my-keys-) on enabling add-on features on your keys.
:::

```java
pubnub.unsubscribe()
    .channels(Arrays.asList("ch1", "ch2", "ch3"))
    .channelGroups(Arrays.asList("cg1", "cg2", "cg3"))
    .execute();
```

###### Example response

```java
@Override
public void presence(PubNub pubnub, PNPresenceEventResult presence) {
    if (presence.getEvent().equals("leave")) {
        presence.getTimestamp(); // 1345546797
        presence.getOccupancy(); // 2
        presence.getUuid(); // left_uuid
    }
}
```

##### Unsubscribe from a channel group

```java
pubnub.unsubscribe()
    .channelGroups(Arrays.asList("cg1", "cg2", "cg3"))
    .execute();
```

###### Example response

```java
@Override
public void presence(PubNub pubnub, PNPresenceEventResult presence) {
    if (presence.getEvent().equals("leave")) {
        presence.getTimestamp(); // 1345546797
        presence.getOccupancy(); // 2
        presence.getUuid(); // left_uuid
    }
}
```

## Unsubscribe all (old)

:::warning Not recommended
The use of this method is discouraged. Use [Unsubscribe All](#unsubscribe-all) instead.
:::

Unsubscribe from all channels and all channel groups

#### Method(s)

```java
public final void unsubscribeAll()
```

#### Sample code

```java
pubnub.unsubscribeAll();
```

#### Returns

None