我的应用程序中有一个数据库,当我需要插入或删除某些内容时,我当然必须打开数据库。我在每个活动中都这样做,这意味着即使数据库处于打开状态,我也会打开它。在 DDMS 中,我得到:“发现泄漏”。我应该怎么做才能只打开一次我的数据库?我应该使用单例类吗?
2 回答
是的,Singleton 是最好的选择。您可以使用通用实例来访问数据库。如果您想与外部活动共享数据库,请选择内容提供者。
当我第一次开始使用 Android 时,这对我来说是一个问题,因为网络上没有很多教程描述如何正确地允许在整个应用程序中访问您的数据库(不要问我为什么)。下面是一些示例代码,展示了三种可能的方法。
方法 #1:继承 `Application`
如果您知道您的应用程序不会很复杂(即,如果您知道您最终只会拥有 的一个子类Application
),那么您可以创建一个 的子类Application
并让您的主 Activity 扩展它。这确保了数据库的一个实例在应用程序的整个生命周期中运行。
public class MainApplication extends Application {
/**
* see NotePad tutorial for an example implementation of DataDbAdapter
*/
private static DataDbAdapter mDbHelper;
/**
* create the database helper when the application is launched
*/
@Override
public void onCreate() {
mDbHelper = new DataDbAdapter(this);
mDbHelper.open();
}
/**
* close the database helper when the application terminates.
*/
@Override
public void onTerminate() {
mDbHelper.close();
mDbHelper = null;
}
public static DataDbAdapter getDatabaseHelper() {
return mDbHelper;
}
}
方法 #2:让 `SQLiteOpenHelper` 成为静态数据成员
这不是完整的实现,但它应该让您了解如何DatabaseHelper
正确设计类。静态工厂方法确保任何时候都只存在一个 DatabaseHelper 实例。
/**
* create custom DatabaseHelper class that extends SQLiteOpenHelper
*/
public class DatabaseHelper extends SQLiteOpenHelper {
private static DatabaseHelper mInstance = null;
private static final String DATABASE_NAME = "databaseName";
private static final String DATABASE_TABLE = "tableName";
private static final int DATABASE_VERSION = 1;
private Context mCxt;
public static DatabaseHelper getInstance(Context ctx) {
/**
* use the application context as suggested by CommonsWare.
* this will ensure that you dont accidentally leak an Activitys
* context (see this article for more information:
* http://developer.android.com/resources/articles/avoiding-memory-leaks.html)
*/
if (mInstance == null) {
mInstance = new DatabaseHelper(ctx.getApplicationContext());
}
return mInstance;
}
/**
* constructor should be private to prevent direct instantiation.
* make call to static factory method "getInstance()" instead.
*/
private DatabaseHelper(Context ctx) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
this.mCtx = ctx;
}
}
方法 #3:使用 `ContentProvider` 抽象 SQLite 数据库
这是我建议的方法。一方面,新LoaderManager
类在很大程度上依赖于 ContentProviders,所以如果你想实现一个 Activity 或 Fragment LoaderManager.LoaderCallbacks<Cursor>
(我建议你利用它,它很神奇!),你需要ContentProvider
为你的应用程序实现一个。此外,您无需担心使用 ContentProviders 创建 Singleton 数据库助手。只需getContentResolver()
从 Activity 调用,系统就会为您处理所有事情(换句话说,无需设计单例模式来防止创建多个实例)。
希望有帮助!