I constructed an SQL Lite handler class which extends SQLiteOpenHelper:
public class DatabaseHandler extends SQLiteOpenHelper
The class have this constructor:
public DatabaseHandler(Context context)
{
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
How can i use this class from multiple activites? that is throuhout my entire app?
When i try to instantiate the class from another activity it gives an error because the context is wrong.
What is the best practice for excessing a db from multiple activities?
Each activity should have its own instance of SQLiteDatabase.
See Do I need to call getWritableDatabase() everytime I manipulate data for more discussion on the subject, including example code.
Take a global static
Utils.class
public static DatabaseHandler data;
SplashActivity.class
Utils.data=new PortfolioDatabaseManager(getBaseContext());
You can use it as per your need in any class by accessing like:
Utils.data
You can add getReadDatabase & getWriteDatabase in database class:
public SQLiteDatabase getReadDatabase(Context context){
// create or open the database
DatabaseHandler helper = new DatabaseHandler(context);
SQLiteDatabase data = helper.getReadableDatabase();
return data;
}
public SQLiteDatabase getWriteDatabase(Context context){
// create or open the database
DatabaseHandler helper = new DatabaseHandler(context);
SQLiteDatabase data = helper.getWritableDatabase();
return data;
}
You can extend the class with the Application class and after that you can use all the members and functions of that class from any of the activity. You can make your class a member of the Global class and use it in whole application.
Like this :
class Global extends Application
{
........
........
}
When managing persistent data, the best practice in OOP is the use of the "Gateway Pattern".
Gateways encapsulate and centralizes the application database for easier access.
public class OfflineGateway(){
private static OfflineGateway instance;
private Activity activity;
private OfflineGateway(){
//some initialization
}
public static OfflineGateway getInstance(Activity activity){
if(instance == null)
instance = new OfflineGateway();
return instance;
}
//private accessible methods
private String getStringData(){
//do something here
}
private void setStringData(String string){
//do something here
}
}
Related
This question already has answers here:
Are fields initialized before constructor code is run in Java?
(5 answers)
Closed 12 months ago.
Hi I have the following code and as I am stepping through it in the debugger I notice that the constructor does not get invoked and hence mContext variable initiated within it remains null.
As I am stepping through the debugger the getInstance() function will call the constructor RaceTimeDataContract(Context context), however if I try to step into the constructor it does not and instead the debugger steps to the line where TABLE_NAME is being initialized. The problem is since mContext remains null, then exception is being thrown.
Anyone know what may be causing this behavior? Code is below:
public class RaceTimeDataContract implements BaseColumns{
private static RaceTimeDataContract sInstance;
private static Context mContext;
private RaceTimeDataContract(Context context) {
this.mContext = context; // This is not getting called
}
private RaceTimeDataContract(){}
public static RaceTimeDataContract getInstance(Context context) {
if (sInstance == null) {
sInstance = new RaceTimeDataContract(context.getApplicationContext());
}
return sInstance;
}
// mContext remains null and forces a exception
private final String TABLE_NAME = mContext.getResources().getString(R.string.table_name);
Appreciate any feedback!
When creating new instances, inline field initialisation is performed before the constructor is called. One simple fix in your case is to move the field initialisation into the constructor after the context is set
e.g. (I've reorganised the code a little, and dropped the this on mContext since it is a static member)
public class RaceTimeDataContract implements BaseColumns {
private static RaceTimeDataContract sInstance;
private static Context mContext;
public static RaceTimeDataContract getInstance(Context context) {
if (sInstance == null) {
sInstance = new RaceTimeDataContract(context.getApplicationContext());
}
return sInstance;
}
private final String TABLE_NAME;
private RaceTimeDataContract(Context context) {
mContext = context;
this.TABLE_NAME = mContext.getResources().getString(R.string.table_name);
}
// The below is invalid as it doesn't set TABLE_NAME and should probably be removed
// private RaceTimeDataContract(){}
}
The above isn't very idiomatic and would be better re-arranged to support a singleton better. There are many ways to do this but some general things which would be a benefit are
Storing the context on the instance object, and not statically
Preventing race conditions on getInstance
Removing the default constructor
Assuming you don't retrieve the instance often this can easily be accomplished by synchronising on the getInstance call. e.g.
public class RaceTimeDataContract implements BaseColumns {
private static RaceTimeDataContract sInstance;
public static synchronized RaceTimeDataContract getInstance(Context context) {
if (sInstance == null) {
sInstance = new RaceTimeDataContract(context.getApplicationContext());
}
return sInstance;
}
private final Context mContext;
private final String tableName;
private RaceTimeDataContract(Context context) {
this.mContext = context;
tableName = mContext.getResources().getString(R.string.table_name);
}
}
As a last note it is atypical of a singleton to take a parameter in the getInstance method but always return the same object - you can imagine in this case that if getInstance is called a second time with a different context then we get the original instance which may have an incorrect table name.
If you do need a singleton per context you can store each instance per context in something like a Map<Context, RaceTimeDataContract>, probably using a ConcurrentHashMap, and it would be better to think of it as some kind of reference cache or factory rather than a singletone.
If possible, it is better to just have a zero parameter getInstance method which can retrieve the singleton context statically the first time it is required. This can open your class up to more typical/simpler singleton patterns like enum singletons and static singleton holders.
I want to use the SharedPreferences in a Class that has no Activity. I have wrote this code but im still getting an error. Can you help me out please?
package com.example.keypass;
import android.content.Context;
import android.content.SharedPreferences;
public class test {
SharedPreferences sharedPreferences;
public void loadInt(){
sharedPreferences = this.getSharedPreferences("com.example.keypass",Context.MODE_PRIVATE);
int usrPassword = sharedPreferences.getInt("meinInteger", 0);
}
}
If I use the same code in a Class with Activity it works. But in this class is not working.
Here Maybe this help
Its a good practice making separate class file for shared prefrence
first, create a file(class) name Constants.java
public class Constants {
static Constants _instance;
Context context;
SharedPreferences sharedPref;
SharedPreferences.Editor sharedPrefEditor;
public static Constants instance(Context context) {
if (_instance == null) {
_instance = new Constants();
_instance.configSessionUtils(context);
}
return _instance;
}
public static Constants instance() {
return _instance;
}
public void configSessionUtils(Context context) {
this.context = context;
sharedPref = context.getSharedPreferences("AppPreferences", Activity.MODE_PRIVATE);
sharedPrefEditor = sharedPref.edit();
}
public void storeValueString(String key, String value) {
sharedPrefEditor.putString(key, value);
sharedPrefEditor.commit();
}
public String fetchValueString(String key) {
return sharedPref.getString(key, null);
}
}
The above code will generate an XML file inside your phone with the name AppPreferences
where you can store value in key-value pair
Now go to an activity where you want to access shared preference
Constants.instance(this.getApplicationContext());
Now when you want to store inside shared preference use like that
Constants.instance().storeValueString("companyKey", "Brainwash Inc.");
now when you want to fetch data from shared prefrence
String companyName = (Constants.instance().fetchValueString("companyKey"));
Note Its for Activity if you want to use inside fragments use getactivity() instead of getapplicationcontext()
To be able to use shared preference in a class, you have to pass in the context. You can try to add a constructor with the context parameter in it and call this class inside the activity you want.
What are the best practices to structure big android databases? From what I've seen so far doing some research on this topic, I've seen that most people are using a DatabaseHelper, which extends SQLiteOpenHelper. Does this also apply when you have multiple tables?
For example, in my current project, I have about 30 tables. So far, all of my tables are being created in my DatabaseHelper class, which currently is getting pretty huge. For every module, I also have a (class)Source class, which has all the CRUD methods in that module, and is using a singleton instance of my DatabaseHelper class.
Somehow it feels unnatural to have all of that code in my DatabaseHelper class. Have I done it the right way, or are there some better way to do this?
I would recommend to produce the database via an DB-Client like Squirell or something else. Then you can deploy the database to your app via the assets folder of your app.
Have a look at this thread
I've taken the following approach which helps separate responsibility. First off, start with an abstract database adapter. Its responsibility is to manage access to the database, create tables (if required), handle upgrades, etc. It provides no access to any tables.
public abstract class DBAdapter {
private static final String DATABASE_NAME = "database.db";
private static final int DATABASE_VERSION = 1;
protected final Context context;
protected SQLiteDatabase database;
private DatabaseManager databaseManager;
private static class DatabaseManager extends SQLiteOpenHelper
{
private static final String CREATE_TABLE_PERSON = "create table ...";
//define other tables here
DatabaseManager(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_TABLE_PERSON);
//create other tables here
}
}
public DBAdapter(Context aContext)
{
context = aContext;
}
public DBAdapter open() throws SQLException {
if (databaseManager == null)
{
databaseManager = new DatabaseManager(context);
}
database = databaseManager.getWritableDatabase();
return this;
}
public void close() {
databaseManager.close();
}
}
Then, for each table, provide an implementation of your DBAdapter. It provides the access to your tables and the column definitions. Alternatively, you can also create DBAdapter implementations for each multi-table joins you need to do. This class provides the create/read/update/delete (CRUD) functionality for this type of access (table or multi-table join).
public class PersonAdapter extends DBAdapter
{
static final String COLUMN__ID = "_id";
static final String TABLE_PERSON = "Person";
static final String COLUMN_DATE_OF_BIRTH = "DateOfBirth";
static final String COLUMN_SURNAME = "Surname";
//etc.
public PersonAdapter(Context aContext) {
super(aContext);
}
public long deletePerson(long personId)
{
open();
long numberRowsDeleted =
database.delete(TABLE_PERSON, COLUMN__ID + "=" + personId, null);
close();
return numberRowsDeleted;
}
//your other Person CRUD methods go here
}
I am relatively new to android development and being from a c# background it is entirely possible my entire strategy is wrong, but I am continually getting warned by Eclipse when degugging that I haven't closed a database connection properly causing a memory leak.
I have a base database class that extends SQLiteOpenHelper:
public class MySQLiteOpenHelper extends SQLiteOpenHelper {
public MySQLiteOpenHelper(Context context, String name,
CursorFactory factory, int version) {
super(context, name, factory, version);
}
public MySQLiteOpenHelper(Context context) {
this(context, "myDb", null, 1);
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE MyTable (A INT)");
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
public Cursor executeSelect(String sql, String[] parameters) {
return getReadableDatabase().rawQuery(sql, parameters);
}
}
A generic entity:
public class MyClass {
private int a;
public void setA(int value) {
this.a = value;
}
public int getA() {
return this.a;
}
}
And essentially a service for MyClass (although in reality this extends a generic abstract class for reusability purposes)
public class MyClassService {
private MySQLiteOpenHelper helper;
private Context context;
public MyClassService(Context context) {
this.context = context;
}
private MySQLiteOpenHelper getHelper() {
if (helper == null) {
helper = new MySQLiteOpenHelper(this.context);
}
return helper;
}
public void dispose() {
if (helper != null) {
helper.close();
helper = null;
}
}
public ArrayList<MyClass> getAll()
{
ArrayList<MyClass> list = new ArrayList<MyClass>();
Cursor cursor = getHelper().executeSelect("SELECT A FROM MyTable", new String[0]);
while (cursor.moveToNext()) {
MyClass item = new MyClass()
item.setA(cursor.getInt(0));
list.add(item);
}
cursor.close();
return list;
}
}
So, my question is when I use a line of code like this from an Activity:
ArrayList<MyClass> list = new MyClassService(this).getAll();
is the instance of MyClassService disposed of immediately, or could this be the source of my memory leaks.
Would I be better calling the full code to ensure the database is closed using the dispose method?
MyClassService svc = new MyClassService(this);
ArrayList<MyClass> list = svc.getAll();
svc.dispose();
The Garbage Collector would be able to collect your class, as well as the Helper class, since these are no longer part of the Object chain (not a technical term - just something I made up). However, you would still need to explicitly close the database (if you don't this would definitely be your memory leak culprit). As it stands, you can do this in your Object's finalize() method, which is called during garbage collection:
#Override
public void finalize() {
dispose();
}
I usually prefer, however, to do things a little differently. Data Stores like this are often best written as Singletons, since they may be accessed by multiple classes, and if different instances are created they will still open a new access point for reading a writing, and could cause many issues. You sort of have a singleton-style setup in that there is one helper variable in your code, but you may want to simply make your Helper class the singleton. You can do this by removing your constructors and adding this:
private static MySQLiteOpenHelper self;
private MySQLiteOpenHelper(Context context, String name, CursorFactory factory, int version) {
super(context, name, factory, version);
}
private MySQLiteOpenHelper(Context context) {
this(context, "myDb", null, 1);
}
public static MySQLiteOpenHelper sharedHelper(Context context) {
if (self == null)
self = new MySQLiteOpenHelper(context);
return self;
}
Then, instead of keeping track of a helper object in MyClassService using getHelper(), you can get THE helper using:
MySQLiteOpenHelper.sharedHelper(context);
The benefit of doing this means you only have to keep track of one Helper throughout the entire app, and in the helper's finalize() method, you can now close the database. This will be called when the app process is killed, and prevent any memory leaks:
public void finalize()
{
close();
}
You should explicitly call dispose - not doing so won't cause a memory leak (the object can be collected immediately after new MyClassService(this).getAll() because there aren't any live references to the object), but may cause your database to run out of available connections.
You forgot to call close on the database object returned from getReadableDatabase().
I'm working in a application which has many activities and most of the activities share more than one objects, So I created MyApplication class by extending android Application class to store selected objects to share. But I feel quit uncomfortable while accessing those objects inside provider/helper classes b'coz context is needed in providers to get instance of Application.
So I planned to create static class called SelectionProvider inside MyApplication class to store selected objects, then I can access those in static way without create instance to MyApplication.
MyApplication class with static inner class as follows
class MyApplication extends Application {
public static final String TAG = "MyApplication";
public static class SelectionProvider {
private static UserObj userObj;
private static TownObj townObj;
private static StoreObj storeObj;
public static UserObj getUserObj() {
return userObj;
}
public static setUserObj(UserObj userObj) {
this.userObj = userObj;
}
public static TownObj getTownObj() {
return townObj;
}
public static setTownObj(TownObj townObj) {
this.townObj = townObj;
}
public static StoreObj getStoreObj() {
return storeObj;
}
public static setStoreObj() {
this.storeObj = storeObj;
}
}
}
Is it right approach? if not why?
Will reside the selected objects (which are stored in inner class) in entire application life or will it destroyed anywhere?
This method or a static value elsewhere should work fine and last for the lifetime of the application as long as you don't have multiple processes running that need access to this object. If that's the case, you should use a Service to handle transactions.
I would not design it as an inner class. I would create SelectionProvider (and any other classes you need) as its own separate class, and instantiate it in your MyApplication class' onCreate method.
You should not instantiate the application object as it can be accessed at any time by calling getApplication() and casting it to your application class (e.g. (MyApplication)getApplication(); Then you can access any objects created by the class.
If data persistence is an issue with these classes, consider storing their values in SQLLite or as a Shared Preference, as Android may terminate your application at any time when it is in the background if it needs the resources.
I would create a singleton class of my own:
public class Data {
/* Start of singleton block */
private static Data data = new Data();
private Data(){
}
public static Data getInstance(){
}
/* End of singleton block */
private SelectionProvider selectionProvider;
public SelectionProvider getSelectionProvider(){
return selectionProvider;
}
/* other necessary methods (get, set) and classes below */
}
This way you can access your objects with Data.getInstance().getSelectionProvider().
This will be available during an active application, though you might want to build in some persistant storing of your data for when the user leaves the app for some time to come back later:
public SelectionProvider getSelectionProvider(){
if(selectionProvider == null)
selectionProvider = readSelectionProviderFromPersistantStorage();
return selectionProvider;
}