10

i try to reload Rewarded Video Ads, when i call RewardedVideoAd.instance.load(adUnitId: "xxx", targetingInfo: xyz); i find below error :

W/MessageQueue(13672): Handler (android.os.Handler) {1a13e8a} sending message to a Handler on a dead thread W/MessageQueue(13672): java.lang.IllegalStateException: Handler (android.os.Handler) {1a13e8a} sending message to a Handler on a dead thread W/MessageQueue(13672): at android.os.MessageQueue.enqueueMessage(MessageQueue.java:543) W/MessageQueue(13672): at android.os.Handler.enqueueMessage(Handler.java:643) W/MessageQueue(13672): at android.os.Handler.sendMessageAtTime(Handler.java:612) W/MessageQueue(13672): at android.os.Handler.sendMessageDelayed(Handler.java:582) W/MessageQueue(13672): at android.os.Handler.sendEmptyMessageDelayed(Handler.java:546) W/MessageQueue(13672): at android.os.Handler.sendEmptyMessage(Handler.java:531) W/MessageQueue(13672): at com.google.android.gms.ads.exoplayer1.h.c(:com.google.android.gms.policy_ads_fdr_dynamite@20300003@20300003.251657827.251657827:2) W/MessageQueue(13672): at com.google.android.gms.ads.internal.video.exoplayer1.f.b(:com.google.android.gms.policy_ads_fdr_dynamite@20300003@20300003.251657827.251657827:1) W/MessageQueue(13672): at com.google.android.gms.ads.internal.webview.t.E(:com.google.android.gms.policy_ads_fdr_dynamite@20300003@20300003.251657827.251657827:5) W/MessageQueue(13672): at com.google.android.gms.ads.internal.webview.j.onPageFinished(:com.google.android.gms.policy_ads_fdr_dynamite@20300003@20300003.251657827.251657827:2) W/MessageQueue(13672): at uU.d(PG:307) W/MessageQueue(13672): at aIV.handleMessage(PG:73) W/MessageQueue(13672): at android.os.Handler.dispatchMessage(Handler.java:102) W/MessageQueue(13672): at android.os.Looper.loop(Looper.java:154) W/MessageQueue(13672): at android.app.ActivityThread.main(ActivityThread.java:6780) W/MessageQueue(13672): at java.lang.reflect.Method.invoke(Native Method) W/MessageQueue(13672): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1496) W/MessageQueue(13672): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1386) W/ExoPlayerImplInternal(13672): Sent message(1) after release. Message ignored. D/Graph (13672): removeVertex() : insertDummyVertex, because there is no ancestor. D/ViewRootImpl@b8db50eAdActivity: mHardwareRenderer.destroy()#4 D/ViewRootImpl@b8db50eAdActivity: dispatchDetachedFromWindow

i place the listener in initState() of my screen. in this screen i have a button where if we tap it, it should show Rewarded Video Ads.

Moreover, after getting error when Rewarded Ads reloaded, i got below error after tap the button to show ads (because ads instance was null):

E/flutter (13672): [ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: PlatformException(ad_not_loaded, show failed for rewarded video, no ad was loaded, null) E/flutter (13672): #0 StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:564:7) E/flutter (13672): #1 MethodChannel.invokeMethod (package:flutter/src/services/platform_channel.dart:316:33) E/flutter (13672): E/flutter (13672): #2 _invokeBooleanMethod (package:firebase_admob/firebase_admob.dart:518:61) E/flutter (13672): E/flutter (13672): #3 RewardedVideoAd.show (package:firebase_admob/firebase_admob.dart:392:12)

I place Rewarded Video Ads Listener at initState(), below are the codes:

@override
  void initState() {
    super.initState();
...
    RewardedVideoAd.instance.listener =
        (RewardedVideoAdEvent event, {String rewardType, int rewardAmount}) {
      if (event == RewardedVideoAdEvent.completed) {
        setState(() {
          print ("::debug:: ads should be reloaded");
          RewardedVideoAd.instance.load(adUnitId: "ca-app-pub-3940256099942544/5224354917", targetingInfo: targetingInfos);
        });
      }
    };
...

However, if i put code at button's onPressed like below, the video ads will show after tap for 2-3 times (where at debug is show ads = null)

RaisedButton(
  onPressed: () {
    RewardedVideoAd.instance.show().whenComplete(() {
              RewardedVideoAd.instance.load(adUnitId: "ca-app-pub-3940256099942544/5224354917", targetingInfo: targetingInfos);
    })    
},
...

Any Idea ?

Thanks in Advance...

zukijuki
  • 2,053
  • 3
  • 36
  • 87

4 Answers4

7

Seems like the issue was with the event completed. Check out this code.

MobileAdTargetingInfo targetingInfo = MobileAdTargetingInfo(
  keywords: <String>['flutterio', 'beautiful apps'],
  contentUrl: 'https://flutter.io',
  childDirected: false,
  testDevices: <String>[], // Android emulators are considered test devices
);
bool _loaded = false;

@override
void initState() {
  super.initState();

  // load ad in the beginning
  RewardedVideoAd.instance
      .load(adUnitId: RewardedVideoAd.testAdUnitId, targetingInfo: targetingInfo)
      .catchError((e) => print("error in loading 1st time"))
      .then((v) => setState(() => _loaded = v));

  // ad listener
  RewardedVideoAd.instance.listener = (RewardedVideoAdEvent event, {String rewardType, int rewardAmount}) {
    if (event == RewardedVideoAdEvent.closed) {
      RewardedVideoAd.instance
          .load(adUnitId: RewardedVideoAd.testAdUnitId, targetingInfo: targetingInfo)
          .catchError((e) => print("error in loading again"))
          .then((v) => setState(() => _loaded = v));
    }
  };
}


@override
Widget build(BuildContext context) {
  return Scaffold(
    body: Center(
      child: Text(
        "Loaded = ${_loaded}",
        style: TextStyle(fontSize: 32, fontWeight: FontWeight.bold),
      ),
    ),
    floatingActionButton: FloatingActionButton(
      // show ad on FAB click
      onPressed: () async {
        await RewardedVideoAd.instance.show().catchError((e) => print("error in showing ad: ${e.toString()}"));
        setState(() => _loaded = false);
      },
    ),
  );
}
CopsOnRoad
  • 109,635
  • 30
  • 367
  • 257
  • Hi, thank you very much. now it works. but i still curious why everytime i tap close (X) of admob screen, in debug show error : `Handler (android.os.Handler) {e7884a7} sending message to a Handler on a dead thread W/MessageQueue(28400): java.lang.IllegalStateException: Handler (android.os.Handler) {e7884a7} sending message to a Handler on a dead thread` – zukijuki Jul 26 '19 at 06:46
  • OK, so my emulator isn't opening. LOL, when I get to my Android real device, I will give it a try. – CopsOnRoad Jul 26 '19 at 06:57
5

No need for calling set state as it is expensive and causes a full rebuild.

This problem can easily be fixed in the following way:

import 'package:flutter/material.dart';
import 'package:firebase_admob/firebase_admob.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: HomePage());
  }
}

class HomePage extends StatefulWidget {
  HomePage({Key key}) : super(key: key);

  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  //The targeting info required for Rewarded Videos Ads
  MobileAdTargetingInfo targetingInfo = MobileAdTargetingInfo(
    keywords: <String>['flutterio', 'beautiful apps'],
    contentUrl: 'https://flutter.io',
    childDirected: false,
    testDevices: <String>[], // Android emulators are considered test devices
  );

  //An instance to be called in the init state
  RewardedVideoAd _videoAd = RewardedVideoAd.instance;

  @override
  void initState() {
    //---------------------------------------//
    //Initialise the listener with the values.
    _videoAd.listener =
        (RewardedVideoAdEvent event, {String rewardType, int rewardAmount}) {
      if (event == RewardedVideoAdEvent.completed) {
        //When the video ad gets completed load a new video ad
        _videoAd
            .load(
                adUnitId: RewardedVideoAd.testAdUnitId,
                targetingInfo: targetingInfo)
            .catchError((e) => print('Error in loading.'));
      }

      //On every other event change pass the values to the _handleEvent Method.
      _handleEvent(event, rewardType, 'Reward', rewardAmount);
    };
    //------------------------------------------------------------------//

    //This will load the video when the widget is built for the first time.
    _videoAd
        .load(
            adUnitId: RewardedVideoAd.testAdUnitId,
            targetingInfo: targetingInfo)
        .catchError((e) => print('Error in loading.'));

    //-----------------------------------------------------//
    super.initState();
  }

  //---- Useful function to know exactly what is being done ----//
  void _handleEvent(RewardedVideoAdEvent event, String rewardType,
      String adType, int rewardAmount) {
    switch (event) {
      case RewardedVideoAdEvent.loaded:
        _showSnackBar('New Admob $adType Ad loaded!', 1500);
        break;
      case RewardedVideoAdEvent.opened:
        _showSnackBar('Admob $adType Ad opened!', 1500);
        break;
      //
      //The way we are fixing the issue is here.
      //This is by calling the video to be loaded when the other rewarded video is closed.
      case RewardedVideoAdEvent.closed:
        _showSnackBar('Admob $adType Ad closed!', 1500);
        _videoAd
            .load(
                adUnitId: RewardedVideoAd.testAdUnitId,
                targetingInfo: targetingInfo)
            .catchError((e) => print('Error in loading.'));
        break;
      case RewardedVideoAdEvent.failedToLoad:
        _showSnackBar('Admob $adType failed to load.', 1500);
        break;
      case RewardedVideoAdEvent.rewarded:
        _showSnackBar('Rewarded $rewardAmount', 3000);
        break;
      default:
    }
  }

  //Snackbar shown with ad status
  void _showSnackBar(String content, int duration) {
    Scaffold.of(context).showSnackBar(SnackBar(
      content: Text(content),
      duration: Duration(milliseconds: duration),
    ));
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: FlatButton(
          child: Text('Play AD'),
          onPressed: () {
            _videoAd.show().catchError(
                (e) => print("error in showing ad: ${e.toString()}"));
          },
        ),
      ),
    );
  }
}


Rohit Singh
  • 124
  • 2
  • 6
1

You can simply caught the exception as shown below:

myRewardVideoAd.show()
.catchError((e) => print("error in showing ad: ${e.toString()}"));
Jithin Jude
  • 525
  • 10
  • 14
1

Hi I think the best solution is using try catch and if there is a problem we can try to show it again. Here is my code;

MobileAdTargetingInfo targetingInfo = MobileAdTargetingInfo(
  keywords: <String>['flutterio', 'beautiful apps'],
  contentUrl: 'https://flutter.io',
  childDirected: false,
  testDevices: <String>[],
);

String adUnit = "ca-app-pub-6288831324909345/9733176442";
bool tryAgain = false;

await RewardedVideoAd.instance
    .load(adUnitId: adUnit, targetingInfo: targetingInfo);

try {
  await RewardedVideoAd.instance.show();
} on PlatformException catch (e) {
  tryAgain = true;
  print(e.message);
}

RewardedVideoAd.instance.listener =
    (RewardedVideoAdEvent event, {String rewardType, int rewardAmount}) {
  switch (event) {
    case RewardedVideoAdEvent.rewarded:
      setState(() {
        // Here, apps should update state to reflect the reward.
        print("_goldCoins += rewardAmount");
      });
      break;

    case RewardedVideoAdEvent.loaded:
      if (tryAgain) RewardedVideoAd.instance.show();
      break;

    default:
      print(event.toString());
      break;
  }
};
malibayram91
  • 4,575
  • 2
  • 15
  • 19