You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter Android端如何获取Activity?插屏广告加载遇空指针问题

问题:Flutter插件Kotlin侧获取Activity为空,插屏广告无法正常展示

我正在使用Kotlin和Swift开发一款Flutter插件,用于在Flutter界面中展示横幅广告和插屏广告。但在Kotlin侧展示插屏广告时,需要用到Activity,尝试通过onAttachedToActivity方法获取,却发现activity变量始终为空。

我没有使用FlutterEngine,而是通过init方法在Flutter界面中添加布局(该布局用于展示横幅广告,且运行正常,相关代码已移除)。以下是用于展示广告的三个Kotlin类:

插件类

class SecondPluginAttemptPlugin: FlutterPlugin {

  private var Tag: String = "MyTag"
  override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {
    Log.d(Tag, "SecondPluginAttemptPlugin attached to Flutter engine")
    try {
      binding.platformViewRegistry.registerViewFactory(
        "plugins.example/second_attempt", MyViewFactory(binding.binaryMessenger)
      )
      Log.d(Tag, "MyViewFactory registered")
    } catch (e: Exception) {
      Log.e(Tag, "Error during registration: ${e.message}")
    }
  }
  
  override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
    Log.d(Tag, "SecondPluginAttemptPlugin detached from Flutter engine")
  }
}

工厂类

class MyViewFactory (private val messenger: BinaryMessenger): PlatformViewFactory(StandardMessageCodec.INSTANCE){
        override fun create(context: Context, id: Int, o: Any?) : PlatformView {
            return MyView(context, messenger, id)
        }
}

视图类

class MyView internal constructor(context: Context, messenger: BinaryMessenger, id: Int) :
    PlatformView, MethodCallHandler, ActivityAware {
    private var applicationContext: Context = context
    private var messageLayout: ViewGroup?
    private val channel = MethodChannel(messenger, "plugins.example/second_attempt_$id")

    private var mAdManagerInterstitialAd: AdManagerInterstitialAd? = null
    private lateinit var myActivity: Activity
    private val Tag = "MyTag"

    init {
        try {
            Log.d(Tag, "init")
            channel.setMethodCallHandler(this)

        } catch (e: Exception) {
            Log.e(Tag, "Error setting method call handler: $e")
        }
        messageLayout = FrameLayout(applicationContext)
        messageLayout?.setBackgroundColor(Color.BLUE)
        val params = FrameLayout.LayoutParams(
            FrameLayout.LayoutParams.WRAP_CONTENT,
            FrameLayout.LayoutParams.WRAP_CONTENT
        )
        params.gravity = Gravity.BOTTOM
    }

    override fun getView(): View? {
        Log.d(Tag, "View")
        return messageLayout
    }

    override fun dispose() {
        Log.d(Tag, "Dispose")
        messageLayout = null
    }

    override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
        Log.d(Tag, "onMethodCall " )
        when (call.method) {
            "setParams" -> settingParameters(call)
            else -> result.notImplemented()
        }
    }

    private fun settingParameters(call: MethodCall) {
        val arguments = call.arguments as? Map<*, *>
        val accountId = arguments?.get("prebidAccountId") as? String ?: ""
        val adUnitId = arguments?.get("adUnitId") as? String ?: ""
        val configId = arguments?.get("configId") as? String ?: ""
        val width = arguments?.get("width") as? Int ?: 0
        val height = arguments?.get("height") as? Int ?: 0

        messageLayout?.removeAllViews()

        val textView = TextView(applicationContext)
        textView.setTextColor(Color.RED)
        textView.gravity = Gravity.CENTER

        //Skipped some code used to check if variables are not empty and if they are - a message is displayed inside messageLayout

        createInterstitial(adUnitId)
    }

    private fun createInterstitial(AD_UNIT_ID: String) {
        val adRequest = AdManagerAdRequest.Builder().build()

        AdManagerInterstitialAd.load(applicationContext, AD_UNIT_ID, adRequest,
            object : AdManagerInterstitialAdLoadCallback() {
                override fun onAdLoaded(interstitialAd: AdManagerInterstitialAd) {
                    mAdManagerInterstitialAd = interstitialAd
                    Log.i(Tag, "onAdLoaded")
                    showInterstitial()
                }

                override fun onAdFailedToLoad(loadAdError: LoadAdError) {
                    Log.d(Tag, loadAdError.toString())
                    mAdManagerInterstitialAd = null
                }
            })
    }

    private fun showInterstitial() {
        if (mAdManagerInterstitialAd != null) {
            mAdManagerInterstitialAd?.show(myActivity)
        } else {
            Log.d("TAG", "The interstitial ad wasn't ready yet.")
        }
    }

    override fun onAttachedToActivity(binding: ActivityPluginBinding) {
        myActivity = binding.activity
    }

    override fun onDetachedFromActivityForConfigChanges() {
        TODO("Not yet implemented")
    }

    override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
        TODO("Not yet implemented")
    }

    override fun onDetachedFromActivity() {
        TODO("Not yet implemented")
    }
}

问题解决说明

后来定位到问题根源:ActivityAware接口被错误地实现在了MyView类中,正确的做法应该是在插件主类SecondPluginAttemptPlugin中实现该接口。

将Activity传递给MyView类的实现方式:结合使用lateinit和CompletableFuture<Activity>来完成Activity实例的传递。


内容的提问来源于stack exchange,提问作者T1D

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 16:15:40