Jul*_* A. 39 java sqlite android android-cursor android-loadermanager
将单个SQLiteOpenHelper实例作为子类应用程序的成员,并且所有需要SQLiteDatabase实例的活动从一个帮助程序获取它是否可以?
Ale*_*ood 46
CommonsWare是正常的(像往常一样).扩展他的帖子,这里有一些示例代码,说明了三种可能的方法.这些将允许在整个应用程序中访问数据库.
如果你知道你的应用程序不会很复杂(例如,如果你知道你最终只有一个子类Application),那么你可以创建一个子类Application并让你的主Activity扩展它.这可确保数据库的一个实例在整个应用程序的整个生命周期中运行.
public class MainApplication extends Application {
/**
* see NotePad tutorial for an example implementation of DataDbAdapter
*/
private static DataDbAdapter mDbHelper;
/**
* Called when the application is starting, before any other
* application objects have been created. Implementations
* should be as quick as possible...
*/
@Override
public void onCreate() {
super.onCreate();
mDbHelper = new DataDbAdapter(this);
mDbHelper.open();
}
public static DataDbAdapter getDatabaseHelper() {
return mDbHelper;
}
}
Run Code Online (Sandbox Code Playgroud)
这不是完整的实现,但它应该让您对如何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;
}
}
Run Code Online (Sandbox Code Playgroud)
这是我建议的方法.首先,新LoaderManager类很大程度上依赖于ContentProviders,所以如果你想要实现一个Activity或Fragment LoaderManager.LoaderCallbacks<Cursor>(我建议你利用它,这很神奇!),你需要ContentProvider为你的应用程序实现一个.此外,您不必担心使用ContentProviders创建Singleton数据库帮助程序.只需getContentResolver()从Activity 调用,系统就会为您处理所有事情(换句话说,不需要设计Singleton模式来防止创建多个实例).
希望有所帮助!
Com*_*are 41
拥有单个SQLiteOpenHelper实例可以帮助处理线程.由于所有线程都共享公共SQLiteDatabase,因此提供了操作的同步.
但是,我不会做一个子类Application.只需拥有一个静态数据成员即可SQLiteOpenHelper.这两种方法都可以让您随处访问.但是,只有一个子类Application,使您更难以使用其他子类Application(例如,GreenDroid需要一个IIRC).使用静态数据成员可以避免这种情况.但是,请Application Context在实例化此静态SQLiteOpenHelper(构造函数参数)时使用,这样就不会泄漏其他一些Context.
而且,在您不处理多个线程的情况下,您可以通过SQLiteOpenHelper每个组件使用一个实例来避免任何可能的内存泄漏问题.但是,在实践中,您应该处理多个线程(例如,a Loader),因此此建议仅适用于琐碎的应用程序,例如某些书籍中的那些...... :-)
小智 7
我编写了MultiThreadSQLiteOpenHelper,它是针对Android应用程序的增强型SQLiteOpenHelper,其中多个线程可能会打开并关闭相同的sqlite数据库.
线程要求关闭数据库,而不是调用close方法,从而阻止线程对已关闭的数据库执行查询.
如果每个线程要求关闭,则实际执行关闭.每个活动或线程(UI线程和用户线程)上的数据库恢复时,执行开放呼叫,并请求暂停或精加工时关闭数据库.
源代码和示例可在此处获取:https: //github.com/d4rxh4wx/MultiThreadSQLiteOpenHelper
我对这个主题做了很多研究,我同意 commonware 提到的所有观点。但我认为这里每个人都忽略了重要的一点,这个问题的答案完全取决于您的用例,因此如果您的应用程序通过多个线程读取数据库 并且仅使用 Singleton 读取会对性能造成巨大影响,因为所有函数都是同步的并串行执行,因为只有一个到数据库的连接\n顺便说一句,开源很棒。您可以直接深入代码并查看\xe2\x80\x99s 发生了什么。从这些和一些测试中,我\xe2\x80\x99了解到以下内容是正确的:
\n\nSqlite takes care of the file level locking. Many threads can read, one can write. The locks prevent more than one writing.\nAndroid implements some java locking in SQLiteDatabase to help keep things straight.\nIf you go crazy and hammer the database from many threads, your database will (or should) not be corrupted.\nRun Code Online (Sandbox Code Playgroud)\n\n如果您尝试同时从实际不同的连接写入数据库,将会失败。它不会等到第一个完成后再写入。它根本不会写入您的更改。更糟糕的是,如果您不在 SQLiteDatabase 上调用正确版本的插入/更新,您将不会遇到异常。您\xe2\x80\x99 将在 LogCat 中收到一条消息,仅此而已。
\n\n第一个问题,真实的、独特的联系。开源代码的伟大之处在于您可以直接挖掘并查看\xe2\x80\x99s 正在发生什么。SQLiteOpenHelper 类做了一些有趣的事情。尽管有一种方法可以获取只读数据库连接和读写连接,但在幕后,它始终是相同的连接。假设没有文件写入错误,即使只读连接实际上也是单个读写连接。挺滑稽的。因此,如果您在应用程序中使用一个辅助实例,即使是从多个线程,您也永远不会真正使用多个连接。
\n\n另外,SQLiteDatabase 类(其中每个帮助程序只有一个实例)本身实现了 Java 级锁定。因此,当您\xe2\x80\x99实际执行数据库操作时,所有其他数据库操作都将被锁定。因此,即使您有多个线程在执行操作,如果您\xe2\x80\x99 这样做是为了最大限度地提高数据库性能,我也有一些坏消息要告诉您。没有任何好处。
\n\n有趣的观察
\n\n如果您关闭一个写入线程,那么只有一个线程正在写入数据库,而另一个线程正在读取,并且两者都有自己的连接,则读取性能会大幅提高,并且我看不到任何锁定问题。 那\xe2\x80\x99是值得追求的东西。我还没有尝试过写批处理。
\n\n如果您要执行多次任何类型的更新,请将其包装在事务中。看起来我在事务中执行的 50 次更新与事务外的 1 次更新花费的时间相同。我的猜测是,在事务调用之外,每次更新都会尝试将数据库更改写入磁盘。在事务内部,写入是在一个块中完成的,写入的开销使更新逻辑本身相形见绌。
\n| 归档时间: |
|
| 查看次数: |
23362 次 |
| 最近记录: |