Android WebView运行数小时后触发SQLite错误,onReceivedError无法捕获
我来帮你拆解下这个问题——你碰到的是Android WebView在长时间运行后,WebKit底层组件尝试打开SQLite数据库失败导致的应用崩溃,而且onReceivedError抓不到这个错误很正常,因为它属于WebView内部的数据库操作异常,不是网页加载层面的错误。
错误原因分析
从你升级后的日志能看到,WebKit一直在尝试从根目录/打开FileSyetmQuota.db和NotificationPermissions.db,但根目录是没有访问权限的(errno=2是文件不存在/权限不足),SQLite错误码14就是无法打开数据库文件。
在Android 4.1.2(Jelly Bean)上,WebView的数据库默认应该存在应用私有目录的databases文件夹下,出现这种路径错误,大概率是WebView长时间运行后状态异常,导致内部路径解析出了问题,或者数据库目录的权限配置有问题。
具体解决方案
1. 手动指定WebView数据库存储路径
强制让WebView把数据库存在应用私有目录里,避免它跑到根目录去访问:
// 在初始化WebView之前执行 Context appContext = getApplicationContext(); String webViewDataDir = appContext.getDir("webview_databases", Context.MODE_PRIVATE).getPath(); WebSettings webSettings = webView.getSettings(); // 启用数据库存储 webSettings.setDatabaseEnabled(true); // 指定数据库路径(仅Android 4.4及以下有效) webSettings.setDatabasePath(webViewDataDir); // 同时启用DOM存储,避免其他存储相关异常 webSettings.setDomStorageEnabled(true);
2. 优化WebView生命周期管理,避免状态异常
长时间持有WebView实例很容易导致内存泄漏和内部状态混乱,记得在页面生命周期里及时释放资源:
@Override protected void onPause() { super.onPause(); // 暂停WebView的JavaScript执行和渲染 webView.onPause(); } @Override protected void onResume() { super.onResume(); webView.onResume(); } @Override protected void onDestroy() { // 先清空页面,再销毁WebView webView.loadUrl("about:blank"); webView.stopLoading(); webView.destroy(); super.onDestroy(); }
3. 清理WebView缓存和异常数据库
如果已经出现过数据库异常,可以在应用启动时清理WebView的数据库目录,避免残留的损坏文件导致后续错误:
// 在初始化WebView之前执行 File webViewDbParent = new File(appContext.getDatabasePath("webview.db").getParent()); if (webViewDbParent.exists()) { deleteFolderRecursively(webViewDbParent); } // 递归删除文件夹的工具方法 private void deleteFolderRecursively(File folder) { if (folder.isDirectory()) { for (File file : folder.listFiles()) { deleteFolderRecursively(file); } } folder.delete(); }
4. 全局捕获未处理异常,避免应用直接终止
既然onReceivedError抓不到底层异常,你可以设置全局异常处理器,在崩溃前记录日志或者尝试恢复:
Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> { Log.e("WebViewCrash", "出现未捕获异常", throwable); // 这里可以做一些恢复操作,比如重启当前Activity Intent intent = new Intent(this, YourMainActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); startActivity(intent); finish(); });
总结
优先尝试指定WebView数据库路径和优化生命周期管理这两个方案,这是解决这类问题最有效的手段。在Android 4.1.2这种旧版本系统上,WebView的稳定性确实较差,做好资源管理能大幅减少这类异常。
内容的提问来源于stack exchange,提问作者seb2704

