> ## Documentation Index
> Fetch the complete documentation index at: https://docs.adrop.io/llms.txt
> Use this file to discover all available pages before exploring further.

# バナー広告

> Androidアプリでバナー広告を実装する方法をご案内します。

## 概要

バナー広告は画面の一部に表示される矩形の広告です。XMLレイアウトとコードの両方で使用できます。

### 主な特徴

* 画面の上部、下部、または中央に固定配置可能
* 画像および動画広告に対応
* XMLレイアウトとプログラム方式の両方に対応
* リスナーによる広告イベント処理

<Note>
  開発環境ではテストユニットIDを使用してください：`PUBLIC_TEST_UNIT_ID_320_100`
</Note>

***

## XMLレイアウト実装

XMLレイアウトで`AdropBanner`を定義し、ActivityまたはFragmentからロードする方式です。

### 1. XMLレイアウト定義

`FrameLayout`または他のコンテナに`AdropBanner`を配置します。

```xml activity_main.xml theme={null}
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!-- メインコンテンツ -->
    <TextView
        android:id="@+id/content"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="メインコンテンツ"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />

    <!-- バナー広告コンテナ -->
    <FrameLayout
        android:id="@+id/banner_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent">

        <io.adrop.ads.banner.AdropBanner
            android:id="@+id/adrop_banner"
            android:layout_width="320dp"
            android:layout_height="100dp"
            android:layout_gravity="center"
            app:adrop_unit_id="YOUR_UNIT_ID" />

    </FrameLayout>

</androidx.constraintlayout.widget.ConstraintLayout>
```

### 2. Activityからロード

<CodeGroup>
  ```kotlin Kotlin theme={null}
  import android.os.Bundle
  import androidx.appcompat.app.AppCompatActivity
  import io.adrop.ads.banner.AdropBanner
  import io.adrop.ads.banner.AdropBannerListener
  import io.adrop.ads.model.AdropErrorCode

  class MainActivity : AppCompatActivity() {
      private var banner: AdropBanner? = null

      override fun onCreate(savedInstanceState: Bundle?) {
          super.onCreate(savedInstanceState)
          setContentView(R.layout.activity_main)

          // 1. XMLで定義したバナービューを取得
          banner = findViewById(R.id.adrop_banner)

          // 2. リスナー設定
          banner?.listener = object : AdropBannerListener {
              override fun onAdReceived(banner: AdropBanner) {
                  println("バナー広告の受信成功")
              }

              override fun onAdFailedToReceive(banner: AdropBanner, errorCode: AdropErrorCode) {
                  println("バナー広告の受信失敗: $errorCode")
              }

              override fun onAdImpression(banner: AdropBanner) {
                  println("バナー広告のインプレッション")
              }

              override fun onAdClicked(banner: AdropBanner) {
                  println("バナー広告がクリックされました")
              }
          }

          // 3. 広告をロード
          banner?.load()
      }

      override fun onDestroy() {
          super.onDestroy()
          // 4. メモリ解放
          banner?.destroy()
          banner = null
      }
  }
  ```

  ```java Java theme={null}
  import android.os.Bundle;
  import androidx.appcompat.app.AppCompatActivity;
  import io.adrop.ads.banner.AdropBanner;
  import io.adrop.ads.banner.AdropBannerListener;
  import io.adrop.ads.model.AdropErrorCode;
  import org.jetbrains.annotations.NotNull;

  public class MainActivity extends AppCompatActivity {
      private AdropBanner banner;

      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_main);

          // 1. XMLで定義したバナービューを取得
          banner = findViewById(R.id.adrop_banner);

          // 2. リスナー設定
          banner.setListener(new AdropBannerListener() {
              @Override
              public void onAdReceived(@NotNull AdropBanner banner) {
                  System.out.println("バナー広告の受信成功");
              }

              @Override
              public void onAdFailedToReceive(@NotNull AdropBanner banner, @NotNull AdropErrorCode errorCode) {
                  System.out.println("バナー広告の受信失敗: " + errorCode);
              }

              @Override
              public void onAdImpression(@NotNull AdropBanner banner) {
                  System.out.println("バナー広告のインプレッション");
              }

              @Override
              public void onAdClicked(@NotNull AdropBanner banner) {
                  System.out.println("バナー広告がクリックされました");
              }
          });

          // 3. 広告をロード
          banner.load();
      }

      @Override
      protected void onDestroy() {
          super.onDestroy();
          // 4. メモリ解放
          if (banner != null) {
              banner.destroy();
              banner = null;
          }
      }
  }
  ```
</CodeGroup>

### XML属性

| 属性                      | 説明                      |  必須 |
| ----------------------- | ----------------------- | :-: |
| `app:adrop_unit_id`     | 広告ユニットID                |  O  |
| `app:adrop_context_id`  | コンテキストターゲティング用のコンテキストID |     |
| `android:layout_width`  | バナーの幅 (dp)              |  O  |
| `android:layout_height` | バナーの高さ (dp)             |  O  |

***

## プログラム方式での実装

コードで直接`AdropBanner`インスタンスを作成してビューに追加する方式です。

<CodeGroup>
  ```kotlin Kotlin theme={null}
  import android.os.Bundle
  import android.widget.FrameLayout
  import androidx.appcompat.app.AppCompatActivity
  import io.adrop.ads.banner.AdropBanner
  import io.adrop.ads.banner.AdropBannerListener
  import io.adrop.ads.model.AdropErrorCode

  class MainActivity : AppCompatActivity() {
      private var banner: AdropBanner? = null

      override fun onCreate(savedInstanceState: Bundle?) {
          super.onCreate(savedInstanceState)
          setContentView(R.layout.activity_main)

          // 1. バナーインスタンスを作成
          banner = AdropBanner(this, "YOUR_UNIT_ID").apply {
              // 2. リスナー設定
              listener = object : AdropBannerListener {
                  override fun onAdReceived(banner: AdropBanner) {
                      println("バナー広告の受信成功")
                  }

                  override fun onAdFailedToReceive(banner: AdropBanner, errorCode: AdropErrorCode) {
                      println("バナー広告の受信失敗: $errorCode")
                  }

                  override fun onAdImpression(banner: AdropBanner) {
                      println("バナー広告のインプレッション")
                  }

                  override fun onAdClicked(banner: AdropBanner) {
                      println("バナー広告がクリックされました")
                  }
              }
          }

          // 3. ビュー階層に追加
          val container = findViewById<FrameLayout>(R.id.banner_container)
          val params = FrameLayout.LayoutParams(
              FrameLayout.LayoutParams.MATCH_PARENT,
              FrameLayout.LayoutParams.WRAP_CONTENT
          )
          container.addView(banner, params)

          // 4. 広告をロード
          banner?.load()
      }

      override fun onDestroy() {
          super.onDestroy()
          // 5. メモリ解放
          banner?.destroy()
          banner = null
      }
  }
  ```

  ```java Java theme={null}
  import android.os.Bundle;
  import android.widget.FrameLayout;
  import androidx.appcompat.app.AppCompatActivity;
  import io.adrop.ads.banner.AdropBanner;
  import io.adrop.ads.banner.AdropBannerListener;
  import io.adrop.ads.model.AdropErrorCode;
  import org.jetbrains.annotations.NotNull;

  public class MainActivity extends AppCompatActivity {
      private AdropBanner banner;

      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_main);

          // 1. バナーインスタンスを作成（unitIdはコンストラクタで必須）
          banner = new AdropBanner(this, "YOUR_UNIT_ID");

          // 2. リスナー設定
          banner.setListener(new AdropBannerListener() {
              @Override
              public void onAdReceived(@NotNull AdropBanner banner) {
                  System.out.println("バナー広告の受信成功");
              }

              @Override
              public void onAdFailedToReceive(@NotNull AdropBanner banner, @NotNull AdropErrorCode errorCode) {
                  System.out.println("バナー広告の受信失敗: " + errorCode);
              }

              @Override
              public void onAdImpression(@NotNull AdropBanner banner) {
                  System.out.println("バナー広告のインプレッション");
              }

              @Override
              public void onAdClicked(@NotNull AdropBanner banner) {
                  System.out.println("バナー広告がクリックされました");
              }
          });

          // 3. ビュー階層に追加
          FrameLayout container = findViewById(R.id.banner_container);
          FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
              FrameLayout.LayoutParams.MATCH_PARENT,
              FrameLayout.LayoutParams.WRAP_CONTENT
          );
          container.addView(banner, params);

          // 4. 広告をロード
          banner.load();
      }

      @Override
      protected void onDestroy() {
          super.onDestroy();
          // 5. メモリ解放
          if (banner != null) {
              banner.destroy();
              banner = null;
          }
      }
  }
  ```
</CodeGroup>

***

## AdropBannerの初期化

### コンストラクタ

<ParamField body="context" type="Context" required>
  ActivityまたはApplicationのContext
</ParamField>

<CodeGroup>
  ```kotlin Kotlin theme={null}
  val banner = AdropBanner(context, "YOUR_UNIT_ID")
  ```

  ```java Java theme={null}
  AdropBanner banner = new AdropBanner(context, "YOUR_UNIT_ID");
  ```
</CodeGroup>

### ユニットIDの設定

<ParamField body="unitId" type="String" required>
  Adropコンソールで作成したユニットID
</ParamField>

<CodeGroup>
  ```kotlin Kotlin theme={null}
  banner.setUnitId("YOUR_UNIT_ID")
  ```

  ```java Java theme={null}
  banner.setUnitId("YOUR_UNIT_ID");
  ```
</CodeGroup>

### 広告のロード

バナーを画面に追加した後、`load()`メソッドを呼び出して広告をリクエストします。

<CodeGroup>
  ```kotlin Kotlin theme={null}
  banner.load()
  ```

  ```java Java theme={null}
  banner.load();
  ```
</CodeGroup>

<Warning>
  バナーが画面に表示されている時点で`load()`を呼び出してください。表示されていない状態でロードすると、インプレッションが正確に測定されない場合があります。
</Warning>

***

## リスナーの実装

`AdropBannerListener`インターフェースは広告のライフサイクルイベントを処理します。

### onAdReceived（必須）

広告の受信に成功した時に呼び出されます。

<CodeGroup>
  ```kotlin Kotlin theme={null}
  override fun onAdReceived(banner: AdropBanner) {
      println("バナー広告の受信成功")
      // ローディングインジケーターを非表示にするなどの処理
  }
  ```

  ```java Java theme={null}
  @Override
  public void onAdReceived(@NotNull AdropBanner banner) {
      System.out.println("バナー広告の受信成功");
      // ローディングインジケーターを非表示にするなどの処理
  }
  ```
</CodeGroup>

### onAdFailedToReceive（必須）

広告の受信に失敗した時に呼び出されます。

<CodeGroup>
  ```kotlin Kotlin theme={null}
  override fun onAdFailedToReceive(banner: AdropBanner, errorCode: AdropErrorCode) {
      println("バナー広告の受信失敗: $errorCode")
      // エラー処理および代替コンテンツの表示
  }
  ```

  ```java Java theme={null}
  @Override
  public void onAdFailedToReceive(@NotNull AdropBanner banner, @NotNull AdropErrorCode errorCode) {
      System.out.println("バナー広告の受信失敗: " + errorCode);
      // エラー処理および代替コンテンツの表示
  }
  ```
</CodeGroup>

<ParamField body="errorCode" type="AdropErrorCode">
  エラーの種類を示すコード。詳細は[リファレンス](/ja/sdk/android/reference#エラーコード)を参照してください。
</ParamField>

### onAdImpression（オプション）

広告が画面に表示された時に呼び出されます。

<CodeGroup>
  ```kotlin Kotlin theme={null}
  override fun onAdImpression(banner: AdropBanner) {
      println("バナー広告のインプレッション")
      // インプレッション分析ログなどの処理
  }
  ```

  ```java Java theme={null}
  @Override
  public void onAdImpression(@NotNull AdropBanner banner) {
      System.out.println("バナー広告のインプレッション");
      // インプレッション分析ログなどの処理
  }
  ```
</CodeGroup>

### onAdClicked（必須）

ユーザーが広告をクリックした時に呼び出されます。

<CodeGroup>
  ```kotlin Kotlin theme={null}
  override fun onAdClicked(banner: AdropBanner) {
      println("バナー広告がクリックされました")
      // クリック分析ログなどの処理
  }
  ```

  ```java Java theme={null}
  @Override
  public void onAdClicked(@NotNull AdropBanner banner) {
      System.out.println("バナー広告がクリックされました");
      // クリック分析ログなどの処理
  }
  ```
</CodeGroup>

### onAdVideoStart（オプション）

動画バナー広告で動画再生が開始された時に呼び出されます。

<CodeGroup>
  ```kotlin Kotlin theme={null}
  override fun onAdVideoStart(banner: AdropBanner) {
      println("バナー動画再生開始")
  }
  ```

  ```java Java theme={null}
  @Override
  public void onAdVideoStart(@NotNull AdropBanner banner) {
      System.out.println("バナー動画再生開始");
  }
  ```
</CodeGroup>

### onAdVideoEnd（オプション）

動画バナー広告で動画再生が終了した時に呼び出されます。

<CodeGroup>
  ```kotlin Kotlin theme={null}
  override fun onAdVideoEnd(banner: AdropBanner) {
      println("バナー動画再生終了")
  }
  ```

  ```java Java theme={null}
  @Override
  public void onAdVideoEnd(@NotNull AdropBanner banner) {
      System.out.println("バナー動画再生終了");
  }
  ```
</CodeGroup>

***

## コンテキストIDの設定

[コンテキストターゲティング](/ja/sdk/android/targeting#コンテキストターゲティング)のためにコンテキストIDを設定できます。

<CodeGroup>
  ```kotlin Kotlin theme={null}
  // contextIdは読み取り専用 — コンストラクタで設定
  val banner = AdropBanner(this, "YOUR_UNIT_ID", "article_123")
  ```

  ```java Java theme={null}
  // contextIdは読み取り専用 — コンストラクタで設定
  AdropBanner banner = new AdropBanner(this, "YOUR_UNIT_ID", "article_123");
  ```
</CodeGroup>

<Note>
  コンテキストIDは広告をロードする前に設定する必要があります。
</Note>

***

## ライフサイクル管理

### destroy()

バナーを使用しなくなった時は、必ず`destroy()`を呼び出してリソースを解放してください。

<CodeGroup>
  ```kotlin Kotlin theme={null}
  override fun onDestroy() {
      super.onDestroy()
      banner?.destroy()
      banner = null
  }
  ```

  ```java Java theme={null}
  @Override
  protected void onDestroy() {
      super.onDestroy();
      if (banner != null) {
          banner.destroy();
          banner = null;
      }
  }
  ```
</CodeGroup>

<Warning>
  `destroy()`を呼び出さないとメモリリークが発生する可能性があります。
</Warning>

***

## 広告サイズ

バナー広告はユニットに設定したサイズに合わせてビューのサイズを指定する必要があります。

### 一般的なバナーサイズ

| サイズ       | 用途    |
| --------- | ----- |
| 320 x 50  | 小型バナー |
| 320 x 100 | 中型バナー |
| 16:9比率    | 動画バナー |

### XMLでサイズを指定

```xml theme={null}
<io.adrop.ads.banner.AdropBanner
    android:id="@+id/adrop_banner"
    android:layout_width="320dp"
    android:layout_height="100dp"
    app:adrop_unit_id="YOUR_UNIT_ID" />
```

### コードでサイズを指定

<CodeGroup>
  ```kotlin Kotlin theme={null}
  val params = FrameLayout.LayoutParams(
      dpToPx(320), // 幅
      dpToPx(100)   // 高さ
  )
  container.addView(banner, params)

  // dpをpxに変換するユーティリティ関数
  fun dpToPx(dp: Int): Int {
      val density = resources.displayMetrics.density
      return (dp * density).toInt()
  }
  ```

  ```java Java theme={null}
  FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
      dpToPx(320), // 幅
      dpToPx(100)   // 高さ
  );
  container.addView(banner, params);

  // dpをpxに変換するユーティリティ関数
  private int dpToPx(int dp) {
      float density = getResources().getDisplayMetrics().density;
      return (int) (dp * density);
  }
  ```
</CodeGroup>

***

## テストユニットID

開発およびテスト時は以下のテストユニットIDを使用してください。

| 広告タイプ         | テストユニットID                               | サイズ       |
| ------------- | --------------------------------------- | --------- |
| バナー (320x50)  | `PUBLIC_TEST_UNIT_ID_320_50`            | 320 x 50  |
| バナー (320x100) | `PUBLIC_TEST_UNIT_ID_320_100`           | 320 x 100 |
| カルーセルバナー      | `PUBLIC_TEST_UNIT_ID_CAROUSEL`          | 可変        |
| バナー動画 (16:9)  | `PUBLIC_TEST_UNIT_ID_BANNER_VIDEO_16_9` | 16:9比率    |
| バナー動画 (9:16)  | `PUBLIC_TEST_UNIT_ID_BANNER_VIDEO_9_16` | 9:16比率    |

### 使用例

<CodeGroup>
  ```kotlin Kotlin theme={null}
  val banner = AdropBanner(this, "PUBLIC_TEST_UNIT_ID_320_100")
  ```

  ```java Java theme={null}
  AdropBanner banner = new AdropBanner(this, "PUBLIC_TEST_UNIT_ID_320_100");
  ```

  ```xml XML theme={null}
  <io.adrop.ads.banner.AdropBanner
      android:id="@+id/adrop_banner"
      android:layout_width="320dp"
      android:layout_height="100dp"
      app:adrop_unit_id="PUBLIC_TEST_UNIT_ID_320_100" />
  ```
</CodeGroup>

***

## 動画再生制御

動画バナー広告の場合、`play()`と`pause()`を使用してビデオ再生を手動で制御できます。

### play()

動画の再生を再開します。ポップアップが閉じたり、アプリがバックグラウンドから復帰してバナーが再び表示されるときに呼び出してください。

<CodeGroup>
  ```kotlin Kotlin theme={null}
  banner?.play()
  ```

  ```java Java theme={null}
  banner.play();
  ```
</CodeGroup>

### pause()

動画の再生を一時停止します。バナーがポップアップで隠れたり、アプリがバックグラウンドに移行するときに呼び出してください。

<CodeGroup>
  ```kotlin Kotlin theme={null}
  banner?.pause()
  ```

  ```java Java theme={null}
  banner.pause();
  ```
</CodeGroup>

### 例：バックグラウンド/フォアグラウンドの処理

<CodeGroup>
  ```kotlin Kotlin theme={null}
  override fun onResume() {
      super.onResume()
      banner?.play()
  }

  override fun onPause() {
      super.onPause()
      banner?.pause()
  }
  ```

  ```java Java theme={null}
  @Override
  protected void onResume() {
      super.onResume();
      if (banner != null) {
          banner.play();
      }
  }

  @Override
  protected void onPause() {
      super.onPause();
      if (banner != null) {
          banner.pause();
      }
  }
  ```
</CodeGroup>

<Note>
  `play()`と`pause()`は動画バナー広告にのみ影響します。画像バナーには効果がありません。
</Note>

***

## カスタムクリック処理

デフォルトでは、SDKはユーザーがバナー広告をクリックすると自動的に遷移先URLを開きます。クリックイベントを自分で処理したい場合（例：確認ダイアログの表示、分析ログの記録後に遷移など）、`useCustomClick`を使用できます。

<ParamField path="useCustomClick" type="Boolean" default="false">
  `true`に設定すると、SDKはクリック時に自動的に遷移先URLを開きません。`onAdClicked`イベントのみ発火し、`open()`を手動で呼び出す必要があります。
</ParamField>

<CodeGroup>
  ```kotlin Kotlin theme={null}
  // 1. カスタムクリック処理を有効化
  banner?.useCustomClick = true

  // 2. リスナーでクリック処理
  banner?.listener = object : AdropBannerListener {
      override fun onAdClicked(banner: AdropBanner) {
          // カスタムロジック実行（ダイアログ表示、分析ログなど）
          println("広告クリック — 遷移先URLを開く")
          banner.open()
      }

      // ... 他のリスナーメソッド
  }
  ```

  ```java Java theme={null}
  // 1. カスタムクリック処理を有効化
  banner.setUseCustomClick(true);

  // 2. リスナーでクリック処理
  banner.setListener(new AdropBannerListener() {
      @Override
      public void onAdClicked(@NotNull AdropBanner banner) {
          // カスタムロジック実行（ダイアログ表示、分析ログなど）
          System.out.println("広告クリック — 遷移先URLを開く");
          banner.open();
      }

      // ... 他のリスナーメソッド
  });
  ```
</CodeGroup>

### open()

広告の遷移先URLを開きます。カスタムURLを渡して別のURLを開くこともできます。

<CodeGroup>
  ```kotlin Kotlin theme={null}
  // デフォルトの遷移先URLを開く
  banner?.open()

  // カスタムURLを開く
  banner?.open("https://example.com")
  ```

  ```java Java theme={null}
  // デフォルトの遷移先URLを開く
  banner.open();

  // カスタムURLを開く
  banner.open("https://example.com");
  ```
</CodeGroup>

<Note>
  `open()`は`useCustomClick`が`true`に設定されている場合のみ動作します。`useCustomClick`が`false`（デフォルト）の場合、SDKが自動的にURLを開きます。
</Note>

***

## ベストプラクティス

### 1. メモリ管理

ActivityやFragmentが終了する時は必ずバナーを解放してください。

<CodeGroup>
  ```kotlin Kotlin theme={null}
  override fun onDestroy() {
      super.onDestroy()
      banner?.destroy()
      banner = null
  }
  ```

  ```java Java theme={null}
  @Override
  protected void onDestroy() {
      super.onDestroy();
      if (banner != null) {
          banner.destroy();
          banner = null;
      }
  }
  ```
</CodeGroup>

### 2. 画面の可視性

バナーが画面に表示されている時に広告をロードしてください。

<CodeGroup>
  ```kotlin Kotlin theme={null}
  override fun onResume() {
      super.onResume()
      banner?.load()
  }
  ```

  ```java Java theme={null}
  @Override
  protected void onResume() {
      super.onResume();
      if (banner != null) {
          banner.load();
      }
  }
  ```
</CodeGroup>

### 3. エラー処理

広告ロード失敗時の適切なエラー処理を実装してください。

<CodeGroup>
  ```kotlin Kotlin theme={null}
  override fun onAdFailedToReceive(banner: AdropBanner, errorCode: AdropErrorCode) {
      when (errorCode) {
          AdropErrorCode.ERROR_CODE_NETWORK -> {
              println("ネットワークエラー：接続を確認してください")
          }
          AdropErrorCode.ERROR_CODE_AD_NO_FILL -> {
              println("表示可能な広告がありません")
          }
          else -> {
              println("広告ロード失敗: $errorCode")
          }
      }
  }
  ```

  ```java Java theme={null}
  @Override
  public void onAdFailedToReceive(@NotNull AdropBanner banner, @NotNull AdropErrorCode errorCode) {
      if (errorCode == AdropErrorCode.ERROR_CODE_NETWORK) {
          System.out.println("ネットワークエラー：接続を確認してください");
      } else if (errorCode == AdropErrorCode.ERROR_CODE_AD_NO_FILL) {
          System.out.println("表示可能な広告がありません");
      } else {
          System.out.println("広告ロード失敗: " + errorCode);
      }
  }
  ```
</CodeGroup>

### 4. RecyclerViewでの使用

RecyclerViewでバナーを使用する時は、ViewHolderで適切に管理してください。

<CodeGroup>
  ```kotlin Kotlin theme={null}
  class BannerViewHolder(view: View) : RecyclerView.ViewHolder(view) {
      private val banner: AdropBanner = view.findViewById(R.id.adrop_banner)

      fun bind() {
          banner.listener = object : AdropBannerListener {
              // リスナー実装
          }
          banner.load()
      }

      fun recycle() {
          banner.destroy()
      }
  }

  // アダプター内で
  override fun onViewRecycled(holder: BannerViewHolder) {
      holder.recycle()
  }
  ```

  ```java Java theme={null}
  class BannerViewHolder extends RecyclerView.ViewHolder {
      private AdropBanner banner;

      public BannerViewHolder(View view) {
          super(view);
          banner = view.findViewById(R.id.adrop_banner);
      }

      public void bind() {
          banner.setListener(new AdropBannerListener() {
              // リスナー実装
          });
          banner.load();
      }

      public void recycle() {
          banner.destroy();
      }
  }

  // アダプター内で
  @Override
  public void onViewRecycled(BannerViewHolder holder) {
      holder.recycle();
  }
  ```
</CodeGroup>

***

## 完全な例

### Kotlinの例

```kotlin theme={null}
import android.os.Bundle
import android.view.View
import android.widget.FrameLayout
import android.widget.ProgressBar
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import io.adrop.ads.banner.AdropBanner
import io.adrop.ads.banner.AdropBannerListener
import io.adrop.ads.model.AdropErrorCode

class BannerActivity : AppCompatActivity() {
    private var banner: AdropBanner? = null
    private lateinit var progressBar: ProgressBar

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_banner)

        progressBar = findViewById(R.id.progress_bar)
        setupBanner()
    }

    private fun setupBanner() {
        // 1. バナーインスタンスを作成
        // contextIdは読み取り専用プロパティ — コンストラクタで設定
        banner = AdropBanner(this, "YOUR_UNIT_ID", "article_123").apply {
            // 2. リスナー設定
            listener = object : AdropBannerListener {
                override fun onAdReceived(banner: AdropBanner) {
                    println("バナー広告の受信成功")
                    progressBar.visibility = View.GONE
                }

                override fun onAdFailedToReceive(banner: AdropBanner, errorCode: AdropErrorCode) {
                    println("バナー広告の受信失敗: $errorCode")
                    progressBar.visibility = View.GONE

                    // エラー処理
                    when (errorCode) {
                        AdropErrorCode.ERROR_CODE_NETWORK -> {
                            showToast("ネットワーク接続を確認してください")
                        }
                        AdropErrorCode.ERROR_CODE_AD_NO_FILL -> {
                            println("表示可能な広告がありません")
                        }
                        else -> {
                            showToast("広告を読み込めませんでした")
                        }
                    }
                }

                override fun onAdImpression(banner: AdropBanner) {
                    println("バナー広告のインプレッション")
                }

                override fun onAdClicked(banner: AdropBanner) {
                    println("バナー広告がクリックされました")
                }
            }
        }

        // 3. ビュー階層に追加
        val container = findViewById<FrameLayout>(R.id.banner_container)
        val params = FrameLayout.LayoutParams(
            dpToPx(320),
            dpToPx(100)
        )
        container.addView(banner, params)

        // 4. 広告をロード
        progressBar.visibility = View.VISIBLE
        banner?.load()
    }

    private fun dpToPx(dp: Int): Int {
        val density = resources.displayMetrics.density
        return (dp * density).toInt()
    }

    private fun showToast(message: String) {
        Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
    }

    override fun onDestroy() {
        super.onDestroy()
        // 5. メモリ解放
        banner?.destroy()
        banner = null
    }
}
```

### Javaの例

```java theme={null}
import android.os.Bundle;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ProgressBar;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import io.adrop.ads.banner.AdropBanner;
import io.adrop.ads.banner.AdropBannerListener;
import io.adrop.ads.model.AdropErrorCode;
import org.jetbrains.annotations.NotNull;

public class BannerActivity extends AppCompatActivity {
    private AdropBanner banner;
    private ProgressBar progressBar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_banner);

        progressBar = findViewById(R.id.progress_bar);
        setupBanner();
    }

    private void setupBanner() {
        // 1. バナーインスタンスを作成（コンテキストID付き）
        banner = new AdropBanner(this, "YOUR_UNIT_ID", "article_123");

        // 2. リスナー設定
        banner.setListener(new AdropBannerListener() {
            @Override
            public void onAdReceived(@NotNull AdropBanner banner) {
                System.out.println("バナー広告の受信成功");
                progressBar.setVisibility(View.GONE);
            }

            @Override
            public void onAdFailedToReceive(@NotNull AdropBanner banner, @NotNull AdropErrorCode errorCode) {
                System.out.println("バナー広告の受信失敗: " + errorCode);
                progressBar.setVisibility(View.GONE);

                // エラー処理
                if (errorCode == AdropErrorCode.ERROR_CODE_NETWORK) {
                    showToast("ネットワーク接続を確認してください");
                } else if (errorCode == AdropErrorCode.ERROR_CODE_AD_NO_FILL) {
                    System.out.println("表示可能な広告がありません");
                } else {
                    showToast("広告を読み込めませんでした");
                }
            }

            @Override
            public void onAdImpression(@NotNull AdropBanner banner) {
                System.out.println("バナー広告のインプレッション");
            }

            @Override
            public void onAdClicked(@NotNull AdropBanner banner) {
                System.out.println("バナー広告がクリックされました");
            }
        });

        // 3. ビュー階層に追加
        FrameLayout container = findViewById(R.id.banner_container);
        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
            dpToPx(320),
            dpToPx(100)
        );
        container.addView(banner, params);

        // 4. 広告をロード
        progressBar.setVisibility(View.VISIBLE);
        banner.load();
    }

    private int dpToPx(int dp) {
        float density = getResources().getDisplayMetrics().density;
        return (int) (dp * density);
    }

    private void showToast(String message) {
        Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 5. メモリ解放
        if (banner != null) {
            banner.destroy();
            banner = null;
        }
    }
}
```

### XMLレイアウト

```xml activity_banner.xml theme={null}
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="バナー広告の例"
        android:textSize="24sp"
        android:textStyle="bold"
        android:layout_marginTop="32dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />

    <ProgressBar
        android:id="@+id/progress_bar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:visibility="gone"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <FrameLayout
        android:id="@+id/banner_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="16dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
```

***

## 一括ロード (loads)

`AdropBanner.loads()`を使用すると、1回の呼び出しで複数のバナー広告をまとめてリクエストできます。カルーセルやページネーション付きフィード、広告プールのプリフェッチなどに有用です。

### シグネチャ

<CodeGroup>
  ```kotlin Kotlin theme={null}
  AdropBanner.loads(
      context: Context,
      unitId: String,
      contextId: String? = null,
      listener: AdropBannerListener,
  )
  ```

  ```java Java theme={null}
  AdropBanner.loads(context, "YOUR_UNIT_ID", null, listener);
  ```
</CodeGroup>

### 使用方法

<CodeGroup>
  ```kotlin Kotlin theme={null}
  AdropBanner.loads(
      context = this,
      unitId = "YOUR_UNIT_ID",
      contextId = null,
      listener = object : AdropBannerListener {
          // バッチ成功 — 最大5個の準備済みバナーが渡されます。
          override fun onAdsReceived(banners: List<AdropBanner>) {
              banners.forEach { banner ->
                  // ビュー階層へ追加 (ViewPager2、RecyclerViewなど)
                  container.addView(banner)
              }
          }

          // バッチ失敗
          override fun onAdsFailedToReceive(errorCode: AdropErrorCode) {
              println("バッチロード失敗: $errorCode")
          }

          // 単体用コールバックはloads経路では呼ばれません。
          override fun onAdReceived(banner: AdropBanner) { /* batch path */ }
          override fun onAdFailedToReceive(banner: AdropBanner, errorCode: AdropErrorCode) {}

          // クリック/インプレッション/動画コールバックは各インスタンスで通常通り呼ばれます。
          override fun onAdClicked(banner: AdropBanner) {
              println("バナークリック: ${banner.creativeId}")
          }

          override fun onAdImpression(banner: AdropBanner) {
              println("バナーインプレッション: ${banner.creativeId}")
          }
      },
  )
  ```

  ```java Java theme={null}
  AdropBanner.loads(this, "YOUR_UNIT_ID", null, new AdropBannerListener() {
      @Override
      public void onAdsReceived(@NotNull List<AdropBanner> banners) {
          for (AdropBanner banner : banners) {
              container.addView(banner);
          }
      }

      @Override
      public void onAdsFailedToReceive(@NotNull AdropErrorCode errorCode) {
          System.out.println("バッチロード失敗: " + errorCode);
      }

      // 単体用コールバック — バッチ経路では使用されません。
      @Override
      public void onAdReceived(@NotNull AdropBanner banner) { }

      @Override
      public void onAdFailedToReceive(@NotNull AdropBanner banner, @NotNull AdropErrorCode errorCode) { }

      @Override
      public void onAdClicked(@NotNull AdropBanner banner) {
          System.out.println("バナークリック: " + banner.getCreativeId());
      }

      @Override
      public void onAdImpression(@NotNull AdropBanner banner) {
          System.out.println("バナーインプレッション: " + banner.getCreativeId());
      }
  });
  ```
</CodeGroup>

### リスナーコールバック

| コールバック                                                               | 呼び出されるタイミング                                                   |
| -------------------------------------------------------------------- | ------------------------------------------------------------- |
| `onAdsReceived(banners)`                                             | バッチ配信完了。各`AdropBanner`にはリスナーがすでに付与され、広告データが適用されています。          |
| `onAdsFailedToReceive(errorCode)`                                    | リクエスト拒否、ネットワーク失敗、または表示可能な広告がなかった場合 (`ERROR_CODE_AD_NO_FILL`)。 |
| `onAdClicked` / `onAdImpression` / `onAdVideoStart` / `onAdVideoEnd` | 単体`load()`と同様に、各バナーごとに呼ばれます。                                  |

<Warning>
  単体`onAdReceived` / `onAdFailedToReceive`コールバックは`loads()`経路では**呼ばれません**。バッチ結果は必ず`onAdsReceived` / `onAdsFailedToReceive`で受け取ってください。
</Warning>

### 制約事項

* **呼び出しあたり最大5個。** サーバーがそれ以上を返しても先頭の5個のみ配信されます。
* **バックフィルは適用されません。** ダイレクト広告が埋まらない場合、バックフィル設定に関わらず`onAdsFailedToReceive`が`ERROR_CODE_AD_NO_FILL`で呼ばれます。
* **`onAdsReceived`内で`destroy()`を呼ばないでください。** まず各バナーをビュー階層に付加し、その後親`Activity.onDestroy()`(または同等のタイミング)で`destroy()`してください。
* `onAdsReceived`は広告データが適用され次第発火し、単体`load()`と同じ動作です — ビューに付加後にクリエイティブが描画されます。

***

## バックフィル広告

バックフィル広告が有効な場合、ダイレクト広告がないときに自動的にバックフィル広告がロードされます。`isBackfilled`プロパティでバックフィル広告かどうかを確認できます。

<CodeGroup>
  ```kotlin Kotlin theme={null}
  banner.listener = object : AdropBannerListener {
      override fun onAdReceived(banner: AdropBanner) {
          if (banner.isBackfilled) {
              println("バックフィル広告がロードされました")
          } else {
              println("ダイレクト広告がロードされました")
          }
      }

      override fun onAdFailedToReceive(banner: AdropBanner, errorCode: AdropErrorCode) {
          when (errorCode) {
              AdropErrorCode.ERROR_CODE_AD_NO_FILL -> {
                  println("ダイレクト広告なし、バックフィルをリクエスト中...")
              }
              AdropErrorCode.ERROR_CODE_AD_BACKFILL_NO_FILL -> {
                  println("バックフィル広告も利用不可")
              }
              else -> {
                  println("広告ロード失敗: $errorCode")
              }
          }
      }
  }
  ```

  ```java Java theme={null}
  banner.setListener(new AdropBannerListener() {
      @Override
      public void onAdReceived(@NotNull AdropBanner banner) {
          if (banner.isBackfilled()) {
              System.out.println("バックフィル広告がロードされました");
          } else {
              System.out.println("ダイレクト広告がロードされました");
          }
      }

      @Override
      public void onAdFailedToReceive(@NotNull AdropBanner banner, @NotNull AdropErrorCode errorCode) {
          if (errorCode == AdropErrorCode.ERROR_CODE_AD_NO_FILL) {
              System.out.println("ダイレクト広告なし、バックフィルをリクエスト中...");
          } else if (errorCode == AdropErrorCode.ERROR_CODE_AD_BACKFILL_NO_FILL) {
              System.out.println("バックフィル広告も利用不可");
          } else {
              System.out.println("広告ロード失敗: " + errorCode);
          }
      }
  });
  ```
</CodeGroup>

<Note>
  バックフィル広告を使用するには、`io.adrop:adrop-ads-backfill`依存関係を追加する必要があります。
</Note>

***

## 次のステップ

<CardGroup cols={2}>
  <Card title="ネイティブ広告" href="/ja/sdk/android/native">
    UIに合わせてカスタマイズ可能なネイティブ広告を実装
  </Card>

  <Card title="インタースティシャル広告" href="/ja/sdk/android/interstitial">
    全画面のインタースティシャル広告を実装
  </Card>

  <Card title="ターゲティング設定" href="/ja/sdk/android/targeting">
    ユーザー属性とコンテキストターゲティングを設定
  </Card>

  <Card title="リファレンス" href="/ja/sdk/android/reference">
    クラス、リスナー、エラーコードを確認
  </Card>
</CardGroup>
