前回に引き続き、今回はWebView。
HTMLはローカル、画像はWebにある場合に、Picassoのメモリキャッシュを利用してオフラインでも画像を表示できる(かもしれない)。
ディスクキャッシュはオフラインでは利用できないため、利用したい場合はアプリ側で別途保持するなどの対応が必要。
Android4.3以前での注意点
以降は基本的にAndroid4.4以降向け。
Android4.3以前ではWebView#loadUrl()
に渡す引数が長すぎるため、以下のエラーが発生してしまう。
Uncaught SyntaxError: Unexpected token ILLEGAL
Android4.3以前で同様の対応をするには、@kaaさんの[Android] native→webviewへ大きめのデータを渡すにあるように、分割して渡す必要がある。
assets内のHTML
画像を表示する要素(div
)と画像を設定するJavascript(loadImage
)があるだけ。
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
function loadImage(id, mime, base64) {
document.getElementById(id).innerHTML = "<img src='data:" + mime + ";base64," + base64 + "'/>";
}
</script>
</head>
<body>
<div id="image_area">
<!-- ここに画像を表示 -->
</div>
</body>
</html>
Targetを実装したクラス
前回のActionBarアイコンを設定する方法同様、Target
を実装したクラスを作成する。
読み込み完了時にBase64エンコードして上記Javascriptを実行している。onPrepareLoad
とonBitmapFailed
は省略。
public class WebViewTarget implements Target {
private WebView mWebView;
private String mId;
public WebViewTarget(WebView webView, String id) {
mWebView = webView;
mId = id;
}
@Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
@Override
public void onBitmapLoaded(Bitmap bitmap, LoadedFrom from) {
String base64 = toBase64(bitmap);
String js = String.format("javascript:loadImage('%s','%s','%s')", mId, "image/png", base64);
mWebView.loadUrl(js);
}
@Override
public void onBitmapFailed(Drawable errorDrawable) {
}
private String toBase64(Bitmap bitmap) {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
try {
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] bytes = stream.toByteArray();
return Base64.encodeToString(bytes, Base64.DEFAULT);
} finally {
try {
stream.close();
} catch (IOException e) {
}
}
}
呼び出し元
assets内のHTML読み込み完了後、Picassoで画像を読み込む。
メモリキャッシュがある場合は同期的に実行されるため、WebViewClient#onPageFinished
以降に実行しないとUncaught ReferenceError: loadImage is not defined
などと怒られる。
final WebView webView = (WebView) findViewById(R.id.web);
webView.getSettings().setDefaultTextEncodingName("UTF-8");
webView.getSettings().setJavaScriptEnabled(true);
webView.setWebViewClient(new WebViewClient() {
private WebViewTarget mWebViewTarget = new WebViewTarget(webView, "image_area");
@Override
public void onPageFinished(WebView view, String url) {
Picasso.with(MainActivity.this).load("<画像のURL>").into(mWebViewTarget);
}
});
webView.loadUrl("file:///android_asset/index.html");