应用后台被杀后数据库对象为空致空指针异常,求正确声明方案
问题原因分析
- 进程被杀后实例完全销毁:当应用后台被杀,整个进程被回收,
MainActivity的所有成员变量(包括myDB1-myDB4)都会被清空。用户重新打开应用时,系统会创建全新的MainActivity实例,但如果JS代码保存了对旧Activity实例的引用,调用数据库方法时就会触发空指针异常。 - JavascriptInterface引用失效:你创建的
JavaScriptInterface和WebViewJavaScriptInterface如果持有旧的MainActivity实例,进程重启后这些引用指向的是已销毁的对象,其内部关联的数据库自然为空。 - onStop中主动finish()的影响:该操作会强制销毁Activity,进程重启后必须完全重建所有组件,若JS通信未重新绑定到新的Activity实例,就会出现调用空对象的情况。
数据库正确声明与解决方案
1. 用单例模式管理数据库实例
将每个SQLite数据库类改为单例,确保全局只有一个实例,既避免重复创建,也能在进程重启后正确初始化,同时避免持有Activity引用导致的内存泄漏。
以ContentTableDataBase为例:
public class ContentTableDataBase extends SQLiteOpenHelper { private static ContentTableDataBase instance; // 私有构造,禁止外部直接实例化 private ContentTableDataBase(Context context) { super(context, "content_db", null, 1); } // 获取单例,传入ApplicationContext避免持有Activity public static synchronized ContentTableDataBase getInstance(Context context) { if (instance == null) { instance = new ContentTableDataBase(context.getApplicationContext()); } return instance; } // 重写onCreate、onUpgrade等方法... }
然后在MainActivity中初始化:
// 替换原初始化代码 myDB1 = HTMLDataBase.getInstance(this); myDB2 = ContentTableDataBase.getInstance(this); myDB3 = CloudTableDataBase.getInstance(this); myDB4 = InterviewDataBase.getInstance(this);
2. 修复JavascriptInterface的引用问题
让接口类使用ApplicationContext或直接通过单例获取数据库,避免依赖Activity实例:
public class JavaScriptInterface { private Context appContext; public JavaScriptInterface(Context context) { this.appContext = context.getApplicationContext(); } @JavascriptInterface public void deleteContent(String data) { // 直接通过单例获取有效数据库实例 ContentTableDataBase db = ContentTableDataBase.getInstance(appContext); db.deleteData(data); } }
3. 优化Activity生命周期逻辑
- 移除
onStop中的finish():让系统正常管理Activity生命周期,无需主动销毁。 - 避免重复初始化WebView:
display_html和Javascript_Android_Communication只需在onCreate中调用一次,onResume中仅需确保数据库实例有效,同时使用成员变量view避免局部变量覆盖:
@Override protected void onResume() { super.onResume(); // 单例模式下自动处理实例初始化 myDB1 = HTMLDataBase.getInstance(this); myDB2 = ContentTableDataBase.getInstance(this); myDB3 = CloudTableDataBase.getInstance(this); myDB4 = InterviewDataBase.getInstance(this); if (view != null) { view.onResume(); } } public void display_html() { // 使用成员变量view,避免局部变量覆盖 view = (WebView) findViewById(R.id.WebView); view.getSettings().setJavaScriptEnabled(true); view.getSettings().setDomStorageEnabled(true); view.loadUrl("file:///android_asset/index.html"); }
4. 确保JS在页面加载完成后调用接口
在HTML/JS中,等待window.onload事件触发后再执行与Android的交互逻辑,避免WebView未完全初始化时调用接口导致异常。
内容的提问来源于stack exchange,提问作者Lo Dennis
相关产品推荐
相关产品推荐

