Android与JS通信异常:后台被杀重启后操作数据库崩溃
问题描述
我正在开发一款集成WebView的App,将HTML、CSS和JS文件嵌入WebView中,并搭建多个SQLite数据库存储数据,通过JS完成数据的增删改操作。App后台驻留被系统杀死后,数据库用于重建HTML恢复运行。
初次运行时WebView与数据库均正常工作,但App被杀死重启后,虽能通过数据库重建HTML,但执行数据增删改操作时崩溃,报错:
[INFO:CONSOLE(5841)] "Uncaught Error: Java exception was raised during method invocation", source: file:///android_asset/index.html (5841)
崩溃时执行的JS代码:
app.delete_duty(String(myVar[4 * a]));
对应的Java代码:
@JavascriptInterface public void delete_duty(String id) { myDB2.deleteData(id); // myDB2是存储数据的数据库实例之一 }
MainActivity核心代码:
public class MainActivity extends AppCompatActivity { HTMLDataBase myDB1; ContentTableDataBase myDB2; CloudTableDataBase myDB3; InterviewDataBase myDB4; Context context; boolean check; private WebView view; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); myDB1 = new HTMLDataBase(this); myDB2 = new ContentTableDataBase(this); myDB3 = new CloudTableDataBase(this); myDB4 = new InterviewDataBase(this); display_html(); Javascript_Android_Communication(); } public void display_html() { WebView view = (WebView) findViewById(R.id.WebView); view.getSettings().setJavaScriptEnabled(true); view.getSettings().setDomStorageEnabled(true); view.loadUrl("file:///android_asset/index.html"); } public void Javascript_Android_Communication() { WebView view = (WebView) findViewById(R.id.WebView); view.setWebChromeClient(new WebChromeClient() {}); WebSettings settings = view.getSettings(); settings.setJavaScriptEnabled(true); settings.setDomStorageEnabled(true); view.addJavascriptInterface(new JavaScriptInterface(this), "Android"); view.addJavascriptInterface(new WebViewJavaScriptInterface(this), "app"); } }
怀疑问题出在Java与JavaScript的通信环节,因为App未被杀死时JS操作完全正常,仅重启后执行相同脚本出错。
可能的原因
- 数据库实例引用失效:
WebViewJavaScriptInterface类大概率直接持有了MainActivity中myDB2的旧引用,App被杀死重启后,原有数据库连接已失效,但接口仍在使用旧实例,调用deleteData时抛出异常。 - WebView重复初始化:
display_html和Javascript_Android_Communication方法中重复通过findViewById获取WebView实例,可能导致JavascriptInterface绑定出现状态冲突,尤其在重启后的WebView恢复阶段。 - 上下文引用无效:如果
WebViewJavaScriptInterface保存的Context不是MainActivity的有效实例,会导致数据库操作时上下文失效,引发异常。
解决方案
1. 让WebViewJavaScriptInterface动态获取最新数据库实例
修改WebViewJavaScriptInterface类,通过传入的MainActivity实例动态获取当前的数据库对象,避免持有旧引用:
public class WebViewJavaScriptInterface { private WeakReference<MainActivity> mActivityRef; public WebViewJavaScriptInterface(MainActivity activity) { mActivityRef = new WeakReference<>(activity); } @JavascriptInterface public void delete_duty(String id) { MainActivity activity = mActivityRef.get(); if (activity != null && !activity.isFinishing() && !activity.isDestroyed()) { activity.myDB2.deleteData(id); } } }
注:需将MainActivity中的myDB2设为public,或提供getMyDB2()这类getter方法。
2. 统一WebView初始化逻辑
将WebView的配置、接口绑定和HTML加载统一到一个方法中,避免重复操作:
private WebView view; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 初始化数据库 myDB1 = new HTMLDataBase(this); myDB2 = new ContentTableDataBase(this); myDB3 = new CloudTableDataBase(this); myDB4 = new InterviewDataBase(this); // 统一初始化WebView initWebView(); } private void initWebView() { view = findViewById(R.id.WebView); WebSettings settings = view.getSettings(); settings.setJavaScriptEnabled(true); settings.setDomStorageEnabled(true); view.setWebChromeClient(new WebChromeClient() {}); // 绑定JavascriptInterface view.addJavascriptInterface(new JavaScriptInterface(this), "Android"); view.addJavascriptInterface(new WebViewJavaScriptInterface(this), "app"); // 加载HTML view.loadUrl("file:///android_asset/index.html"); }
3. 给数据库操作添加异常捕获
在deleteData方法中添加异常处理,明确错误原因:
public void deleteData(String id) { SQLiteDatabase db = null; try { db = this.getWritableDatabase(); db.delete("your_table_name", "id=?", new String[]{id}); } catch (Exception e) { e.printStackTrace(); // 记录错误日志,方便排查 } finally { if (db != null && db.isOpen()) { db.close(); } } }
内容的提问来源于stack exchange,提问作者Lo Dennis
相关产品推荐
相关产品推荐

