連載
» 2009年09月03日 00時00分 公開

Androidで動く携帯Javaアプリ作成入門(9):Netbookにも広まるAndroidで、かつてないWeb体験を (2/3)

[緒方聡,株式会社イーフロー]

同じコードでも、Webサイトによって動作が異なる?

 先ほどと同じプログラムでwww.yahoo.comとwww.google.comを読み込んでみました。同じプログラムで読み込んでいるにもかかわらず、見た目が若干異なります。分かりやすいように並べてみます。

 Yahoo!と比べると、Googleは<title>タグのところにページタイトルが表示され、faviconも表示されています。実は、Googleの方は自分で作成したWebViewとは別のWebブラウザが勝手に起動しているのです。

図5 Yahoo!とGoogleの比較 図5 Yahoo!(左)とGoogle(右)の比較

 Googleのページを閉じると、本来ここに読み込むはずだった真っ白のWebViewが出てきます。

図6 Webブラウザの裏に隠れていたアプリ 図6 Webブラウザの裏に隠れていたアプリ

 この現象はYahoo!のページでも、任意のリンクをクリックすると発生します。これは、どうしてでしょうか?答えは、連載第3回の「ブラウザや地図、ストリートビューの基、Intentとは?」で紹介したIntentにありました。

 Googleの場合は、接続元IPアドレスから各国のGoogleに適切にリダイレクトされるようになっています。新しいURLにアクセスする必要が出たWebViewは、そのURLを自分で表示せず、ActivityManagerによってIntentを発行し、発行されるIntentはWebページを表示させたいものであるため、結果として「Webブラウザが起動する」ということになります。リンクをクリックした場合も同様です。

 下記は、Googleにアクセスした際のログです。Intentが2回発行されているのが分かりますね。

08-10 22:26:32.269: INFO/ActivityManager(570): Starting activity: Intent { comp={com.example.android.web/com.example.android.web.Example01} (has extras) }
08-10 22:26:33.593: DEBUG/InetAddress(720): www.google.com: 66.249.89.99 (family 2, proto 6)
08-10 22:26:33.601: DEBUG/InetAddress(720): www.google.com: 66.249.89.147 (family 2, proto 6)
08-10 22:26:33.611: DEBUG/InetAddress(720): www.google.com: 66.249.89.104 (family 2, proto 6)
08-10 22:26:34.110: INFO/ActivityManager(570): Displayed activity com.example.android.web/.Example01: 1814 ms
08-10 22:26:35.160: INFO/ActivityManager(570): Starting activity: Intent { action=android.intent.action.VIEW categories={android.intent.category.BROWSABLE} data=http://www.google.cn/m comp={com.android.browser/com.android.browser.BrowserActivity} (has extras) }
08-10 22:26:35.239: DEBUG/PhoneWindow(720): couldn't save which view has focus because the focused view android.webkit.WebView@435cc958 has no id.
08-10 22:26:37.000: WARN/ActivityManager(570): Unable to start service Intent { comp={com.google.android.googleapps/com.google.android.googleapps.GoogleLoginService} }: not found
08-10 22:26:38.019: INFO/ActivityManager(570): Displayed activity com.android.browser/.BrowserActivity: 2853 ms
08-10 22:26:44.711: DEBUG/dalvikvm(720): GC freed 1404 objects / 128504 bytes in 306ms
08-10 22:26:44.839: DEBUG/webviewglue(720): nativeDestroy view: 0x207d70
08-10 22:26:45.159: DEBUG/InetAddress(742): www.google.cn: 203.208.37.104 (family 2, proto 6)
08-10 22:26:45.179: DEBUG/InetAddress(742): www.google.cn: 203.208.37.99 (family 2, proto 6)
08-10 22:26:45.220: DEBUG/InetAddress(742): www.google.cn: 203.208.37.160 (family 2, proto 6)
08-10 22:26:45.520: DEBUG/InetAddress(742): www.google.com: 66.249.89.104 (family 2, proto 6)
08-10 22:26:45.554: DEBUG/InetAddress(742): www.google.com: 66.249.89.99 (family 2, proto 6)
08-10 22:26:45.554: DEBUG/InetAddress(742): www.google.com: 66.249.89.147 (family 2, proto 6)

 Webブラウザを起動するのではなく、アプリ内のWebViewでリンク先も表示させたい場合は、「WebViewClient」というクラスを使用します。

WebView webView = new WebView(this);
webView.setWebViewClient(new WebViewClient());
webView.loadUrl(“http://www.yahoo.com”);
setContentView(webView, new LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,ViewGroup.LayoutParams.FILL_PARENT));

 このように、WebView#setWebViewClient(WebViewClient)を呼び出せばWebブラウザは起動されなくなり、WebView自身がWebを表示するためのクライアントになります。WebViewClientについては、後ほどもう少し詳しく解説します。

アドレスバーを、どこにレイアウトするか?

 アプリ内でWebブラウザを使用できるのなら、任意のURLを自由に入力できるようにしたいですね。

図7 URL入力欄 図7 URL入力欄

 やっていることは、EditTextでENTERが押されたら、入力されている文字列を取り出しWebViewに渡しているだけです。この画面のレイアウトはXMLで行っています。WebViewはAndroid Layout Editorでは編集できません。

図8 WebViewを含むレイアウトエディタ画面 図8 WebViewを含むレイアウトエディタ画面

 左側の「Views」に、WebViewが含まれていません。右側のレイアウト画面にWebViewがあるのは、XMLを直接編集したためです。ビューのサイズは、レイアウト画面に反映されるので、割り切って使うのなら問題ありません。

進む/戻るボタンを付けて閲覧履歴を管理するには?

 アドレス入力に加え、進むボタンと戻るボタンを付ければ、立派なWebブラウザです。

図9 進むボタン、戻るボタン 図9 進むボタン、戻るボタン

 WebViewには、以下の履歴管理用のメソッドが用意されています。

メソッド 説明
boolean canGoBack( ) 戻れるかどうか判定する
void goBack( ) 戻る
boolean canGoForward( ) 進めるかどうか判定する
void goForward( ) 進む
boolean canGoBackOrForward(int steps) 指定したステップ移動できるか判定する
void goBackOrForward(int steps) 指定したステップ移動する
表1 WebViewの履歴管理用メソッド

 canGoBack()とcanGoForward()を使用して、ボタンの活性/非活性をコントロールしています。この活性/非活性をどのタイミングで行うかというと、前述したWebViewClientのコールバックメソッド内で行います。

 ここは大事なので、ソースコードを見てみましょう。

class MyWebViewClient extends WebViewClient {
    @Override
    public void doUpdateVisitedHistory(WebView view, String url, boolean isReload) {
        back.setEnabled(webView.canGoBack());
        forward.setEnabled(webView.canGoForward());
    }
    @Override
    public void onPageFinished(WebView view, String url) {
        if (webView.getTitle() != null) {
            Example03.this.setTitle(webView.getTitle());
        }
    }
    @Override
    public void onPageStarted(WebView view, String url, Bitmap favicon) {
        Example03.this.setTitle("Loading...");
        back.setEnabled(webView.canGoBack());
        forward.setEnabled(webView.canGoForward());
    }
}

 WebViewClientを継承したクラスを作成し、ハンドリングしたいコールバックメソッドをオーバーライドします。今回は、以下の3つを使用しています。

メソッド 説明
void onPageStarted(…) ページ読み込み直後に呼び出される
void onPageFinished(…) ページ読み込み完了後に呼び出される
void doUpdateVisitedHistory(…) 履歴が更新されたタイミングで呼び出される
表2 WebViewClientのコールバックメソッド

 ページ読み込み開始時と履歴更新時に、ボタンの活性/非活性を制御しています。また、ついでにページ読み込み開始時にタイトルを「Loading……」にし、読み込み終了時にWebページのタイトルに変更しています。

 このようにして、作ったクラスのインスタンスを以下のようにWebViewに設定すればOKです。

webView = (WebView)findViewById(R.id.WebView01);
webView.setWebViewClient(new MyWebViewClient());

 進む/戻るボタンの制御も含め、わずか80行しかありません。本当にWebViewを使うととても簡単にWebブラウザアプリができてしまいます。

 次ページでは、タッチスクリーンによるモーションジェスチャーの付け方やWebViewの真骨頂であるJavaScriptとの連動の仕方を解説します。

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。