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...

questionasker
  • 2,536
  • 12
  • 55
  • 119

5 Answers5

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
  • 237,138
  • 77
  • 654
  • 440
  • 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` – questionasker 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
  • 208
  • 4
  • 8
1

You can simply caught the exception as shown below:

myRewardVideoAd.show()
.catchError((e) => print("error in showing ad: ${e.toString()}"));
Jithin Jude
  • 840
  • 14
  • 19
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;
  }
};
Mehmet Ali Bayram
  • 7,222
  • 2
  • 22
  • 27
0

Please check whether you have add the payment information in your admob account. Seeing ads is disabled without giving these infos to Google. Admob Payments

Another problem could be that you account is not approved yet. This means that your account is new and you have to wait 24h up to 2 weeks.