Audience Polls during Live Stream - Android
Interactive polls are a great way to increase engagement during livestreams. Using VideoSDK’s PubSub mechanism, you can easily implement real-time audience polling, where viewers can vote and the host can see live results instantly.
This guide walks you through how to create, send, and visualize poll results during a livestream.
Step 1: Creating and Publishing a Poll
To initiate a poll, use the PubSub class with a POLL topic. The poll structure should include a question and multiple options. This message will be published to all participants.
- Kotlin
- Java
class CreatePollDialog() {
companion object {
const val POLL_TOPIC = "POLL"
}
fun show() {
// ... UI setup code ...
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener {
// Validate inputs
// Create poll object
val options = mutableListOf(option1, option2)
if (option3.isNotEmpty()) options.add(option3)
if (option4.isNotEmpty()) options.add(option4)
val poll = SimplePoll(question, options)
// Publish poll to all participants
val pubSubPublishOptions = PubSubPublishOptions()
pubSubPublishOptions.isPersist = true
liveStream.pubSub.publish(POLL_TOPIC, poll.toJsonString(), pubSubPublishOptions)
// Show results dialog to host
PollResultsDialog(context, liveStream).show(poll)
dialog.dismiss()
}
}
}
public class CreatePollDialog {
public static final String POLL_TOPIC = "POLL";
public CreatePollDialog() {
// default constructor
}
public void show() {
// ... UI setup code ...
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(v -> {
// Validate inputs
// Create poll object
List<String> options = new ArrayList<>();
options.add(option1);
options.add(option2);
if (!option3.isEmpty()) options.add(option3);
if (!option4.isEmpty()) options.add(option4);
SimplePoll poll = new SimplePoll(question, options);
// Publish poll to all participants
PubSubPublishOptions pubSubPublishOptions = new PubSubPublishOptions();
pubSubPublishOptions.setPersist(true);
liveStream.pubSub.publish(POLL_TOPIC, poll.toJsonString(), pubSubPublishOptions);
// Show results dialog to host
new PollResultsDialog(context, liveStream).show(poll);
dialog.dismiss();
});
}
}
Step 2: Subscribing to Polls and Displaying Options
Participants can listen to the POLL topic and render voting options dynamically based on the incoming data. The senderId of the received poll message identifies the host. Publish the vote with sendOnly set to that id, so only the host receives it and other participants can't see who voted for what.
- Kotlin
- Java
class PollVotingDialog() {
companion object {
const val POLL_RESPONSE_TOPIC = "POLL_RESPONSE"
}
// hostId is the senderId of the received POLL message (message.senderId)
fun show(poll: SimplePoll, hostId: String) {
// ... UI setup code ...
// Create option buttons dynamically
poll.options.forEach { option ->
val button = Button(context)
button.text = option
button.setOnClickListener {
// Submit vote
val response = SimplePollResponse(
pollId = poll.id,
option = option,
participantId = liveStream.localParticipant.id,
participantName = liveStream.localParticipant.displayName
)
val publishOptions = PubSubPublishOptions()
val sendOnly: Array<String> = arrayOf(hostId)
publishOptions.setSendOnly(sendOnly)
liveStream.pubSub.publish(POLL_RESPONSE_TOPIC, response.toJsonString(), publishOptions)
// Disable all buttons after voting
for (i in 0 until optionsContainer.childCount) {
optionsContainer.getChildAt(i).isEnabled = false
}
}
optionsContainer.addView(button)
}
}
}
public class PollVotingDialog {
public static final String POLL_RESPONSE_TOPIC = "POLL_RESPONSE";
// hostId is the senderId of the received POLL message (message.getSenderId())
public void show(SimplePoll poll, String hostId) {
// ... UI setup code ...
// Create option buttons dynamically
for (String option : poll.getOptions()) {
Button button = new Button(context);
button.setText(option);
button.setOnClickListener(v -> {
// Submit vote
SimplePollResponse response = new SimplePollResponse(
poll.getId(),
option,
liveStream.getLocalParticipant().getId(),
liveStream.getLocalParticipant().getDisplayName()
);
PubSubPublishOptions publishOptions = new PubSubPublishOptions();
String[] sendOnly = { hostId };
publishOptions.setSendOnly(sendOnly);
liveStream.pubSub.publish(POLL_RESPONSE_TOPIC, response.toJsonString(), publishOptions);
// Disable all buttons after voting
for (int i = 0; i < optionsContainer.getChildCount(); i++) {
optionsContainer.getChildAt(i).setEnabled(false);
}
});
optionsContainer.addView(button);
}
}
}
Step 3: Aggregating and Displaying Poll Results
The host can subscribe to the POLL_RESPONSE topic to collect responses and render the result in real-time.
- Kotlin
- Java
class PollResultsDialog() {
private val pollResults = ConcurrentHashMap<String, Int>()
private var totalVotes = 0
companion object {
const val POLL_RESPONSE_TOPIC = "POLL_RESPONSE"
}
fun show(poll: SimplePoll) {
// ... UI setup code ...
// Initialize results map with 0 votes for each option
poll.options.forEach { option ->
pollResults[option] = 0
}
// Create initial result bars
updateResultBars()
// Listen for poll responses
responsesListener = object : PubSubMessageListener {
override fun onMessageReceived(pubSubMessage: PubSubMessage) {
try {
val response = SimplePollResponse.fromJsonString(pubSubMessage.message)
val option = response.option
// Update vote count
pollResults[option] = (pollResults[option] ?: 0) + 1
totalVotes++
// Update UI on main thread
(context as? android.app.Activity)?.runOnUiThread {
updateResultBars()
}
} catch (e: Exception) {
e.printStackTrace()
}
}
override fun onOldMessagesReceived(messages: List<PubSubMessage>) {
// Persisted message list
Log.d("VideoSDK", "messages: $messages")
}
}
// Subscribe to poll responses
liveStream.pubSub.subscribe(POLL_RESPONSE_TOPIC, responsesListener)
}
private fun updateResultBars() {
// Clear previous results
optionsContainer?.removeAllViews()
// Create result bars for each option
pollResults.forEach { (option, votes) ->
val percentage = if (totalVotes > 0) (votes * 100) / totalVotes else 0
// Create progress bar UI showing percentage
// ... UI code to display results ...
}
}
}
import java.util.concurrent.ConcurrentHashMap;
import java.util.Map;
public class PollResultsDialog {
private ConcurrentHashMap<String, Integer> pollResults = new ConcurrentHashMap<>();
private int totalVotes = 0;
public static final String POLL_RESPONSE_TOPIC = "POLL_RESPONSE";
public void show(SimplePoll poll) {
// ... UI setup code ...
// Initialize results map with 0 votes for each option
for (String option : poll.options) {
pollResults.put(option, 0);
}
// Create initial result bars
updateResultBars();
// Listen for poll responses
responsesListener = new PubSubMessageListener() {
@Override
public void onMessageReceived(PubSubMessage PubSubMessage) {
try {
SimplePollResponse response = SimplePollResponse.fromJsonString(pubSubMessage.message);
String option = response.option;
// Update vote count
pollResults.put(option, pollResults.getOrDefault(option, 0) + 1);
totalVotes++;
// Update UI on main thread
if (context instanceof android.app.Activity) {
((android.app.Activity) context).runOnUiThread(new Runnable() {
@Override
public void run() {
updateResultBars();
}
});
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onOldMessagesReceived(List<PubSubMessage> messages) {
// Persisted message list
Log.d("VideoSDK", "onOldMessagesReceived: " + messages);
}
};
// Subscribe to poll responses
liveStream.pubSub.subscribe(POLL_RESPONSE_TOPIC, responsesListener);
}
private void updateResultBars() {
// Clear previous results
if (optionsContainer != null) {
optionsContainer.removeAllViews();
}
// Create result bars for each option
for (Map.Entry<String, Integer> entry : pollResults.entrySet()) {
String option = entry.getKey();
int votes = entry.getValue();
int percentage = (totalVotes > 0) ? (votes * 100) / totalVotes : 0;
// Create progress bar UI showing percentage
// ... UI code to display results ...
}
}
}
API Reference
The API references for all the methods and events utilized in this guide are provided below.
Got a Question? Ask us on discord

