AdView bug causing all webviews stop loading when orientation changes and multi-threads are running?

假装没事ソ 提交于 2019-12-07 11:39:06

问题


I just found a problem with Adview when screen orientation changes and multi-threads are running. I think this might be a bug of Adview. And this problem impacts all the webviews in the application. The webviews stop loading any content, i.e. they either show blank or the content that was shown before.

The test environment is

Platform: Google Nexus S + Android 4.1.2 (not only this platform, a lot of other platforms, even the emulators are affected)

Ads SDK: 6.4.1 (we also tested Ads SDK 4.1.1 which has the same problem)

The way to reproduce this issue is

  1. construct an android project using the following manifest, main.xml layout and helloAndroid.java, and also Ads SDK (6.4.1 or lower version);

  2. run the HelloAndroid project in the above platform, or other platforms even emulators which may also be affected;

  3. After the app starts, it shows "OnCreate function called." in the webview, and also the time when the content is loaded. Meanwhile, ads show on the top of the screen;

  4. Now click the "Start Calculating Thread" button, at the same time, rotate screen to change its orientation, then immediately change orientation again, etc... meanwhile, continuously click the "Start Calculating Thread" button immediately after last calculating task finishes. Repeat these actions for a few times, then you will notice that the webview does not reload. Its text is always "Background calculating thread done" whether you rotate screen or not. (Its text could also be "Configuration changed" whether you click the "Start Calculating Thread" button or not). The time shown in the webview is not updated either. The ads are not shown.

From the log file, we can see a lot of ads errors like:

11-17 11:51:11.254: I/Ads(7411): AdLoader timed out after 60000ms while getting the URL.

11-17 11:51:11.254: I/Ads(7411): onFailedToReceiveAd(A network error occurred.)

We also get an exception, but this exception appears after the above error came out.

11-17 11:53:14.597: W/Ads(7411): An error occurred while loading data in AdWebView:

11-17 11:53:14.609: I/Ads(7411): The following was caught and handled:

11-17 11:53:14.609: I/Ads(7411): java.lang.NullPointerException

11-17 11:53:14.609: I/Ads(7411): at android.webkit.WebViewClassic.loadDataWithBaseURL(WebViewClassic.java:2564)

11-17 11:53:14.609: I/Ads(7411): at android.webkit.WebView.loadDataWithBaseURL(WebView.java:842)

11-17 11:53:14.609: I/Ads(7411): at com.google.ads.internal.AdWebView.loadDataWithBaseURL(SourceFile:229)

11-17 11:53:14.609: I/Ads(7411): at com.google.ads.internal.c$c.run(SourceFile:164)

11-17 11:53:14.609: I/Ads(7411): at android.os.Handler.handleCallback(Handler.java:615)

11-17 11:53:14.609: I/Ads(7411): at android.os.Handler.dispatchMessage(Handler.java:92)

11-17 11:53:14.609: I/Ads(7411): at android.os.Looper.loop(Looper.java:137)

11-17 11:53:14.609: I/Ads(7411): at android.app.ActivityThread.main(ActivityThread.java:4745)

11-17 11:53:14.609: I/Ads(7411): at java.lang.reflect.Method.invokeNative(Native Method)

11-17 11:53:14.609: I/Ads(7411): at java.lang.reflect.Method.invoke(Method.java:511)

11-17 11:53:14.609: I/Ads(7411): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)

11-17 11:53:14.609: I/Ads(7411): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)

11-17 11:53:14.609: I/Ads(7411): at dalvik.system.NativeStart.main(Native Method)

We believe this issue is caused by AdView not by webView or the thread programming based on the following observations:

  1. We have found that, even if we place the webView in another activity, i.e. the multithread activity only includes a button and adView, this problem still comes out after the above reproducing steps. And after the problem comes we move the other activity which includes the webView, it still stops loading anything. In other words, it is not the webView who triggers the problem.

  2. The calculating thread is very simple, no UI operation is included in it. Start and stop loading ads are always done in the main thread.

The codes are quite simple. The manifest file is:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.example.helloandroid"
      android:versionCode="1"
      android:versionName="1.0">
    <uses-sdk android:minSdkVersion="7" />
    <!--  uses-permission android:name="android.permission.INTERNET"/-->

    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".HelloAndroid"
                  android:label="@string/app_name"
                  android:configChanges="orientation|keyboardHidden|screenSize">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name="com.google.ads.AdActivity"
              android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"/>
    </application>
</manifest>

The only layout file is:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:ads="http://schemas.android.com/apk/lib/com.google.ads"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
    <LinearLayout 
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:id="@+id/adsHolder" >
    </LinearLayout>

    <android.webkit.WebView
        android:id="@+id/webview_show_something"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_above="@+id/button1"
        android:layout_below="@+id/adsHolder"
    ></android.webkit.WebView>

    <Button
        android:id="@+id/button1"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:text="Start Calculating Thread" />

</RelativeLayout>

And the HelloAndroid.java file is:

package com.example.helloandroid;

import java.text.DateFormat;
import java.util.Date;

import com.google.ads.AdRequest;
import com.google.ads.AdSize;
import com.google.ads.AdView;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;

public class HelloAndroid extends Activity {
    // Need handler for callbacks to the UI thread
    public Handler mHandler;

    public WebView mwebView;

    public AdView madView;

    public Thread mthread = null;
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mHandler = new Handler();   // handler is attached to the UI thread.

        Button btn = (Button) findViewById(R.id.button1);
        btn.setOnClickListener(new OnClickListener(){

            @Override
            public void onClick(View v) {
                final ProgressDialog dlgProgress = ProgressDialog.show(HelloAndroid.this, "Please wait",
                        "Background calculating ...", true);
                mthread = new Thread(new Runnable(){

                    @Override
                    public void run() {
                        for (int idx = 0; idx < 10000; idx ++)  {
                            for (int idx1 = 0; idx1 < 10; idx1 ++)  {
                                int a = idx + idx1;
                                a ++;
                            }
                        }
                        mHandler.post(new Runnable()    {

                            @Override
                            public void run() {
                                dlgProgress.dismiss();
                                if (madView != null)    {
                                    madView.loadAd(new AdRequest());
                                }
                                String currentDateTimeString = DateFormat.getDateTimeInstance().format(new Date());

                                mwebView.loadDataWithBaseURL("http://",
                                        "<html><body><h1>Background calculating thread done.</h1><p>" + currentDateTimeString + "</p></body></html>",
                                        "text/html","utf-8","");
                                mthread = null;
                            }
                        });
                    }
                });
                if (madView != null)    {
                    madView.stopLoading();
                }
                mthread.start();

            }

        });

        mwebView = (WebView)findViewById(R.id.webview_show_something);
        mwebView.setVerticalScrollBarEnabled(true);
        mwebView.setHorizontalScrollBarEnabled(true);
        mwebView.getSettings().setBuiltInZoomControls(true);
        mwebView.setWebViewClient(new WebViewClient());

        String currentDateTimeString = DateFormat.getDateTimeInstance().format(new Date());

        mwebView.loadDataWithBaseURL("http://",
                "<html><body><h1>OnCreate function called.</h1><p>" + currentDateTimeString + "</p></body></html>",
                "text/html","utf-8","");
        startLoadingAds();

    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        // because it is smart_banner, adview has to be dynamically generated to fit landscape or portrait screen.
        stopLoadingAds();
        if (mthread == null)    {   // only if calculating thread finishes we start to load ads.
            startLoadingAds();
        }
        String currentDateTimeString = DateFormat.getDateTimeInstance().format(new Date());

        mwebView.loadDataWithBaseURL("http://",
                "<html><body><h1>Configuration changed.</h1><p>" + currentDateTimeString + "</p></body></html>",
                "text/html","utf-8","");
    }

    public void stopLoadingAds()    {
        // reset the adView.
        if (madView != null)    {
            madView.stopLoading();
            ViewGroup viewGroup = (ViewGroup) madView.getParent();
            if (viewGroup != null)
            {
                viewGroup.removeView(madView);
            }
            madView.removeAllViews();
            madView.destroy();  // not required.
            madView = null;
        }
    }

    public void startLoadingAds()   {
        LinearLayout layoutAdView = (LinearLayout)findViewById(R.id.adsHolder);
        layoutAdView.removeAllViews();
        madView = new AdView(this, AdSize.SMART_BANNER, "ca-app-pub-9004844319824679/3238161316");
        if (madView != null)    {
            layoutAdView.addView(madView, new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
            madView.loadAd(new AdRequest());
        }
    }
}

来源:https://stackoverflow.com/questions/20026268/adview-bug-causing-all-webviews-stop-loading-when-orientation-changes-and-multi

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!