flutter - 将原生广告添加到列表视图后,有时在颤振应用程序中会出现 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");
}
}
解决方案
推荐阅读
- c# - %= 会得到一个集合的模块吗?
- angular - VS代码中的Angular 5 Jasmine问题
- java - 奇怪的 ArrayList 值
- leaflet - 如何将嵌套多边形与来自不同 GeoJSON 文件的父级相关联?
- docker - 如何在 docker 容器中调试“没有路由到主机”
- react-leaflet - 瓷砖不好取
- bash - 在给定时间后杀死 nohup 进程
- javascript - 使用隐藏的 WebView 并在 Javascript 和 Java 代码之间调用函数
- javascript - 如何为 Stampit 对象自动创建 TypeScript 或 Flow 定义?
- php - 有什么作用?在 PHP 中代表(在 href 运算符之后)?