Serait-il acceptable d’avoir une seule instance de SQLiteOpenHelper en tant que membre d’une application sous-classée, et avoir toutes les activités qui ont besoin d’une instance de SQLiteDatabase l’obtenir à partir d’un seul assistant?
Réponses
Trop de publicités?Cliquez ici pour voir mon billet de blog sur ce sujet.
CommonsWare, c'est sur (comme d'habitude). L'expansion sur son post, voici un exemple de code qui illustre trois approches possibles. Ceux-ci permettront l'accès à la base de données dans l'application.
Approche n ° 1: sous-classement "Application"
Si vous savez que votre application ne sera pas très compliqué (c'est à dire si vous savez que vous ne finissent par en avoir une sous-classe de la Application
), alors vous pouvez créer une sous-classe de Application
et votre principale Activité de l'étendre. Cela garantit qu'une instance de la base de données est en cours d'exécution tout au long de l'Application de l'ensemble du cycle de vie.
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;
}
}
Approche n ° 2: avoir " SQLiteOpenHelper` être une donnée membre statique
Ce n'est pas la mise en œuvre complète, mais elle devrait vous donner une bonne idée sur la façon d'aller sur la conception de l' DatabaseHelper
classe correctement. La statique de l'usine méthode garantit qu'il n'existe qu'un DatabaseHelper instance à tout moment.
/**
* 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;
}
}
Approche n ° 3: résumé de la base de données SQLite avec un " ContentProvider`
C'est l'approche que je ne le suggèrent. Pour l'un, le nouveau LoaderManager
classe s'appuie fortement sur ContentProviders, donc si vous voulez une Activité ou d'un Fragment de mettre en œuvre LoaderManager.LoaderCallbacks<Cursor>
(qui je vous suggère de prendre avantage de, il est magique!), vous aurez besoin de mettre en œuvre un ContentProvider
pour votre application. De plus, vous n'avez pas besoin de vous soucier de faire un Singleton base de données helper avec ContentProviders. Appelez simplement getContentResolver()
de l'Activité et le système se chargera de tout pour vous (en d'autres termes, il n'est pas nécessaire pour la conception d'un pattern Singleton pour empêcher plusieurs instances en cours de création).
Espérons que ça aide!
Avoir un seul SQLiteOpenHelper
instance peut aider dans le filetage des cas. Depuis tous les threads partagent la commune SQLiteDatabase
, la synchronisation des opérations est fournie.
Cependant, je ne voudrais pas faire une sous-classe de Application
. Juste une donnée membre statique qui est votre SQLiteOpenHelper
. Les deux approches vous donner quelque chose d'accessible à partir de n'importe où. Toutefois, il existe une sous-classe de la Application
, rendant plus difficile pour vous d'utiliser d'autres sous-classes de Application
(par exemple, GreenDroid nécessite un IIRC). À l'aide d'une donnée membre statique évite que. Néanmoins, utilisez l' Application
Context
lors de l'instanciation de cette statique SQLiteOpenHelper
(paramètre du constructeur), de sorte que vous n'avez pas de fuite de certains autres Context
.
Et, dans le cas où vous n'êtes pas affaire avec plusieurs threads, vous pouvez éviter d'éventuels problèmes de fuite de mémoire en utilisant simplement un SQLiteOpenHelper
exemple par composant. Cependant, dans la pratique, vous devriez traiter avec plusieurs threads (par exemple, un Loader
), de sorte que cette recommandation n'est pertinente que pour trivial applications, tels que ceux trouvés dans des livres... :-)
J'ai écrit MultiThreadSQLiteOpenHelper qui est une amélioration de SQLiteOpenHelper pour les applications Android, où plusieurs threads peut ouvrir et fermer de la même base de données sqlite.
Au lieu d'appeler à proximité de la méthode, les threads demander la fermeture de la base de données, la prévention d'un thread d'exécution d'une requête sur un fermé de la base de données.
Si chaque thread a demandé la fermeture, puis un gros est effectivement réalisé. Chaque activité ou du fil (ui-fil et de l'utilisateur-threads) effectue un appel ouvert sur la base de données lors de la reprise, et demande la fermeture de la base de données lors de la suspension ou de la finition.
Le code Source et les échantillons disponibles ici: https://github.com/d4rxh4wx/MultiThreadSQLiteOpenHelper