4

当屏幕方向发生变化并且多线程正在运行时,我刚刚发现 Adview 出现问题。我认为这可能是 Adview 的错误。这个问题会影响应用程序中的所有 webviews。webviews 停止加载任何内容,即它们要么显示空白,要么显示之前显示的内容。

测试环境是

平台:Google Nexus S + Android 4.1.2(不只是这个平台,其他很多平台,连模拟器都受影响)

Ads SDK:6.4.1(我们也测试了 Ads SDK 4.1.1 也有同样的问题)

重现此问题的方法是

  1. 使用以下清单、main.xml 布局和 helloAndroid.java 以及 Ads SDK(6.4.1 或更低版本)构建一个 android 项目;

  2. 在上述平台上运行HelloAndroid项目,或者其他平台甚至模拟器也可能受到影响;

  3. 应用程序启动后,显示“已调用 OnCreate 函数”。在 webview 中,以及加载内容的时间。同时,广告显示在屏幕顶部;

  4. 现在点击“开始计算线程”按钮,同时旋转屏幕改变方向,然后立即再次改变方向,等等……同时,在最后一个计算任务完成后立即连续点击“开始计算线程”按钮。重复这些动作几次,然后你会注意到 webview 没有重新加载。无论您是否旋转屏幕,它的文本始终是“后台计算线程完成”。(无论您是否单击“开始计算线程”按钮,其文本也可能是“配置更改”)。webview 中显示的时间也不会更新。不显示广告。

从日志文件中,我们可以看到很多广告错误,例如:

11-17 11:51:11.254: I/Ads(7411): AdLoader 在获取 URL 时在 60000 毫秒后超时。

11-17 11:51:11.254: I/Ads(7411): onFailedToReceiveAd(发生网络错误。)

我们也得到了一个异常,但是这个异常出现在上面的错误出来之后。

11-17 11:53:14.597: W/Ads(7411): 在 AdWebView 中加载数据时出错:

11-17 11:53:14.609: I/Ads(7411): 捕获并处理了以下内容:

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

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

11-17 11:53:14.609: I/Ads(7411): 在 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): 在 android.os.Handler.handleCallback(Handler.java:615)

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

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

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

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

11-17 11:53:14.609: I/Ads(7411): 在 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)

我们认为这个问题是由 AdView 引起的,而不是由 webView 或基于以下观察的线程编程引起的:

  1. 我们发现,即使我们把webView放到另外一个activity中,即多线程activity中只包含一个button和adView,经过上面的复现步骤,还是会出现这个问题。在问题出现后,我们移动了包含 webView 的其他活动,它仍然停止加载任何内容。换句话说,不是 webView 触发了问题。

  2. 计算线程非常简单,不包含任何UI操作。开始和停止加载广告总是在主线程中完成。

代码非常简单。清单文件是:

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

唯一的布局文件是:

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

HelloAndroid.java 文件是:

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());
        }
    }
}
4

0 回答 0