Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WebViewCoreThread used by admob AdView is using high CPU even when parent Activity is paused [duplicate]

I'm using Google Admob SDK v6.1.0 (https://developers.google.com/mobile-ads-sdk/download), and I instantiate the com.google.ads.AdView programmatically (not in XML), and add it into a LinearLayout, dynamically in my Activity.

One of my users reported that when they click the Home button while in my Activity (in order to background it), they start seeing high CPU usage sourced to my app. I was able to reproduce this on a Jellybean platform, and noticed that the source for high CPU usage was a WebViewCoreThread.

My Activity doesn't use any WebViews at all, but I was able to step through my Activity's initialization, and noticed that this WebViewCoreThread starts when I instantiate the AdMob AdView object. As state in the AdMob's references, I call destroy() on this AdView in my Activity's onDestroy() method. And I aso changed my code to call AdView.onDestroy() in my onPause() method. But nothing seems to be causing the WebViewCoreThread to stop. I guess, I'm okay if that thread sticks around. But if I start my Activity several times over and over again, this thread starts using anywhere between 8 to 25% of my CPU, even my activity is not in the foreground.

I noticed a few other users saying that you must call WebView.onPause() as a corrective action. (http://stackoverflow.com/questions/2040963/webview-threads-never-stop-webviewcorethread-cookiesyncmanager-http0-3) But this isn't directly possible for me, since my web view is created by AdMob's AdView. I also changed my code to call .removeAllViews() for mt Admob AdView's container LinearLayout object, and then call System.gc() to force garbage collection, but nothing seems to kill my WebViewCoreThread and eventually it starts eating up the CPU until I force-kill my app's process.

Any clues why AdMob is doing this, and how I can force this thread to be killed?

I'm attaching a class that I created to encapsulate AdView creation and destruction. I call this class's getNewAd() method in my activity's initialization. And I call this class's removeAd() in my Activity's onPause() and onDestroy() methods:

package com.shiprack.client;

import com.google.ads.AdRequest;
import com.google.ads.AdSize;
import com.google.ads.AdView;
import com.mobclix.android.sdk.Mobclix;
import com.mobclix.android.sdk.MobclixMMABannerXLAdView;

import android.app.Activity;
import android.view.Gravity;
import android.view.ViewGroup.LayoutParams;
import android.widget.LinearLayout;

public class AdManager {
    public AdManager(EventLog logger, LinearLayout container, Activity activity) {
        _container = container;
        _activity = activity;
        _eventLogger = logger;
    }

    public void setNetwork(int network) {
        _network = network;
    }

    public void getNewAd() {
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT);
        params.gravity = Gravity.CENTER;
        switch (_network) {
            case TrackDatabase.AD_NETWORK_ADMOB: {
                _admobBanner = new AdView(_activity, AdSize.BANNER, "a14dc419375634c");
                _container.addView(_admobBanner, params);
                _admobBanner.loadAd(new AdRequest());
                break;
            }
            case TrackDatabase.AD_NETWORK_MOBCLIX: {
                Mobclix.onCreate(_activity);
                _mobclixBanner = new MobclixMMABannerXLAdView(_activity);
                _container.addView(_mobclixBanner, params);
                _mobclixBanner.getAd();
                break;
            }
        }
    }

    public void removeAd() {
        switch (_network) {
            case TrackDatabase.AD_NETWORK_ADMOB: {
                _admobBanner.destroy();
                break;
            }
            case TrackDatabase.AD_NETWORK_MOBCLIX: {
                _mobclixBanner.cancelAd();
                break;
            }
        }
        _container.removeAllViews();
    }

    private EventLog _eventLogger;
    private LinearLayout _container;
    private Activity _activity;
    private AdView _admobBanner;
    private MobclixMMABannerXLAdView _mobclixBanner;
    private int _network;
}
like image 316
Shiprack Avatar asked Oct 14 '12 16:10

Shiprack


3 Answers

Not sure if anybody still needs this information, but I have been searching for a solution to this myself. Apparently AdMob is still flawed.

The only problem is, this will stop all WebViews from running in the background. Only a problem if your app depends on this to operate.

Add to onPause() :

new WebView(this).pauseTimers();

and to onResume() :

new WebView(this).resumeTimers();

This came from a Google Employee who claims that they are looking into it: https://groups.google.com/d/msg/google-admob-ads-sdk/Qu4G19NFAuI/wcNkoV0AeDUJ

like image 89
Bryan C Avatar answered Oct 31 '22 21:10

Bryan C


After calling destroy() on the admob AdView object, I now set the reference to null, which removes all references to the AdView, perhaps causing it to get garbage collected, and thus, avoiding any WebViewCoreThreads to be running indefinitely. Overall, I don't like this approach - such clean up work should be handled within the AdMob destroy. Or actually, I shouldn't even have to call destroy() - it slows down my activity onPause.

Big downside though: lots of my users are complaining slowness when pressing the back or home buttons in my app. Obviously, this is because of time being spent in the onPause() method while calling admob destroy(). The long-term solution is to use Fragments and ActionBar, and not have to create multiple copies of the Admob banner (one in every activity)

like image 3
Shiprack Avatar answered Oct 31 '22 19:10

Shiprack


PZolee posted on this subject and a proposed solution in his blog: https://pzoleeblogen.wordpress.com/2014/07/08/android-how-to-solve-adview-cpu-consuming/

I investigated this further (in the comments to the blog post are documented my struggles) and came to the following conclusion:

  1. Indeed, calling just adView.pause(); does not stop Google Ads component from consuming CPU even if the app is in background and ads are not visible.
  2. Finding all the WebViews inside a our adView and calling onPause() and onResume() WevView methods on them does not solve the problem of the unnecessary CPU consumption.
  3. Only the call to WebView pauseTimers() and resumeTimers() methods as the author of the above post proposes does stop the unnecessary CPU consumption.
  4. Finding recursively all the WebViews and calling pauseTimers() and resumeTimers() on all of them is unnecessary, since one such call “Pauses (or resumes – g.) all layout, parsing, and JavaScript timers for all WebViews. (within a process – g.)” – see WebView component docs.
  5. If you use a WebView anywhere else in your app – maybe in other activities, you must resumeTimers() for it, or it won’t work right. Also, be aware that a WevView may be constructed temporarily and used by some library functions you use in your project, without you explicitly knowing about it. It could be e.g. a prompt to login to some web site, social network etc. Such WebView may again not work right, if pauseTimers() was called in your process somewhere and you did not resume them. USE CAUTION AND TEST all you can.

It’s really a shame, that Google and AdMob handled us such a nasty surprise with their ad component (constant CPU consumption even if you background the app, hide their component, even pause() it with their own API call…

like image 3
gregko Avatar answered Oct 31 '22 20:10

gregko