Can I call InterstitialAd.loadAd(AdRequest) in a different thread than InterstitialAd.show()

1,799 views
Skip to first unread message

Zol Heyman

unread,
May 2, 2016, 10:01:22 PM5/2/16
to Google Mobile Ads SDK Developers
Is there any restriction on building the AdRequest and instantiating and loading an InterstitialAd using that AdRequest all in a worker thread, and showing the ad in the main thread. I'd like to attach the AdListener to the InterstitialAd object in the main thread as well.

Thanks,
Zol

Veer Arjun Busani(Mobile Ads SDK Team)

unread,
May 3, 2016, 10:07:13 AM5/3/16
to Google Mobile Ads SDK Developers
Hi Zol,

There is no such restriction for making an AdRequest on the background thread and then showing the actual ad on the main thread. Though all of this depends on your implementation. In certain cases, I would even recommend that you do this, such as, making multiple Ad Requests in a ListView.

Do let us know if you need any specific help with the implementation.

Thanks,
Veer Busani
Mobile Ads SDK Team

Zol Heyman

unread,
May 7, 2016, 10:34:28 PM5/7/16
to Google Mobile Ads SDK Developers
I tried using a background thread like you said, but I got this error:
Can't create handler inside thread that has not called Looper.prepare()
This looks like the error you get if the code must be executed on the UI Thread.

At first the error occurred when I called Builder.build() to create the AdRequest object. I tried moving that call into the main thread, but it just moved the error downstream when I called loadAd(AdRequest). I created the InterstitialAd object in the background thread too.

Any ideas?

Thanks,
Zol

Veer Arjun Busani(Mobile Ads SDK Team)

unread,
May 9, 2016, 11:03:02 AM5/9/16
to Google Mobile Ads SDK Developers
Hi Zol,

Would you mind sharing your sample app/code snippet of your implementation with us? This would be much easier to understand how you are trying to implement and debug the issue.

Thanks,
Veer Busani
Mobile Ads SDK Team

Zol Heyman

unread,
May 9, 2016, 5:22:07 PM5/9/16
to Google Mobile Ads SDK Developers
Here's the code. It fails with the error "Can't create handler inside thread that has not called Looper.prepare()" when it tries to execute the loadAd(adRequest). I tried moving the builder.build into the main thread and then moving the InterstitialAd constructor into the main thread, but as long as the loadAd(adRequest) was called in the background thread, it fails with that error. The Context parameter is the Activity it's called from in the onStart() method. The setContentView was called in onCreate so the message loop should already be active in the main UI thread.

private InterstitialAd admobAd2;
public void loadAds2(final Context context) {
new Thread() {
public void run() {
AdRequest.Builder builder = new AdRequest.Builder();
AdRequest adRequest = builder.build();
admobAd2 = new InterstitialAd(context);
admobAd2.setAdUnitId(context.getResources().getString(R.string.admobUnitId));
admobAd2.loadAd(adRequest);
}

}.start();
}

Veer Arjun Busani(Mobile Ads SDK Team)

unread,
May 10, 2016, 11:08:45 AM5/10/16
to Google Mobile Ads SDK Developers
Hi Zol,

I would suggest you to use AsyncTask to get this done. Do note that setAdListener() and loadAd() must always be called from the Main thread. You can however instantiate the InterstitialAd on the background thread. For example:

An AsyncTask can be -

  private class InterstitialTask extends AsyncTask<Void, Integer, String> {
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }

        @Override
        protected String doInBackground(Void... params) {
                try {
                    // Create the InterstitialAd and set the adUnitId.
                    mInterstitialAd = new InterstitialAd(getApplicationContext());
                    // Defined in res/values/strings.xml
                    mInterstitialAd.setAdUnitId(getString(R.string.ad_unit_id));

                    Thread.sleep(50);
                    mInterstitialAd.setAdListener(new AdListener() {
                        @Override
                        public void onAdClosed() {

                        }
                        @Override
                        public void onAdLoaded() {
                            publishProgress(100); //Random value here
                        }
                    });

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }


            return "All Done!";
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            if (values[0] == 100) {
                mInterstitialAd.show();
            }
        }

        @Override
        protected void onPostExecute(String result) {
            super.onPostExecute(result);
            Log.d("onPostExecute"," onPostExecute...");


            // Request a new ad if one isn't already loaded, hide the button, and kick off the timer.
            AdRequest adRequest = new AdRequest.Builder().build();
            mInterstitialAd.loadAd(adRequest);

        }
    }
and call it like this - new InterstitialTask().execute();

Zol Heyman

unread,
May 10, 2016, 1:38:41 PM5/10/16
to Google Mobile Ads SDK Developers
Ok, so I can't call loadAd() in the background thread, which was my original question. Your example code shows the setAdListener() call in the background, but you say it shouldn't be called there. I guess it should be in the onPostExecute() before the loadAdRequest().

My goal was to keep loading an ad with a particular eCPM until it was successful, while allowing some sleep time in between but not blocking the UI thread. The onPostExecute() in the AsyncTask does give me a way to schedule processing on the UI thread after sleeping in the background thread.  That's cleaner than writing my own code to post a message to a view Handler.

To implement the "looping until ad loaded" logic, I could keep creating and executing AsyncTasks with the sleep() in the background thread. There shouldn't be an issue of creating another AsyncTask and executing it from the onPostExecute(), right?

I'll give that a try.

Veer Arjun Busani(Mobile Ads SDK Team)

unread,
May 10, 2016, 4:30:37 PM5/10/16
to Google Mobile Ads SDK Developers
Hi Zol,

My apologies, I meant to write that only loadAd() must be called from the Main thread. You can certainly create another AsyncTask in onPostExecute() but I would suggest you to call it directly when onAdLoaded() is fired. Do let us know if you need anything else.

Thanks,
Veer Busani
Mobile Ads SDK Team

Zol Heyman

unread,
May 10, 2016, 10:40:09 PM5/10/16
to Google Mobile Ads SDK Developers
Besides loadAd(), In my experience, the Builder.build() that creates the AdRequest must also be called in the main thread.

Zol Heyman

unread,
May 12, 2016, 10:42:31 PM5/12/16
to Google Mobile Ads SDK Developers
The strategy I have described in the thread calls loadAd(AdRequest) every 30 seconds until an ad is served up at the specified eCPM floor. My implementation works, but ads stop being served up at all after a few minutes of testing. The adFailedToLoad() always returns an error code of 3: request succeeded but no ad in the inventory.

Is it possible that the requests are going unfilled because the ad server thinks the ads are coming from some sort of bot?

Veer Arjun Busani(Mobile Ads SDK Team)

unread,
May 13, 2016, 9:30:49 AM5/13/16
to Google Mobile Ads SDK Developers
Hi Zol,

The issue might due to server timeout when you are trying to loop a bunch of AdRequests. If you ever receive error code 3, I would suggest you to add a timer to wait a bit and request again.

Thanks,
Veer Busani
Mobile Ads SDK Team


Zol Heyman

unread,
May 13, 2016, 9:52:29 PM5/13/16
to Google Mobile Ads SDK Developers
This might be true if I was leaking HttpConnections (except error code 3 say the request is successful, but no ad inventory available). But wouldn't that be an AdMob deficiency?
Otherwise, you would think at least the first AdRequest would be serviced. Especially when that first request is made after waiting an hour between requests.

Veer Arjun Busani(Mobile Ads SDK Team)

unread,
May 16, 2016, 9:10:54 AM5/16/16
to Google Mobile Ads SDK Developers
Hi Zol,

If you consequently make a bunch of AdRequests, then there is always a chance of either time outs or no fills. The no fills error can happen due to other reasons as well, including any custom targeting or lack of inventory after a loop of AdRequests. Would you mind confirming that you were able to receive ads after waiting for a period of time after the no fills?

Thanks,
Veer Busani
Mobile Ads SDK Team

Zol Heyman

unread,
May 17, 2016, 1:19:06 PM5/17/16
to Google Mobile Ads SDK Developers
Yes, that's what I was seeing, but today that seemed to stop. Although, in the last couple weeks, my production version seems to be getting much better ads since the CTR is higher and my revenue is about 50% higher. The last half of April, my revenue trailed off. It made me wonder if advertiser dollar caps kicked in making the ad inventory a little thinner.

Anyway, I'm going to implement a slightly different strategy which shouldn't send multiple requests at the same time so don't spend too much time on this.

Thanks,
Zol
Reply all
Reply to author
Forward
0 new messages