I have been assigned an IT project in which we have to program various different GUI's to do various things. We are also using a database. Let's assume we are accessing an "EntityManager" in a class called "Database":
public class GUI1 {
private Database myDatabase;
public void setDatabase(Database DB){
myDatabase = DB;
}
}
public class GUI2 {
private Database myDatabase;
public void setDatabase(Database DB){
myDatabase = DB;
}
}
public class GUI3 {
private Database myDatabase;
public void setDatabase(Database DB){
myDatabase = DB;
}
}
etc...
Lets say I'm in "GUI1" and I want to switch to "GUI3". After initializing "GUI3" I would have to pass "myDatabase" reference to it via the "setDatabase()" method, but if I want to go back to "GUI1", I would have to pass back the database reference again...
By now I have around 15 GUIs and it get's annoying to copy and paste the same code around when I know it could be replaced easily. In this case, wouldn't it be correct to just use a static reference to whatever I want inside the "Database" class instead of passing around the reference between all my "GUI*" classes?
Create a singleton database object, where everybody access the same object:
public class Database {
private Database(){ // privatize the constructor
// your code here
}
private static Database INSTANCE;
public static Database getInstance() {
if(INSTANCE == null) {
// let's make it thread-safe
synchronized(Database.class) {
if(INSTANCE == null) // may have changed in the mean while
// by other thread
INSTANCE = new Database();
}
}
return INSTANCE;
}
}
EDIT: Even better, from a thread-safe perspective is the enum:
public enum Database {
INSTANCE(); // pair of parenthesis, for constructor
Database() { // constructor
// your code here
}
public static Database getInstance() {
return INSTANCE;// initialization controlled by system
}
public void someMethod(){
// even allows you to add custom methods
}
}
Related
I was wondering how I could access my SQLite database in my android app in a static way.
I always use this when I want to access the database:
MySQLiteHelper dbHandler = new MySQLiteHelper(this, "PinDB", null, 4);
This is the constructor of MySQLiteHelper:
public MySQLiteHelper(Context context, String name, CursorFactory factory, int version){
super(context, DATABASE_NAME, factory, DATABASE_VERSION);
}
Now, I have to access the database in a static way for a method I want to use. But I have no idea how I could get the context of the activity (this).
I've tried ways like getApplicationContext() etc. but they all don't seem to work.
So, is it possible to change MySQLiteHelper(this,"PinDB", null, 4); into something like this? MySQLiteHelper(MyActivity, "PinDB", null, 4);
If you need any more information, please do ask!
Thanks in advance
I use a Singleton to access the SQLite Database in Android. I think that pattern fits your use case as well.
Session.java (the Singleton class)
public class Session
{
private static DbUtil; // static DBUtil
protected Session() {
//
}
public static Session getInstance() {
if (instance == null) {
instance = new Session();
}
return instance;
}
public void initDBUtil(Context ctx){
util = new DbUtil(ctx);
}
public DbUtil getDbUtil()
{
return util;
}
}
DbUtil.java (the class extending SQLiteOpenHelper)
public class DbUtil extends SQLiteOpenHelper
{
public DbUtil(Context context) {
super(context, NAME_DB, null, 1);
// other init code here...
}
// onCreate and other override
}
In the first onCreate method of your entrance activity just do something like that:
Session.getInstance().initDBUtil(this);
and then you can use the getter in Session to access the DbUtil class with:
Session.getInstance().getUtil(). ... your method here ...
I want to do something like this
private static final String url;
private static final String pass;
private static final String user;
static {
Bundle metadata = ctx.getPackageManager().getApplicationInfo(ctx.getPackageName(), PackageManager.GET_META_DATA).metaData;
url = (String) metadata.get("JMSQueueURL");
user = (String) metadata.get("JMSQueueUsername");
pass = (String) metadata.get("JMSQueuePassword");
}
So far it was in activity (but not as static), so that I was possible to get package manager, but now i want to move this piece of code to another class which doesn't inherits ContextWrapper (from where we can get package manager). Is it possible somehow? This class is something like util class.
You can pass the Context from the calling method to the method in the Util class and use the context there to get the details you want. This way you can call the method in the Util class from different modules in your application, with different contexts.
// Calling the Util method
Bundle metadata = Util.getMetaData(context);
...
// Inside the Util class
public static Bundle getMetaData(Context context) {
return context.getPackageManager().getApplicationInfo(ctx.getPackageName(), PackageManager.GET_META_DATA).metaData;
}
This allows me to access the metadata from anywhere in my application, without a context:
public class MyAndroidApp extends Application {
private static MyAndroidApp instance;
#Override
public void onCreate() {
super.onCreate();
instance = this;
}
public static MyAndroidApp getInstance() {
return instance;
}
public static Bundle getMetadata() {
try {
return getInstance()
.getPackageManager()
.getApplicationInfo(getInstance().getPackageName(), PackageManager.GET_META_DATA)
.metaData;
} catch (PackageManager.NameNotFoundException e) {
return null;
}
}
}
Sometimes I'm receiving crash reports from google caused by random NullPointerExceptions (see above). I tried to reproduce those errors but I'm not able to catch them.
Examples of NPE I get :
Caused by: java.lang.NullPointerException
at com.gamequiz.databasemanager.CategoryManager.getAllCategories(CategoryManager.java:28)
Caused by: java.lang.NullPointerException
at com.gamequiz.databasemanager.QuestionManager.getQuestionsFromLevel(QuestionManager.java:30)
at com.gamequiz.databasemanager.QuestionManager.getNumberOfQuestionAnsweredFromLevel(QuestionManager.java:148)
I though that my dbHelper variable is null sometimes but I can't figure out why.
Since I don't know how to resolve that, I post the all steps of my code :
First of all I initialize all the managers in the LaunchActivity :
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_launch);
initializeAllManagers();
//some stuff
}
public void initializeAllManagers(){
InitializeAllManagers.init(getApplicationContext());
}
In my InitializeAllManagers class, I set all the managers I need for the lifecycle of the app :
public class InitializeAllManagers {
public static void init(Context context){
DatabaseManager.init(context);
CategoryManager.init(DatabaseManager.getInstance().getHelper());
//and others initializations
}
}
DatabaseManager class (initialization of the dbManager and dbHelper) :
public class DatabaseManager {
private static DatabaseManager instance;
private DatabaseHelper helper;
public static void init(Context ctx) {
if (instance==null) {
instance = new DatabaseManager(ctx);
}
}
public static DatabaseManager getInstance() {
return instance;
}
private DatabaseManager(Context ctx) {
helper = new DatabaseHelper(ctx);
}
public DatabaseHelper getHelper() {
return helper;
}
}
Finally there is an example of one manager :
public class CategoryManager {
private static DatabaseHelper dbHelper;
public static void init(DatabaseHelper dbHelperInstance) {
dbHelper = dbHelperInstance;
}
public static ArrayList <Category> getAllCategories(){
ArrayList <Category> cList = null;
try {
cList = (ArrayList<Category>) dbHelper.getCategoryDao().queryForAll();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return cList;
}
}
So I suspect that my dbHelper variable is null sometimes. Does anyone have an idea about how I can solve this issue ?
EDIT :
NPE mainly refers to this lines :
cList = (ArrayList<Category>) dbHelper.getCategoryDao().queryForAll();
Dao <Question, Long> questionDao = dbHelper.getQuestionDao();
That's why I suspect that dbHelper is null sometimes, and apparently crashes occurs when the app is sleeping for a moment (see feedback above).
Feedback of one user :
So, mainly if I leave the app without exiting it, the app will often
crash when I try to go back to it. Sometimes I just get sent back to
the menu, but mostly just all the way out of the app and I have to
restart it to continue.
I suspect that this happens when the app is minimized for a while and then get re-opened. Android can and will remove Objects from the heap if it feels like it needs the memory. Especially static variables can be removed. Check static variables for null before you access them.
For example in your DatabaseManager class, create the instance in the getInstance() method instead of in init().
public static DatabaseManager getInstance() {
if(instance == null) instance = new DatabaseManager();
return instance;
}
Edit:
Please note that my reasoning in this answer is wrong. Please read all the comments for clarification.
I'm currently working on a little project for school. In my Java application I need a database, and I would like to make it possible to make my application capable to use different types of databases. So I currently implemented a txt-database and a PostgreSQL. In the future, it should be possible to add other database types. Like XML or MySQL, ...
To create a database instance, I designed a factory that uses an enum. It works perfectly, but Itsn't really flexibel in my opionio. So, I did some research, but didn't find a real good example that is clear for me.
This is my enum:
public enum DatabaseType {
TXT,
SQL,
XML;
}
This is my factory:
public class DatabaseFactory {
public Database createDatabase(DatabaseType type, String databaseName) throws DatabaseException {
if(type.equals(DatabaseType.TXT)) {
return new FileDatabase(databaseName);
}else if(type.equals(DatabaseType.SQL)) {
return new SQLDatabase(databaseName);
}else if(type.equals(DatabaseType.XML)) {
return new XMLDatabase(databaseName);
}else {
//default
return new FileDatabase(databaseName);
}
}
}
My aim is to only edit the enum in the future, without touching the factory itself. This should give me enough flexibility, but I've no idea how I could do this.
You could put the factories in the enum itself.
public enum DatabaseType {
TXT {
#Override
public Database createDatabase(String databaseName) {
return new FileDatabase(databaseName);
}
},
SQL {
#Override
public Database createDatabase(String databaseName) {
return new SQLDatabase(databaseName);
}
},
XML {
#Override
public Database createDatabase(String databaseName) {
return new XMLDatabase(databaseName);
}
};
public abstract Database createDatabase(String databaseName);
}
In Java, enums are not just nice names for integral values (like in C). A better way to think of an enum is as a class with a fixed number of instances. Together with the concept of anonymous classes, you can give each value in the enumeration different properties and methods specific for that value.
Use reflection:
Your enum:
public enum DatabaseType {
FILE(FileDatabase.class),
SQL(SQLDatabase.class);
private Database db;
DatabaseType(Class<Database> db) {
this.db = db;
}
/*package friendly*/ Class<Database> getDatabase() {
return this.db;
}
}
Your factory:
public class DatabaseFactory {
public static Database create(DatabaseType type, String dbName) throws Exception {
Database db = null;
Constructor cons = type.getDatabase().getDeclaredConstructor(new Class[] { String.class });
cons.setAccessible(true);
db = cons.newInstance(dbName);
return db;
}
}
Your Database implementors:
public class FileDatabase extends Database {
/* can only be instantiated via reflection */
private FileDatabase(String databaseName) {
// init db.
}
}
I'working on a db application with ORmlite, my model is like this:
MDL object..
DatabaseTable(tableName = "UserCars")
public class CarMDL
{
#DatabaseField(generatedId = true)
private int _id;
#DatabaseField(columnName = "name")
private String _name;
//................. etc
}
// DB Helper class...
public class DatabaseHelper extends OrmLiteSqliteOpenHelper
{
private Dao<CarMDL,Integer> _carDao = null;
#Override
public void onCreate(SQLiteDatabase database,ConnectionSource connectionSource)
{
try
{
TableUtils.createTable(connectionSource, CarMDL.class);
} catch (SQLException e)
{
throw new RuntimeException(e);
} catch (java.sql.SQLException e)
{
e.printStackTrace();
}
}
public Dao<CarMDL, Integer> getCarDao()
{
if (null == _carDao)
{
try
{
_carDao = getDao(CarMDL.class);
}catch (java.sql.SQLException e)
{
e.printStackTrace();
}
}
return _carDao;
}
}
// DatabaseManager class...
public class DatabaseManager
{
static private DatabaseManager instance;
private DatabaseHelper helper;
static public void init(Context ctx)
{
if (null == instance)
{
instance = new DatabaseManager(ctx);
}
}
static public DatabaseManager getInstance()
{
return instance;
}
private DatabaseManager(Context ctx)
{
helper = new DatabaseHelper(ctx);
}
private DatabaseHelper getHelper()
{
return helper;
}
// All the Dao functions of all MDL objects are in this class, for example:
public List<CarMDL> getAllCars()
{
List<CarMDL> carLists = null;
try
{
carLists = getHelper().getCarDao().queryForAll();
} catch (SQLException e)
{
e.printStackTrace();
}
return carLists;
}
// This is another MDL object..
public List<MarkMDL> getAllMarks()
{
List<MarkMDL> marks = null;
try
{
marks = getHelper().getMarkDao().queryForAll();
} catch (SQLException e)
{
e.printStackTrace();
}
return marks;
}
}
So my question is, is it good have a DatabaseManager with all the functions from all the model objects, like:
listCarById(int id)
listPlaneById(int id)
removeCar(int id)
removePlane(int id)
Etc.....
Updated per Gray's comment.
Be careful with your "singleton" implementation. Your init method should be synchronized to ensure that you don't end up with multiple instances of your DatabaseManager class due to concurrency issues. I would just combine the init and getInstance methods to the following (note the added synchronized keyword):
public static synchronized DatabaseManager getInstance(Context c)
{
if(instance == null)
instance = new DatabaseManager(c);
return instance;
}
For further reading, check out these blog posts about Single SQLite Connection and Android Sqlite locking by Kevin Galligan (one of the contributors to ORMlite).
Update:
To answer your question about how to organize your loading methods like getAllCars, I would first suggest making them static, since they do not depend on anything else besides your method to get your singleton of DatabaseManager, which of course, would also be static. If you have a small number of these types of methods, you could make them all static members of DatabaseManger. If you have many, you could make a helper class for all static methods corresponding to a type.
If you have a method that does depend on the internals of a given instance of CarMDL or MarkMDL (like you need a method to get some associated references), consider making these methods members of the CarMDL or MarkMDL class.
I put all my one-time-per-app work in Application onCreate and I keep a reference of the application instance itself, so I can do many tasks without having to mess with synchronized methods or similar. So let's say we have an Application (remember to add it in the manifest):
public class App extends Application
{
private static App gInstance = null;
// your static globals here
#Override
public void onCreate()
{
// according to documentation onCreate is called before any other method
super.onCreate();
// assign here all your static stuff
gInstance = this;
}
// doesn't need to be synchronized because of the early onCreate
public static App getInstance()
{
return gInstance;
}
}
then your database helper class, Manifest.class is an array of all of your datatype classes:
public class DatabaseHelper extends OrmLiteSqliteOpenHelper
{
// private constructor, singleton pattern, we use
// App context so the class is created on static init
private static DatabaseHelper gHelper = new DatabaseHelper(App.getInstance());
private DatabaseHelper(Context context)
{
super(context, DATABASE_NAME, null, DATABASE_VERSION, R.raw.ormlite_config);
// cache your dao here
for (Class<?> cls: Manifest.classes)
{
try
{
DaoManager.createDao(getConnectionSource(), cls);
} catch (SQLException e)
{
e.printStackTrace();
}
}
}
// if you need the instance, you don't need synchronized because of static init
public static DatabaseHelper getHelper()
{
return gHelper;
}
// lookup from cache
public static <D extends Dao<T, ?>, T> D getTypeDao(Class<T> cls)
{
return DaoManager.lookupDao(gHelper.getConnectionSource(), cls);
}
// we leak this class here since android doesn't provide Application onDestroy
// it's not really a big deal if we need the orm mapping for all application lifetime
// Q: should I keep the instance closeable? the android finalyzer calls somehow close here? I was unable to reproduce, to be sure you can call the super.close() and print a warning
#Override
public void close()
{
throw new RuntimeException("DatabaseHelper Singleton is ethernal");
}
}
addd the context to your DatabaseManager method
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DatabaseManager.init(this.getContext());
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
example android app with ormlite
https://github.com/elberthcabrales/cfeMedicion