WebView のエラー処理
前の記事に書いた通り、Android 版の Web 表示器を作った時には、エラー処理のためにアプリを開発しました。
特に重要なエラー処理は「タイムアウト」の処理です。工場向けの表示器としては、通信異常が発生したからといって30秒も画面が止まってしまうようでは使い物になりません。
shouldInterceptRequest
WebView のエラー処理を実装する際には WebViewClient.shouldInterceptRequest をオーバーライドするのが最も柔軟な方法です。
以下にコードを示します。この記事に紹介するコードはアプリを書いた当時のものでかなり古いのですが、今でも基本的な考え方は変わっていないようです。
webView.setWebViewClient(new WebViewClient() {
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
// url が HTTP だった場合に、自分で通信してレスポンスを作る
if (url.matches("https?://[¥¥w¥¥.¥¥-]+(/.*)?")) {
// 通信の準備
HttpGet req = new HttpGet(url);
HttpParams params = req.getParams();
// タイムアウトを設定する
HttpConnectionParams.setConnectionTimeout(params, 1000);
HttpConnectionParams.setSoTimeout(params, 2000);
DefaultHttpClient client = new DefaultHttpClient();
try {
// 通信開始
HttpResponse res = client.execute(req);
// ステータスコードを確認
if (HttpStatus.SC_OK != res.getStatusLine().getStatusCode()) {
throw new Exception();
}
// 正常な応答を記憶しておく
HttpEntity entity = res.getEntity();
String mimeType = null, encoding = null;
Header mimeHeader = entity.getContentType();
if (null != mimeHeader) mimeType = mimeHeader.getValue();
Header encodingHeader = entity.getContentEncoding();
if (null != encodingHeader) encoding = encodingHeader.getValue();
byte[] data = EntityUtils.toByteArray(entity);
_lastGootResponse = new WebResponseArchive();
_lastGootResponse.data = data;
_lastGootResponse.mime = mimeType;
_lastGootResponse.encoding = encoding;
_lastGootResponse.url = url;
_errCount = 0;
} catch (Exception e) {
// 正常な応答ではなかった場合の処理
_errCount++;
// 次回のリロード時間を1秒後に設定する
} finally {
// 通信を終了する
req.abort();
client.getConnectionManager().shutdown();
}
// 必要に応じて正常応答記録を削除する
if (null != _lastGootResponse) {
if (_errCount >= 3 || !url.equals(_lastGootResponse.url)) {
_lastGootResponse = null;
}
}
// 正常応答記録がなければ空のリソースを返して onReceivedError を発生させる
if (null == _lastGootResponse) {
return new WebResourceResponse(null, null, null);
}
// 正常な応答(またはキャッシュ応答)を返す
WebResponseArchive a = _lastGootResponse;
return new WebResourceResponse(a.mime, a.encoding, new ByteArrayInputStream(a.data));
}
// url が HTTP ではなかった場合の処理
_lastGootResponse = null;
return super.shouldInterceptRequest(view, url);
}
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
// エラー画面表示
// 自動回復のためのリロード処理を仕掛ける
}
});
エラー発生時の処理
上記のコード例は、接続のタイムアウトが1秒に設定されています。タイムアウトが発生した場合には「次回のリロード時間を1秒後に設定する」処理が実行されます。この時、WebView には正常な応答(キャッシュ応答)が返されます。WebView でエラーが発生するのは内部のエラーが3回発生した以降です。
実際のアプリでもほぼコード例の通り、エラーが発生してもすぐにエラー画面にはならないようになっています。他にもいくつかの工夫により、表示器アプリは「安定した表示」「エラーに対する高速な応答」「自動回復」を実現しています。
ところで、表示器のために作ったはずの表示器アプリですが、工場ではもう少し別の用途でも使われています。次の記事では、表示器アプリの活用事例を紹介してみたいと思います。
この記事の投稿者
この投稿者の最近の記事
- 2020年5月30日さきラボFA-HAT 開発中
- 2020年4月11日さきラボ工場の設備をネットワークで接続したいけど何をどうしたらいいのか? そんな時はおまかせください!
- 2020年4月10日さきラボテレワークを推奨しない理由
- 2019年10月6日Raspberry Pi と PLC で作る Factory Automationファイルシステムの変換方法