首页 > 解决方案 > 将原生广告添加到列表视图后,有时在颤振应用程序中会出现 IllegalStateException

问题描述

这是我得到的错误:

setState() called after dispose(): _PlatformViewLinkState#bc2a5(lifecycle state: defunct, not mounted)
This error happens if you...

E/flutter ( 4758): [ERROR:flutter/shell/platform/android/platform_view_android_jni_impl.cc(49)] java.lang.IllegalStateException: PlatformView#getView() returned null, but an Android view reference was expected.

我使用的是 google_mobile_ads 包,而不是 firebase_ads 包,因为它已被弃用。我试图在列表视图中固定数量的元素之后将原生广告放在卡片列表中。

我这样做的方法是在 main.dart 文件中使用提供程序:

...
void main() {
  WidgetsFlutterBinding.ensureInitialized();
  final initFuture = MobileAds.instance.initialize();
  final adState = AdState(initFuture);
  runApp(Provider.value(
      value: adState,
    builder: (context, child) => MyApp(),
  ));
}
...

包含列表视图的屏幕称为 chapters_screen.dart,当转到此屏幕时,应用程序有时会崩溃。在这个文件中有一个项目列表List<Object> itemList = [];作为状态变量。在初始状态下,列表中填充了离线数据,如下所示:itemList = List.from(chaptersData);
这就是我在列表中添加广告的方式:

@override
  void didChangeDependencies() {
    super.didChangeDependencies();
    final adState = Provider.of<AdState>(context);
    if(this.mounted){
      adState.initialization.then((status) {
        if(this.mounted){
          setState(() {
            for (int i = itemList.length - 2; i >= 1; i -= 2) {
              itemList.insert(
                i,
                // BannerAd(
                //   adUnitId: adState.bannerAdUnitId,
                //   size: AdSize.banner,
                //   request: AdRequest(),
                //   listener: adState.adListener,
                // )..load(),
                NativeAd(
                  adUnitId: adState.nativeAdUnitId,
                  factoryId: 'listTile',
                  request: AdRequest(),
                  listener: NativeAdListener(
                    onAdLoaded: (_) {
                      print('ad is loaded succesfully!');
                    },
                    onAdFailedToLoad: (ad, error) {
                      // Releases an ad resource when it fails to load
                      ad.dispose();

                      print('Ad load failed (code=${error.code} message=${error.message})');       },
                  ),

                )..load(),
              );
            }
          });
        }
      });
    }
  }

我之前用横幅广告尝试过,没有问题。我遵循了本教程:https ://www.youtube.com/watch?v= m0d_pbgeeG8 但我必须将 google_mobile_ads 软件包版本更改为较新的版本才能使用与颤振文档中相同的 NativeAdFactory。问题是在较新的版本中, AdListener 对象不再存在,因此而不是listener: adState.adListener像在视频中那样传递:我将监听器作为上面的代码放在“NativeAd()”小部件中。

这就是我检查 listItem 的类型以在 listView 中构建它的方式:

Widget _buildListView(BuildContext context) {
    List<Widget> widgetList = [];
    for (int i = 0; i < itemList.length; i++) {
      if (itemList[i] is NativeAd) {
        widgetList.add(Container(
            height: 200,
            child: AdWidget(ad: itemList[i] as NativeAd),
            color: Colors.black));
      } else {
        widgetList.add(ChapterCard(chapter: Chapter.fromJson(itemList[i])));
      }
    }
    return Container(
      decoration: BoxDecoration(
        image: DecorationImage(
          image: AssetImage("assets/images/blured_background.jpg"),
          fit: BoxFit.cover,
        ),
      ),
      child: ListView(children: widgetList.toList()),
    );
  }

我认为我在提供程序或工厂类中做错了,但我不确定。

android的工厂类(在java中):

import com.google.android.gms.ads.nativead.NativeAd;
import com.google.android.gms.ads.nativead.NativeAdView;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.Map;

import io.flutter.plugins.googlemobileads.GoogleMobileAdsPlugin;

class ListTileNativeAdFactory implements GoogleMobileAdsPlugin.NativeAdFactory {
    private final Context context;

    ListTileNativeAdFactory(Context context) {
        this.context = context;
    }

    @Override
    public NativeAdView createNativeAd(
            NativeAd nativeAd, Map<String, Object> customOptions) {
        NativeAdView nativeAdView = (NativeAdView) LayoutInflater.from(context)
                .inflate(R.layout.list_tile_native_ad, null);
        TextView attributionViewSmall = nativeAdView
                .findViewById(R.id.tv_list_tile_native_ad_attribution_small);
        TextView attributionViewLarge = nativeAdView
                .findViewById(R.id.tv_list_tile_native_ad_attribution_large);

        ImageView iconView = nativeAdView.findViewById(R.id.iv_list_tile_native_ad_icon);
        NativeAd.Image icon = nativeAd.getIcon();
        if (icon != null) {
            attributionViewSmall.setVisibility(View.VISIBLE);
            attributionViewLarge.setVisibility(View.INVISIBLE);
            iconView.setImageDrawable(icon.getDrawable());
        } else {
            attributionViewSmall.setVisibility(View.INVISIBLE);
            attributionViewLarge.setVisibility(View.VISIBLE);
        }
        nativeAdView.setIconView(iconView);

        TextView headlineView = nativeAdView.findViewById(R.id.tv_list_tile_native_ad_headline);
        headlineView.setText(nativeAd.getHeadline());
        nativeAdView.setHeadlineView(headlineView);

        TextView bodyView = nativeAdView.findViewById(R.id.tv_list_tile_native_ad_body);
        bodyView.setText(nativeAd.getBody());
        bodyView.setVisibility(nativeAd.getBody() != null ? View.VISIBLE : View.INVISIBLE);
        nativeAdView.setBodyView(bodyView);

        nativeAdView.setNativeAd(nativeAd);

        return nativeAdView;
    }
}

MainActivity 类:

import androidx.annotation.NonNull;

import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugins.googlemobileads.GoogleMobileAdsPlugin;

public class MainActivity extends FlutterActivity {

    @Override
    public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
        super.configureFlutterEngine(flutterEngine);

        // TODO: Register the ListTileNativeAdFactory
        GoogleMobileAdsPlugin.registerNativeAdFactory(flutterEngine, "listTile",
                new ListTileNativeAdFactory(getContext()));
    }

    @Override
    public void cleanUpFlutterEngine(@NonNull FlutterEngine flutterEngine) {
        super.cleanUpFlutterEngine(flutterEngine);

        // TODO: Unregister the ListTileNativeAdFactory
        GoogleMobileAdsPlugin.unregisterNativeAdFactory(flutterEngine, "listTile");
    }
}

标签: flutteradmob

解决方案


推荐阅读