Displaying Ads
The Growl SDK provides a complete adapter system for displaying ads inline with your chat messages. This guide covers the recommended approach using GrowlChatListAdapter.
Overview
Section titled “Overview”The SDK provides two adapter options:
| Adapter | Description | Use Case |
|---|---|---|
GrowlChatListAdapter | Uses DiffUtil for efficient updates with animations | Recommended for most apps |
GrowlChatRecyclerAdapter | Basic adapter requiring manual notifications | Legacy support or custom needs |
Both adapters handle:
- Rendering your custom message views
- Rendering ad views automatically
- Loading ads based on chat context
- Caching loaded ads to prevent re-fetching on scroll
Setting Up the Adapter
Section titled “Setting Up the Adapter”Step 1: Define Your Message Class
Section titled “Step 1: Define Your Message Class”Your message data class must extend ChatItem.MessageItem:
import com.withgrowl.growlandroidsdk.MessageRoleimport com.withgrowl.growlandroidsdk.models.ChatItemimport java.util.UUID
data class Message( override val chatItemId: String = UUID.randomUUID().toString(), val sender: MessageRole, val text: String, val timestamp: Long = System.currentTimeMillis()) : ChatItem.MessageItem(chatItemId)Step 2: Create Your MessageViewHolder
Section titled “Step 2: Create Your MessageViewHolder”Extend the SDK’s abstract MessageViewHolder class:
import com.withgrowl.growlandroidsdk.MessageRoleimport com.withgrowl.growlandroidsdk.recycler.MessageViewHolder
class MyMessageViewHolder( private val binding: ItemChatMessageBinding) : MessageViewHolder<Message>(binding.root) {
override fun bind(messageItem: Message, position: Int) { binding.textViewMessage.text = messageItem.text
// Style based on sender if (messageItem.sender == MessageRole.USER) { binding.textViewMessage.setBackgroundResource(R.drawable.bubble_user) // Align to right } else { binding.textViewMessage.setBackgroundResource(R.drawable.bubble_assistant) // Align to left } }}Step 3: Initialize the Adapter
Section titled “Step 3: Initialize the Adapter”import com.withgrowl.growlandroidsdk.GrowlAdViewimport com.withgrowl.growlandroidsdk.models.ChatMessageimport com.withgrowl.growlandroidsdk.recycler.GrowlChatListAdapterimport androidx.core.graphics.toColorInt
class ChatFragment : Fragment() { private lateinit var adapter: GrowlChatListAdapter private val chatItems = mutableListOf<ChatItem>()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState)
adapter = GrowlChatListAdapter( adUnitId = AD_UNIT_ID, publisherId = PUBLISHER_ID, chatId = chatId, createMessageViewHolder = { parent -> val binding = ItemChatMessageBinding.inflate( LayoutInflater.from(parent.context), parent, false ) MyMessageViewHolder(binding) }, getChatHistory = { getChatHistoryForAds() }, stylingParams = GrowlAdView.StylingParams( background = "#1C1E22".toColorInt(), text = "#EEEEEE".toColorInt(), border = "#2F2F2F".toColorInt(), borderWidth = 1 ) )
binding.recyclerView.layoutManager = LinearLayoutManager(requireContext()) binding.recyclerView.adapter = adapter }
private fun getChatHistoryForAds(): List<ChatMessage> { return chatItems .filterIsInstance<Message>() .map { ChatMessage(role = it.sender.roleName, content = it.text) } }}import com.withgrowl.growlandroidsdk.recycler.GrowlChatRecyclerAdapter
adapter = GrowlChatRecyclerAdapter( adUnitId = AD_UNIT_ID, publisherId = PUBLISHER_ID, chatId = chatId, items = chatItems, // Pass your list directly createMessageViewHolder = { parent -> val binding = ItemChatMessageBinding.inflate( LayoutInflater.from(parent.context), parent, false ) MyMessageViewHolder(binding) }, getChatHistory = { getChatHistoryForAds() }, stylingParams = GrowlAdView.StylingParams(...))
// Manual notifications required:// adapter.notifyItemInserted(position)// adapter.notifyDataSetChanged()Managing Chat Items
Section titled “Managing Chat Items”Adding Messages
Section titled “Adding Messages”// Add a user messageval userMessage = Message( sender = MessageRole.USER, text = userInput)chatItems.add(userMessage)
// Add AI responseval aiMessage = Message( sender = MessageRole.ASSISTANT, text = aiResponse)chatItems.add(aiMessage)
// Submit updated list (GrowlChatListAdapter)adapter.submitList(chatItems.toList())Inserting Ad Slots
Section titled “Inserting Ad Slots”Insert ChatItem.AdItem() where you want ads to appear:
private fun fetchAndInsertAdIfAvailable() { lifecycleScope.launch { val ad = GrowlAdSDK.fetchAdForChat( context = requireContext(), chatHistory = chatHistory, publisherId = PUBLISHER_ID, adUnitId = AD_UNIT_ID, chatId = dashboardViewModel.chatId )
if (ad != null) { // Add an ad slot chatItems.add(ChatItem.AdItem( hasAttemptedLoad = true, loadedAd = ad ))
// Submit the updated list adapter.submitList(chatItems.toList()) // Scroll to bottom binding.recyclerView.scrollToPosition(chatItems.size - 1) } }}Complete Flow Example
Section titled “Complete Flow Example”private fun sendMessage(userInput: String) { // 1. Add user message chatItems.add(Message(sender = MessageRole.USER, text = userInput)) adapter.submitList(chatItems.toList())
// 2. Get AI response lifecycleScope.launch { val response = getAIResponse(userInput)
// 3. Add AI message chatItems.add(Message(sender = MessageRole.ASSISTANT, text = response))
// 4. Add ad slot if needed fetchAndInsertAdIfAvailable() }}Customizing Ad Appearance
Section titled “Customizing Ad Appearance”StylingParams
Section titled “StylingParams”Customize ad appearance using StylingParams:
import com.withgrowl.growlandroidsdk.GrowlAdViewimport androidx.core.graphics.toColorInt
val styling = GrowlAdView.StylingParams( background = "#1C1E22".toColorInt(), // Card background text = "#EEEEEE".toColorInt(), // Title and description border = "#2F2F2F".toColorInt(), // Card border borderWidth = 1 // Border width in dp)| Parameter | Type | Description |
|---|---|---|
background | Int? | Card background color |
text | Int? | Text color for title and description |
border | Int? | Card border/stroke color |
borderWidth | Int? | Border width in dp |
Dark Theme Example
Section titled “Dark Theme Example”GrowlAdView.StylingParams( background = "#121212".toColorInt(), text = "#E0E0E0".toColorInt(), border = "#333333".toColorInt(), borderWidth = 1)Light Theme Example
Section titled “Light Theme Example”GrowlAdView.StylingParams( background = "#FFFFFF".toColorInt(), text = "#212121".toColorInt(), border = "#E0E0E0".toColorInt(), borderWidth = 1)How Ad Loading Works
Section titled “How Ad Loading Works”- When a
ChatItem.AdItemis bound in the RecyclerView, the SDK automatically callsloadAds() - The
getChatHistoryfunction provides conversation context for ad targeting - Loaded ads are cached in
AdItem.loadedAdto prevent re-fetching on scroll - If no ad is available, the ad view is hidden automatically
Using GrowlAdView Directly
Section titled “Using GrowlAdView Directly”For non-chat scenarios, you can use GrowlAdView directly:
<com.withgrowl.growlandroidsdk.GrowlAdView android:id="@+id/growlAdView" android:layout_width="match_parent" android:layout_height="wrap_content" />val growlAdView = binding.growlAdView
// Apply stylinggrowlAdView.applyStyling(GrowlAdView.StylingParams( background = "#1C1E22".toColorInt(), text = "#EEEEEE".toColorInt()))
// Load adslifecycleScope.launch { growlAdView.loadAds( chatHistory = getChatHistory(), publisherId = PUBLISHER_ID, adUnitId = AD_UNIT_ID, chatId = chatId, callback = object : AdLoadCallback { override fun onAdsLoaded(ads: List<Ad>) { Log.d(TAG, "Loaded ${ads.size} ads") } override fun onError(error: String) { Log.e(TAG, "Error: $error") } } )}ChatItem Types
Section titled “ChatItem Types”The SDK provides a sealed class for type-safe chat items:
sealed class ChatItem { abstract val chatItemId: String
// Extend this for your messages abstract class MessageItem(chatItemId: String) : ChatItem()
// Use this for ad slots data class AdItem( override val chatItemId: String = UUID.randomUUID().toString(), var hasAttemptedLoad: Boolean = false, var loadedAd: Ad? = null ) : ChatItem()}Your message class extends MessageItem, and you use AdItem directly for ad slots.