在可捲動的動態饋給中重複使用橫幅廣告

在新聞動態或社群動態等長或無限捲動清單中,為每個項目位置建立橫幅廣告可能會導致記憶體消耗量過高和 UI 延遲。為提升效能,請使用橫幅廣告回收機制,維持 BannerAd 執行個體的小型固定大小快取,並在使用者捲動時重複使用螢幕外的廣告。

本頁面說明如何調整廣告快取大小、檢查 BannerAd 執行個體是否位於螢幕外,以及將快取廣告重新指派給清單位置。

下圖顯示螢幕外的橫幅廣告如何返回快取,並在使用者捲動時於清單位置重複使用:

圖表:橫幅廣告從螢幕外捲動至廣告快取,並在螢幕上動態消息的底部重複使用。

必要條件

繼續操作前,請先在可捲動內容中使用內嵌自動調整橫幅廣告。

追蹤指派的清單位置

當使用者捲動時,橫幅回收機制會在記憶體中保留有限數量的 BannerAd 執行個體,並在清單位置之間移動這些執行個體。

如要瞭解要重複使用哪個廣告,請追蹤快取中每個廣告佔用的清單位置。

在小工具中維持下列狀態:

  • BannerAd 執行個體的固定大小快取。您設定的快取大小,就是記憶體一次可保留的廣告數量上限。
  • 廣告間隔,決定廣告在清單中的顯示頻率。
  • 位置 Map 類別,可將每個 BannerAd 例項與例項佔用的清單位置建立關聯。回收廣告時,請更新這個 Map 類別中的項目,指向最新位置。
  • 大小 Map 類別,用於儲存每個已載入廣告的平台解析 AdSize 物件。廣告載入後,系統就會知道內嵌自動調整橫幅廣告的高度。

以下範例會追蹤快取中每個廣告的指派清單位置:

// Maximum number of banner ad instances kept in the cache.
static const int _cacheSize = 8;

// Spacing between banner ads. For example, index 0, 6, 12, and so on
// display ads.
static const int _adInterval = 6;

// The cache of allocated BannerAd instances.
final List<BannerAd> _banners = [];

// Maps each BannerAd instance to its currently assigned list item position.
final Map<BannerAd, int> _bannerPositions = {};

// Stores the platform-resolved size of each loaded banner ad.
final Map<BannerAd, AdSize> _bannerSizes = {};

選擇快取大小

將快取大小設為大於可同時顯示在畫面上的廣告數量上限。如果快取小於該大小,選取用於回收的廣告通常仍會顯示,且應用程式會分配額外廣告,而不是重複使用廣告。

如要選擇大小,請按照下列步驟操作:

  1. 將可視區域高度除以一個廣告間隔的高度,即可估算畫面一次可顯示多少廣告。
  2. 在快速捲動期間,為仍在卸載的廣告新增空間。
  3. 如果發現選取要回收的廣告仍在畫面上,請增加快取大小。

本頁的範例每六列會顯示一則廣告,並使用八個項目的快取。這個範例會為螢幕上同時顯示的少數廣告保留空間。

檢查廣告是否顯示在畫面上

所有用於算繪平台檢視區塊的 Google Mobile Ads Flutter Plugin 類別都會導入 AdWithView 類別,並提供 isMounted getter。將快取廣告重新指派給清單位置前,請檢查 isMounted 擷取器,確認廣告已捲動至螢幕外,可安全重複使用。

擷取及回收橫幅廣告

當清單要求特定位置的橫幅時,請執行下列操作:

  1. 重複使用已指派給該位置的廣告 (如有)。
  2. 如果快取未滿,請請求廣告。
  3. 如果快取已滿,請選取快取廣告,並在重新指派廣告前,確認 isMounted getter 是 false 值。
  4. 當小工具從小工具樹狀結構中移除時,請對快取中的每個廣告呼叫 dispose() 方法。

以下範例會擷取並回收橫幅廣告:

BannerAd _getRecycledBannerAd(BuildContext context, int bannerPosition) {
  // 1. If an ad is already mapped to this position, reuse it.
  final BannerAd? existingBanner = _bannerPositions.entries
      .firstWhereOrNull((entry) => entry.value == bannerPosition)
      ?.key;
  if (existingBanner != null) {
    return existingBanner;
  }

  // 2. If the cache is not full, allocate a new ad instance.
  if (_banners.length < _cacheSize) {
    final BannerAd newBanner = _createBannerAd(context);
    _banners.add(newBanner);
    _bannerPositions[newBanner] = bannerPosition;
    return newBanner;
  }

  // 3. Select an existing ad from the cache using modulo arithmetic.
  final BannerAd targetBanner = _banners[bannerPosition % _cacheSize];

  // 4. Verify the ad is detached from the screen before recycling.
  if (targetBanner.isMounted) {
    // If still on screen during fast scrolls, allocate a temporary instance.
    return _createBannerAd(context);
  } else {
    // Safe to reuse: reassign to the new position.
    _bannerPositions[targetBanner] = bannerPosition;
    return targetBanner;
  }
}

如需完整範例,請參閱 Google Mobile Ads Flutter Plugin 範例。