Android SQLite静态数据库连接优化求助:解决重复连接与空指针问题
解决Android SQLite连接复用与空指针问题
首先,咱们先搞清楚你遇到的空指针异常根源:你在Activity的成员变量里直接写了private SQLiteDatabase db = databaseConnection.open();,但此时databaseConnection还没被初始化(成员变量的初始化是在Activity构造函数执行阶段,而你在onCreate里初始化databaseConnection是之后的步骤),所以调用open()时自然会触发空指针。
接下来,咱们来实现高效的可复用数据库连接——其实SQLiteOpenHelper本身就内置了连接缓存机制,不需要手动维护静态连接,咱们只需要把ShoppingListDatabase改成单例模式,就能确保整个应用复用同一个数据库连接,同时避免内存泄漏。
步骤1:重构ShoppingListDatabase为单例类
修改你的ShoppingListDatabase,让它成为全局唯一实例,同时使用ApplicationContext避免Activity销毁时的内存泄漏:
package com.puyakul.prin.psychic_shopping; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.util.Log; public class ShoppingListDatabase { private static final String TAG = "ShoppingListDatabase"; private static final String DATABASE_NAME = "ShoppingListDatabase"; private static final int DATABASE_VERSION = 3; // 全局单例实例 private static ShoppingListDatabase sInstance; private final Context mCtx; private SQLiteDatabase mDb; private DatabaseHelper mDbHelper; // 私有构造函数,禁止外部直接实例化 private ShoppingListDatabase(Context ctx) { // 使用ApplicationContext,避免持有Activity引用导致内存泄漏 this.mCtx = ctx.getApplicationContext(); } // 获取单例的方法,线程安全 public static synchronized ShoppingListDatabase getInstance(Context context) { if (sInstance == null) { sInstance = new ShoppingListDatabase(context); } return sInstance; } private static class DatabaseHelper extends SQLiteOpenHelper { DatabaseHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase db) { Log.d(TAG, "DatabaseHelper onCreate"); db.execSQL(ShoppingListItemTable.CREATE_STATEMENT); db.execSQL(ShoppingListTable.CREATE_STATEMENT); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { Log.d(TAG, "DatabaseHelper onUpgrade"); db.execSQL("DROP TABLE IF EXISTS " + ShoppingListItemTable.TABLE_NAME); db.execSQL("DROP TABLE IF EXISTS " + ShoppingListTable.TABLE_NAME); onCreate(db); } } // 获取可复用的数据库连接 public SQLiteDatabase getDatabase() { if (mDbHelper == null) { mDbHelper = new DatabaseHelper(mCtx); } // SQLiteOpenHelper会自动缓存连接,重复调用不会创建新连接 mDb = mDbHelper.getWritableDatabase(); return mDb; } // 仅当确定整个应用不再需要数据库时调用(比如App退出) public void closeDatabase() { if (mDbHelper != null) { mDbHelper.close(); mDbHelper = null; mDb = null; } } }
步骤2:修改getListDetail方法,使用单例获取连接
现在你的getListDetail可以复用连接,无需每次创建新实例:
public void getListDetail(){ // 获取全局唯一的数据库实例 ShoppingListDatabase database = ShoppingListDatabase.getInstance(this); SQLiteDatabase db = database.getDatabase(); final ArrayList<ShoppingItem> lists = ShoppingListItemTable.selectAllItems(db, selectedID); // 注意:这里不需要手动关闭数据库!SQLiteOpenHelper会自动管理连接复用 // 频繁关闭再打开反而会降低效率 ShoppingListItemAdapter adapter = new ShoppingListItemAdapter(this, R.layout.activity_item_detail_list, lists); ListView_ListDetail = findViewById(R.id.ListView_ListDetail); ListView_ListDetail.setAdapter(adapter); adapter.notifyDataSetChanged(); }
关键注意点
- 避免成员变量提前初始化:不要在Activity的成员变量里直接初始化数据库连接,应该在需要使用时(比如
onCreate或getListDetail)再调用getInstance获取实例,避免初始化顺序导致的空指针。 - 不要频繁关闭数据库:SQLiteOpenHelper会自动维护连接池,复用已有连接,频繁关闭再打开反而会增加开销,只有在App退出时才需要调用
closeDatabase。 - 使用ApplicationContext:防止因持有Activity引用导致的内存泄漏,确保数据库实例的生命周期与App一致。
内容的提问来源于stack exchange,提问作者Prin Puyakul
相关产品推荐
相关产品推荐

