스크롤 가능한 피드에서 배너 광고 재활용

뉴스 피드나 소셜 피드와 같이 길거나 무한 스크롤 목록에서 모든 항목 위치에 배너 광고를 만들면 메모리 소비가 많아지고 UI 지연이 발생할 수 있습니다. 성능 향상을 위해 배너 재활용을 사용하여 BannerAd 인스턴스의 작고 고정된 크기의 캐시를 유지하고 사용자가 스크롤할 때 화면 밖 광고를 재사용하세요.

이 페이지에서는 광고 캐시 크기 조정, BannerAd 인스턴스가 화면에 표시되지 않는지 확인, 캐시된 광고를 목록 위치에 다시 할당하는 방법을 설명합니다.

다음 이미지는 사용자가 스크롤할 때 화면 밖 배너 광고가 캐시로 돌아가 목록 위치에서 재사용되는 방식을 보여줍니다.

배너 광고가 화면 밖으로 스크롤되어 광고 캐시로 이동하고 화면 피드 하단에서 재사용되는 것을 보여주는 다이어그램

기본 요건

계속하기 전에 스크롤 배너에 인라인 적응형을 사용하세요.

할당된 목록 위치 추적

사용자가 스크롤하면 배너 재활용은 제한된 수의 BannerAd 인스턴스를 메모리에 유지하고 이러한 인스턴스를 목록 위치 간에 이동합니다.

재사용할 광고를 알기 위해 캐시에 있는 각 광고가 차지하는 목록 위치를 추적합니다.

위젯에서 다음 상태를 유지합니다.

  • BannerAd 인스턴스의 고정 크기 캐시입니다. 캐시를 설정한 크기는 한 번에 메모리에 보관되는 최대 광고 수입니다.
  • 목록에 광고가 표시되는 빈도를 결정하는 광고 간격입니다.
  • 각 BannerAd 인스턴스를 인스턴스가 차지하는 목록 위치와 연결하는 위치 Map 클래스 광고를 재활용할 때는 이 Map 클래스의 항목을 업데이트하여 최신 위치를 가리키도록 합니다.
  • 로드된 각 광고의 플랫폼에서 확인된 AdSize 객체를 저장하는 크기 Map 클래스입니다. 광고가 로드된 후 인라인 적응형 배너 높이를 알 수 있습니다.

다음 예에서는 캐시에 있는 각 광고의 할당된 목록 위치를 추적합니다.

// 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. 재활용하도록 선택한 광고가 여전히 화면에 표시되면 캐시 크기를 늘립니다.

이 페이지의 예에서는 6행마다 광고를 표시하고 8개의 캐시를 사용합니다. 이 예에서는 화면에 한 번에 표시되는 몇 개의 광고를 위한 공간을 남겨 둡니다.

광고가 화면에 표시되는지 확인

플랫폼 뷰를 렌더링하는 모든 Google Mobile Ads Flutter Plugin 클래스는 AdWithView 클래스를 구현하고 isMounted getter를 제공합니다. 캐시된 광고를 목록 위치에 다시 할당하기 전에 isMounted getter를 확인하여 광고가 화면 밖으로 스크롤되었으며 재사용해도 안전한지 확인합니다.

배너 광고 가져오기 및 재활용

목록에서 특정 위치의 배너를 요청하는 경우 다음을 실행합니다.

  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 예시를 참고하세요.