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

# First Look

> 在 Android 中优先尝试 CloudX，同时保留现有聚合广告位作为回退

First Look 让 CloudX 优先获得广告位填充机会，同时保留您现有的聚合设置作为回退路径。建议先从一个广告位开始，验证加载和展示行为后，再扩展到更多广告位。

此示例使用 AdMob 插屏广告作为回退。相同模式也适用于其他回退聚合平台：先加载 CloudX；只有当 CloudX 未加载成功时才加载回退广告；当两个来源都未准备好时，让应用流程继续。

<Info>
  创建控制器前，请先完成 CloudX 和 Google Mobile Ads 初始化。控制器外部仍应保留您现有的频控、重试和广告位触发时机规则。
</Info>

```kotlin FirstLookInterstitialController.kt theme={null}
import android.app.Activity
import com.google.android.gms.ads.AdError
import com.google.android.gms.ads.AdRequest
import com.google.android.gms.ads.FullScreenContentCallback
import com.google.android.gms.ads.LoadAdError
import com.google.android.gms.ads.interstitial.InterstitialAd
import com.google.android.gms.ads.interstitial.InterstitialAdLoadCallback
import io.cloudx.sdk.CloudX
import io.cloudx.sdk.CloudXAd
import io.cloudx.sdk.CloudXError
import io.cloudx.sdk.CloudXInterstitialAd
import io.cloudx.sdk.CloudXInterstitialListener

class FirstLookInterstitialController(
    private val activity: Activity,
    private val cloudXAdUnitId: String,
    private val adMobAdUnitId: String,
) {
    enum class Source {
        CLOUDX,
        ADMOB,
    }

    interface Listener {
        fun onAdLoaded(source: Source) {}
        fun onAdLoadFailed(source: Source, message: String?) {}
        fun onAdShown(source: Source) {}
        fun onAdShowFailed(source: Source, message: String?) {}
        fun onAdClosed(source: Source) {}
        fun onAdClicked(source: Source) {}
    }

    var listener: Listener? = null

    private val cloudXInterstitial: CloudXInterstitialAd =
        CloudX.createInterstitial(activity, cloudXAdUnitId)

    private var adMobInterstitial: InterstitialAd? = null
    private var isLoadingCloudX = false
    private var isLoadingAdMob = false

    init {
        cloudXInterstitial.listener = createCloudXListener()
    }

    fun load() {
        if (isLoadingCloudX || isLoadingAdMob || cloudXInterstitial.isAdReady || adMobInterstitial != null) {
            return
        }

        isLoadingCloudX = true
        cloudXInterstitial.load()
    }

    fun show(): Boolean {
        if (cloudXInterstitial.isAdReady) {
            cloudXInterstitial.show(activity)
            return true
        }

        return showAdMobFallback()
    }

    fun destroy() {
        cloudXInterstitial.destroy()
        adMobInterstitial = null
        listener = null
    }

    private fun createCloudXListener() = object : CloudXInterstitialListener {
        override fun onAdLoaded(cloudXAd: CloudXAd) {
            isLoadingCloudX = false
            listener?.onAdLoaded(Source.CLOUDX)
        }

        override fun onAdLoadFailed(adUnitId: String, cloudXError: CloudXError) {
            isLoadingCloudX = false
            loadAdMobFallback()
        }

        override fun onAdDisplayed(cloudXAd: CloudXAd) {
            listener?.onAdShown(Source.CLOUDX)
        }

        override fun onAdDisplayFailed(cloudXAd: CloudXAd, cloudXError: CloudXError) {
            if (showAdMobFallback()) {
                return
            }

            listener?.onAdShowFailed(Source.CLOUDX, cloudXError.message)
        }

        override fun onAdHidden(cloudXAd: CloudXAd) {
            listener?.onAdClosed(Source.CLOUDX)
        }

        override fun onAdClicked(cloudXAd: CloudXAd) {
            listener?.onAdClicked(Source.CLOUDX)
        }
    }

    private fun loadAdMobFallback() {
        if (isLoadingAdMob || adMobInterstitial != null) {
            return
        }

        isLoadingAdMob = true
        InterstitialAd.load(
            activity,
            adMobAdUnitId,
            AdRequest.Builder().build(),
            object : InterstitialAdLoadCallback() {
                override fun onAdLoaded(interstitialAd: InterstitialAd) {
                    isLoadingAdMob = false
                    adMobInterstitial = interstitialAd.apply {
                        fullScreenContentCallback = createAdMobFullScreenCallback()
                    }
                    listener?.onAdLoaded(Source.ADMOB)
                }

                override fun onAdFailedToLoad(loadAdError: LoadAdError) {
                    isLoadingAdMob = false
                    adMobInterstitial = null
                    listener?.onAdLoadFailed(Source.ADMOB, loadAdError.message)
                }
            },
        )
    }

    private fun showAdMobFallback(): Boolean {
        val ad = adMobInterstitial ?: return false
        ad.show(activity)
        return true
    }

    private fun createAdMobFullScreenCallback() = object : FullScreenContentCallback() {
        override fun onAdShowedFullScreenContent() {
            adMobInterstitial = null
            listener?.onAdShown(Source.ADMOB)
        }

        override fun onAdDismissedFullScreenContent() {
            adMobInterstitial = null
            listener?.onAdClosed(Source.ADMOB)
        }

        override fun onAdFailedToShowFullScreenContent(adError: AdError) {
            adMobInterstitial = null
            listener?.onAdShowFailed(Source.ADMOB, adError.message)
        }

        override fun onAdClicked() {
            listener?.onAdClicked(Source.ADMOB)
        }
    }
}
```

在广告位触发时调用 `show()`。如果返回 `false`，表示 CloudX 和回退广告都没有准备好，此时应继续应用流程，不展示广告。

```kotlin theme={null}
if (!firstLookInterstitial.show()) {
    continueToNextScreen()
}
```

广告展示、关闭或最终失败后，请在您的应用准备好下一次广告位机会时再次调用 `load()`。

<Tip>
  此示例采用懒加载回退：只有 CloudX 加载失败后才加载 AdMob。除非 CloudX 针对您的应用建议其他上线策略，否则不要并行加载两个来源。
</Tip>
