画面の向きが変わってマルチスレッドが実行されているとき、Adview に問題があることがわかりました。これはAdviewのバグかもしれないと思います。この問題は、アプリケーション内のすべての Web ビューに影響します。Web ビューはコンテンツの読み込みを停止します。つまり、空白または以前に表示されていたコンテンツが表示されます。
テスト環境は
プラットフォーム: Google Nexus S + Android 4.1.2 (このプラットフォームだけでなく、他の多くのプラットフォーム、エミュレーターも影響を受けます)
Ads SDK: 6.4.1 (同じ問題がある Ads SDK 4.1.1 もテストしました)
この問題を再現する方法は、
次のマニフェスト、main.xml レイアウト、helloAndroid.java、および Ads SDK (6.4.1 以前のバージョン) を使用して Android プロジェクトを構築します。
上記のプラットフォームで HelloAndroid プロジェクトを実行するか、他のプラットフォームでも影響を受ける可能性のあるエミュレーターで実行します。
アプリの起動後、「OnCreate 関数が呼び出されました」と表示されます。また、コンテンツが読み込まれる時間も表示されます。その間、広告は画面の上部に表示されます。
ここで、[スレッドの計算を開始] ボタンをクリックすると同時に、画面を回転させて向きを変更し、すぐに向きを変更します。その間、最後の計算タスクが終了した直後に [スレッドの計算を開始] ボタンを連続してクリックします。これらのアクションを数回繰り返すと、Web ビューがリロードされないことがわかります。そのテキストは、画面を回転させるかどうかに関係なく、常に「バックグラウンド計算スレッドが完了しました」です。(「スレッド計算の開始」ボタンをクリックするかどうかに関係なく、そのテキストは「構成が変更されました」となる場合もあります)。Webview に表示される時刻も更新されません。広告は表示されません。
ログ ファイルから、次のような多くの広告エラーを確認できます。
11-17 11:51:11.254: I/Ads(7411): URL の取得中に AdLoader が 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: 私/広告 (7411): java.lang.NullPointerException
11-17 11:53:14.609: 私/広告 (7411): android.webkit.WebViewClassic.loadDataWithBaseURL (WebViewClassic.java:2564) で
11-17 11:53:14.609: 私/広告 (7411): android.webkit.WebView.loadDataWithBaseURL (WebView.java:842) で
11-17 11:53:14.609: 私/広告 (7411): com.google.ads.internal.AdWebView.loadDataWithBaseURL (SourceFile:229) で
11-17 11:53:14.609: 私/Ads(7411): com.google.ads.internal.c$c.run(SourceFile:164)
11-17 11:53:14.609: I/広告 (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: 私/広告 (7411): android.app.ActivityThread.main (ActivityThread.java:4745) で
11-17 11:53:14.609: I/Ads(7411): java.lang.reflect.Method.invokeNative(ネイティブ メソッド) で
11-17 11:53:14.609: I/広告 (7411): java.lang.reflect.Method.invoke (Method.java:511) で
11-17 11:53:14.609: 私/広告 (7411): com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run (ZygoteInit.java:786) で
11-17 11:53:14.609: 私/広告 (7411): com.android.internal.os.ZygoteInit.main (ZygoteInit.java:553) で
11-17 11:53:14.609: 私/広告 (7411): dalvik.system.NativeStart.main (ネイティブ メソッド) で
この問題は、次の観察結果に基づいて、webView またはスレッド プログラミングではなく、AdView が原因であると考えています。
webView を別のアクティビティに配置した場合、つまりマルチスレッド アクティビティにボタンと adView のみが含まれている場合でも、上記の再現手順の後にこの問題が発生することがわかりました。そして、問題が発生した後、webView を含む他のアクティビティを移動しましたが、それでも読み込みは停止します。つまり、問題を引き起こすのは webView ではありません。
計算スレッドは非常に単純で、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());
}
}
}