bdlukaa / native_admob_flutter

Easy-to-make native ads in flutter using AdMOB SDK.
https://pub.dev/packages/native_admob_flutter
BSD 3-Clause "New" or "Revised" License
81 stars 57 forks source link

NativeAd becomes unresponsive and its texts disappear after removing & re-adding it to the widget tree #45

Closed ramtinq closed 3 years ago

ramtinq commented 3 years ago

In your example app, I just added a button to toggle show/hide the first NativeAd (which is attached to a controller). After it's shown again, it is unresponsive and its texts won't show up as can bee seen in the screenshots. This is the code I edited:

class _NativeAdsState extends State<NativeAds>
    with AutomaticKeepAliveClientMixin {
  Widget child;

  final controller = NativeAdController();
  bool _showTheTopNativeAd = true;

  @override
  void initState() {
    super.initState();
    controller.load();
    controller.onEvent.listen((event) {
      setState(() {});
    });
  }

  @override
  Widget build(BuildContext context) {
    super.build(context);
    if (child != null) return child;
    return RefreshIndicator(
      onRefresh: () async {
        setState(() => child = SizedBox());
        await Future.delayed(Duration(milliseconds: 20));
        setState(() => child = null);
      },
      child: ListView(
        padding: EdgeInsets.all(10),
        children: [
          if (controller.isLoaded && _showTheTopNativeAd)
            NativeAd(
              controller: controller,
              height: 60,
              builder: (context, child) {
                return Material(
                  elevation: 8,
                  child: child,
                );
              },
              buildLayout: adBannerLayoutBuilder,
              loading: Text('loading'),
              error: Text('error'),
              icon: AdImageView(padding: EdgeInsets.only(left: 6)),
              headline: AdTextView(style: TextStyle(color: Colors.black)),
              advertiser: AdTextView(style: TextStyle(color: Colors.black)),
              body: AdTextView(style: TextStyle(color: Colors.black)),
              media: AdMediaView(height: 70, width: 120),
              button: AdButtonView(
                margin: EdgeInsets.only(left: 6, right: 6),
                textStyle: TextStyle(color: Colors.green, fontSize: 14),
                elevation: 18,
                elevationColor: Colors.amber,
              ),
            ),
          SizedBox(height: 10),
          FlatButton(
              onPressed: () {
                setState(() {
                  _showTheTopNativeAd = ! _showTheTopNativeAd;
                });
              },

              child: Text("Toggle Show")),
        ],
      ),
    );
  }

Screen Shots:

Before hiding it After hiding it
Screenshot_20210421-231600 Screenshot_20210421-231611
bdlukaa commented 3 years ago

I can reproduce it in the latest version.

bdlukaa commented 3 years ago

Hello. I did some testing and I couldn't find a fix for this, but I found a workaround.

@override
  Widget build(BuildContext context) {
    super.build(context);
    if (child != null) return child;
    return RefreshIndicator(
      onRefresh: () async {
        setState(() => child = SizedBox());
        await controller.load(force: true); // **HERE'S THE LINE**
        await Future.delayed(Duration(milliseconds: 20));
        setState(() => child = null);
      },
      child: ListView(
        padding: EdgeInsets.all(10),
        children: [

With that line everything works well.

I also found out that the media is also not showing up. It's weird that they're not showing up, but it's taking space (height and width) in the view.

ramtinq commented 3 years ago

Thanks. Your workaround works but it makes the reappearance of the NativeAd too much slow. I would want to know while we're hopping for a solution to make the bug fixed, is there any workaround for it to display the unresponsive, textless NativeAd immediately as a thumbnail, then wait for the await controller.load(force: true); to finish and replace the thumbnail-like NativeAd with the fully-loaded NativeAd?

ramtinq commented 3 years ago

I just found that your workaround also refreshes the ad content and shows new ads. My whole point of using the controller with showing-hiding the NativeAd is to move THE NativeAd in the widget tree from one widget to another, so first I remove it from the current parent, then add it to its new parent (first removing it so that we wont get the error mentioned in this issue: https://github.com/bdlukaa/native_admob_flutter/issues/38#issuecomment-823661297 ). The goal is to move the NativeAd in the widget tree in a seamless manner.

ramtinq commented 3 years ago

Tested https://github.com/googleads/googleads-mobile-flutter and toggle showing/hiding their AdWidget with Native ads does not make any problems. However their plugin makes animations so much slow and I prefer yours which is so much smoother (at least in Android).

I'm not expert at all in PlatformView s but I thought maybe taking a look at their implementation could help solving this bug.

EDIT: Well, their plugin works completely randomly and now I myself am unable to make their widget reappear successfully :(

bdlukaa commented 3 years ago

I have just found the reason this bug is happening. When the platform view is disposed (removed from the view), I also disposed the native ad, so if I re-added it to the view, it wouldn't work because the native ad is disposed.

    override fun dispose() {
        controller.nativeAd?.destroy()
    }

I'll publish a new version in 30 minutes with the fix for it and some more fixes.

bdlukaa commented 3 years ago

Published a new version 1.2.2. In this new version, the NativeAd object is only destroyed when the controller is disposed. Everything should work now.

If you still see this issue with the new version, please tell me so I can re-open.